Index: compiler/java/com/google/dart/compiler/resolver/Resolver.java |
diff --git a/compiler/java/com/google/dart/compiler/resolver/Resolver.java b/compiler/java/com/google/dart/compiler/resolver/Resolver.java |
index 29fa30b687c2a93f501ff53e864d33424f9b5c72..7a376e56aceddda5c6c6eccb74c19853ddaf9ea4 100644 |
--- a/compiler/java/com/google/dart/compiler/resolver/Resolver.java |
+++ b/compiler/java/com/google/dart/compiler/resolver/Resolver.java |
@@ -177,6 +177,7 @@ public class Resolver { |
private LabelElement currentLabel; |
private Set<LabelElement> referencedLabels = Sets.newHashSet(); |
private Set<LabelElement> labelsInScopes = Sets.newHashSet(); |
+ private Set<String> finalsNeedingInitializing = Sets.newHashSet(); |
@VisibleForTesting |
public ResolveElementsVisitor(ResolutionContext context, |
@@ -240,6 +241,7 @@ public class Resolver { |
currentHolder = classElement; |
context = topLevelContext.extend(classElement); |
+ this.finalsNeedingInitializing.clear(); |
for (Element element : classElement.getMembers()) { |
element.getNode().accept(this); |
} |
@@ -524,6 +526,7 @@ public class Resolver { |
DartFunction functionNode = node.getFunction(); |
List<DartParameter> parameters = functionNode.getParams(); |
+ Set<String> initalizedFinals = Sets.newHashSet(); |
// First declare all normal parameters in the scope, putting them in the |
// scope of the default expressions so we can report better errors. |
@@ -531,6 +534,9 @@ public class Resolver { |
assert parameter.getSymbol() != null; |
if (parameter.getQualifier() instanceof DartThisExpression) { |
checkParameterInitializer(node, parameter); |
+ if (!initalizedFinals.add(parameter.getParameterName())) { |
+ onError(parameter, ResolverErrorCode.DUPLICATE_PARAMETER, parameter.getName()); |
+ } |
} else { |
getContext().declare( |
parameter.getSymbol(), |
@@ -552,7 +558,16 @@ public class Resolver { |
resolve(functionNode.getBody()); |
if (Elements.isNonFactoryConstructor(member)) { |
- resolveInitializers(node); |
+ resolveInitializers(node, initalizedFinals); |
+ // Test for missing final initialized fields |
+ if (!this.currentHolder.isInterface() && !member.getModifiers().isRedirectedConstructor() |
+ && !finalsNeedingInitializing.equals(initalizedFinals)) { |
+ for (String field : this.finalsNeedingInitializing) { |
+ if (!initalizedFinals.contains(field)) { |
+ onError(node.getName(), ResolverErrorCode.FINAL_FIELD_MUST_BE_INITIALIZED, field); |
+ } |
+ } |
+ } |
} |
// If this method is an override, make sure its signature roughly matches any superclass |
@@ -643,8 +658,14 @@ public class Resolver { |
if (expression.getType() != null) { |
Elements.setType(element, expression.getType()); |
} |
- } else if (isStatic && isFinal) { |
- onError(node, ResolverErrorCode.STATIC_FINAL_REQUIRES_VALUE); |
+ } else if (isFinal) { |
+ if (isStatic) { |
+ onError(node, ResolverErrorCode.STATIC_FINAL_REQUIRES_VALUE); |
+ } else { |
+ // If a final instance field wasn't initialized at declaration, we must check |
+ // at construction time. |
+ this.finalsNeedingInitializing.add(node.getName().getTargetName()); |
+ } |
} |
// If field is an accessor, both getter and setter need to be visited (if present). |
@@ -1679,7 +1700,7 @@ public class Resolver { |
} |
} |
- private void resolveInitializers(DartMethodDefinition node) { |
+ private void resolveInitializers(DartMethodDefinition node, Set<String> intializedFields) { |
Iterator<DartInitializer> initializers = node.getInitializers().iterator(); |
ConstructorElement constructorElement = null; |
while (initializers.hasNext()) { |
@@ -1687,6 +1708,11 @@ public class Resolver { |
Element element = resolve(initializer); |
if ((ElementKind.of(element) == ElementKind.CONSTRUCTOR) && initializer.isInvocation()) { |
constructorElement = (ConstructorElement) element; |
+ } else if (initializer.getName() != null && initializer.getName().getSymbol() != null |
+ && initializer.getName().getSymbol().getModifiers() != null |
+ && initializer.getName().getSymbol().getModifiers().isFinal() |
+ && !intializedFields.add(initializer.getName().getTargetName())) { |
+ onError(initializer, ResolverErrorCode.DUPLICATE_PARAMETER, initializer.getName()); |
} |
} |