OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 package com.google.dart.compiler.resolver; | 5 package com.google.dart.compiler.resolver; |
6 | 6 |
7 import com.google.common.annotations.VisibleForTesting; | 7 import com.google.common.annotations.VisibleForTesting; |
8 import com.google.common.collect.Sets; | 8 import com.google.common.collect.Sets; |
9 import com.google.dart.compiler.DartCompilationPhase; | 9 import com.google.dart.compiler.DartCompilationPhase; |
10 import com.google.dart.compiler.DartCompilerContext; | 10 import com.google.dart.compiler.DartCompilerContext; |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 @VisibleForTesting | 170 @VisibleForTesting |
171 public class ResolveElementsVisitor extends ResolveVisitor { | 171 public class ResolveElementsVisitor extends ResolveVisitor { |
172 private EnclosingElement currentHolder; | 172 private EnclosingElement currentHolder; |
173 private MethodElement currentMethod; | 173 private MethodElement currentMethod; |
174 private boolean inInitializer; | 174 private boolean inInitializer; |
175 private MethodElement innermostFunction; | 175 private MethodElement innermostFunction; |
176 private ResolutionContext context; | 176 private ResolutionContext context; |
177 private LabelElement currentLabel; | 177 private LabelElement currentLabel; |
178 private Set<LabelElement> referencedLabels = Sets.newHashSet(); | 178 private Set<LabelElement> referencedLabels = Sets.newHashSet(); |
179 private Set<LabelElement> labelsInScopes = Sets.newHashSet(); | 179 private Set<LabelElement> labelsInScopes = Sets.newHashSet(); |
| 180 private Set<String> finalsNeedingInitializing = Sets.newHashSet(); |
180 | 181 |
181 @VisibleForTesting | 182 @VisibleForTesting |
182 public ResolveElementsVisitor(ResolutionContext context, | 183 public ResolveElementsVisitor(ResolutionContext context, |
183 EnclosingElement currentHolder, | 184 EnclosingElement currentHolder, |
184 MethodElement currentMethod) { | 185 MethodElement currentMethod) { |
185 super(typeProvider); | 186 super(typeProvider); |
186 this.context = context; | 187 this.context = context; |
187 this.currentMethod = currentMethod; | 188 this.currentMethod = currentMethod; |
188 this.innermostFunction = currentMethod; | 189 this.innermostFunction = currentMethod; |
189 this.currentHolder = currentHolder; | 190 this.currentHolder = currentHolder; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 } | 234 } |
234 | 235 |
235 checkClassTypeVariables(classElement); | 236 checkClassTypeVariables(classElement); |
236 | 237 |
237 // Push new resolution context. | 238 // Push new resolution context. |
238 ResolutionContext previousContext = context; | 239 ResolutionContext previousContext = context; |
239 EnclosingElement previousHolder = currentHolder; | 240 EnclosingElement previousHolder = currentHolder; |
240 currentHolder = classElement; | 241 currentHolder = classElement; |
241 context = topLevelContext.extend(classElement); | 242 context = topLevelContext.extend(classElement); |
242 | 243 |
| 244 this.finalsNeedingInitializing.clear(); |
243 for (Element element : classElement.getMembers()) { | 245 for (Element element : classElement.getMembers()) { |
244 element.getNode().accept(this); | 246 element.getNode().accept(this); |
245 } | 247 } |
246 | 248 |
247 for (Element element : classElement.getConstructors()) { | 249 for (Element element : classElement.getConstructors()) { |
248 element.getNode().accept(this); | 250 element.getNode().accept(this); |
249 } | 251 } |
250 | 252 |
251 checkRedirectConstructorCycle(classElement.getConstructors(), context); | 253 checkRedirectConstructorCycle(classElement.getConstructors(), context); |
252 if (Elements.needsImplicitDefaultConstructor(classElement)) { | 254 if (Elements.needsImplicitDefaultConstructor(classElement)) { |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 @Override | 519 @Override |
518 public MethodElement visitMethodDefinition(DartMethodDefinition node) { | 520 public MethodElement visitMethodDefinition(DartMethodDefinition node) { |
519 MethodElement member = node.getSymbol(); | 521 MethodElement member = node.getSymbol(); |
520 ResolutionContext previousContext = context; | 522 ResolutionContext previousContext = context; |
521 context = context.extend(member.getName()); | 523 context = context.extend(member.getName()); |
522 assert currentMethod == null : "Nested methods?"; | 524 assert currentMethod == null : "Nested methods?"; |
523 innermostFunction = currentMethod = member; | 525 innermostFunction = currentMethod = member; |
524 | 526 |
525 DartFunction functionNode = node.getFunction(); | 527 DartFunction functionNode = node.getFunction(); |
526 List<DartParameter> parameters = functionNode.getParams(); | 528 List<DartParameter> parameters = functionNode.getParams(); |
| 529 Set<String> initalizedFinals = Sets.newHashSet(); |
527 | 530 |
528 // First declare all normal parameters in the scope, putting them in the | 531 // First declare all normal parameters in the scope, putting them in the |
529 // scope of the default expressions so we can report better errors. | 532 // scope of the default expressions so we can report better errors. |
530 for (DartParameter parameter : parameters) { | 533 for (DartParameter parameter : parameters) { |
531 assert parameter.getSymbol() != null; | 534 assert parameter.getSymbol() != null; |
532 if (parameter.getQualifier() instanceof DartThisExpression) { | 535 if (parameter.getQualifier() instanceof DartThisExpression) { |
533 checkParameterInitializer(node, parameter); | 536 checkParameterInitializer(node, parameter); |
| 537 if (!initalizedFinals.add(parameter.getParameterName())) { |
| 538 onError(parameter, ResolverErrorCode.DUPLICATE_PARAMETER, parameter.
getName()); |
| 539 } |
534 } else { | 540 } else { |
535 getContext().declare( | 541 getContext().declare( |
536 parameter.getSymbol(), | 542 parameter.getSymbol(), |
537 ResolverErrorCode.DUPLICATE_PARAMETER, | 543 ResolverErrorCode.DUPLICATE_PARAMETER, |
538 ResolverErrorCode.DUPLICATE_PARAMETER_WARNING); | 544 ResolverErrorCode.DUPLICATE_PARAMETER_WARNING); |
539 } | 545 } |
540 } | 546 } |
541 for (DartParameter parameter : parameters) { | 547 for (DartParameter parameter : parameters) { |
542 // Then resolve the default values. | 548 // Then resolve the default values. |
543 resolve(parameter.getDefaultExpr()); | 549 resolve(parameter.getDefaultExpr()); |
544 } | 550 } |
545 | 551 |
546 if ((functionNode.getBody() == null) | 552 if ((functionNode.getBody() == null) |
547 && !Elements.isNonFactoryConstructor(member) | 553 && !Elements.isNonFactoryConstructor(member) |
548 && !member.getModifiers().isAbstract() | 554 && !member.getModifiers().isAbstract() |
549 && !member.getEnclosingElement().isInterface()) { | 555 && !member.getEnclosingElement().isInterface()) { |
550 onError(functionNode, ResolverErrorCode.METHOD_MUST_HAVE_BODY); | 556 onError(functionNode, ResolverErrorCode.METHOD_MUST_HAVE_BODY); |
551 } | 557 } |
552 resolve(functionNode.getBody()); | 558 resolve(functionNode.getBody()); |
553 | 559 |
554 if (Elements.isNonFactoryConstructor(member)) { | 560 if (Elements.isNonFactoryConstructor(member)) { |
555 resolveInitializers(node); | 561 resolveInitializers(node, initalizedFinals); |
| 562 // Test for missing final initialized fields |
| 563 if (!this.currentHolder.isInterface() && !member.getModifiers().isRedire
ctedConstructor() |
| 564 && !finalsNeedingInitializing.equals(initalizedFinals)) { |
| 565 for (String field : this.finalsNeedingInitializing) { |
| 566 if (!initalizedFinals.contains(field)) { |
| 567 onError(node.getName(), ResolverErrorCode.FINAL_FIELD_MUST_BE_INIT
IALIZED, field); |
| 568 } |
| 569 } |
| 570 } |
556 } | 571 } |
557 | 572 |
558 // If this method is an override, make sure its signature roughly matches
any superclass | 573 // If this method is an override, make sure its signature roughly matches
any superclass |
559 // declaration. | 574 // declaration. |
560 if (ElementKind.of(currentHolder).equals(ElementKind.CLASS)) { | 575 if (ElementKind.of(currentHolder).equals(ElementKind.CLASS)) { |
561 // Look for this method in super implementations. | 576 // Look for this method in super implementations. |
562 ClassElement classElement = (ClassElement) currentHolder; | 577 ClassElement classElement = (ClassElement) currentHolder; |
563 try { | 578 try { |
564 for (InterfaceType supertype : classElement.getAllSupertypes()) { | 579 for (InterfaceType supertype : classElement.getAllSupertypes()) { |
565 Member superMember = supertype.lookupMember(member.getName()); | 580 Member superMember = supertype.lookupMember(member.getName()); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 modifiers.makeStatic(); | 651 modifiers.makeStatic(); |
637 } | 652 } |
638 | 653 |
639 if (expression != null) { | 654 if (expression != null) { |
640 resolve(expression); | 655 resolve(expression); |
641 // Now, this constant has a type. Save it for future reference. | 656 // Now, this constant has a type. Save it for future reference. |
642 Element element = node.getSymbol(); | 657 Element element = node.getSymbol(); |
643 if (expression.getType() != null) { | 658 if (expression.getType() != null) { |
644 Elements.setType(element, expression.getType()); | 659 Elements.setType(element, expression.getType()); |
645 } | 660 } |
646 } else if (isStatic && isFinal) { | 661 } else if (isFinal) { |
647 onError(node, ResolverErrorCode.STATIC_FINAL_REQUIRES_VALUE); | 662 if (isStatic) { |
| 663 onError(node, ResolverErrorCode.STATIC_FINAL_REQUIRES_VALUE); |
| 664 } else { |
| 665 // If a final instance field wasn't initialized at declaration, we mus
t check |
| 666 // at construction time. |
| 667 this.finalsNeedingInitializing.add(node.getName().getTargetName()); |
| 668 } |
648 } | 669 } |
649 | 670 |
650 // If field is an accessor, both getter and setter need to be visited (if
present). | 671 // If field is an accessor, both getter and setter need to be visited (if
present). |
651 FieldElement field = node.getSymbol(); | 672 FieldElement field = node.getSymbol(); |
652 if (field.getGetter() != null) { | 673 if (field.getGetter() != null) { |
653 resolve(field.getGetter().getNode()); | 674 resolve(field.getGetter().getNode()); |
654 } | 675 } |
655 if (field.getSetter() != null) { | 676 if (field.getSetter() != null) { |
656 resolve(field.getSetter().getNode()); | 677 resolve(field.getSetter().getNode()); |
657 } | 678 } |
(...skipping 1014 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1672 // If no type specified, use type of field. | 1693 // If no type specified, use type of field. |
1673 if (parameter.getTypeNode() == null && element != null) { | 1694 if (parameter.getTypeNode() == null && element != null) { |
1674 Elements.setType(parameter.getSymbol(), element.getType()); | 1695 Elements.setType(parameter.getSymbol(), element.getType()); |
1675 } | 1696 } |
1676 } else { | 1697 } else { |
1677 onError(parameter.getName(), | 1698 onError(parameter.getName(), |
1678 ResolverErrorCode.PARAMETER_INIT_OUTSIDE_CONSTRUCTOR); | 1699 ResolverErrorCode.PARAMETER_INIT_OUTSIDE_CONSTRUCTOR); |
1679 } | 1700 } |
1680 } | 1701 } |
1681 | 1702 |
1682 private void resolveInitializers(DartMethodDefinition node) { | 1703 private void resolveInitializers(DartMethodDefinition node, Set<String> inti
alizedFields) { |
1683 Iterator<DartInitializer> initializers = node.getInitializers().iterator()
; | 1704 Iterator<DartInitializer> initializers = node.getInitializers().iterator()
; |
1684 ConstructorElement constructorElement = null; | 1705 ConstructorElement constructorElement = null; |
1685 while (initializers.hasNext()) { | 1706 while (initializers.hasNext()) { |
1686 DartInitializer initializer = initializers.next(); | 1707 DartInitializer initializer = initializers.next(); |
1687 Element element = resolve(initializer); | 1708 Element element = resolve(initializer); |
1688 if ((ElementKind.of(element) == ElementKind.CONSTRUCTOR) && initializer.
isInvocation()) { | 1709 if ((ElementKind.of(element) == ElementKind.CONSTRUCTOR) && initializer.
isInvocation()) { |
1689 constructorElement = (ConstructorElement) element; | 1710 constructorElement = (ConstructorElement) element; |
| 1711 } else if (initializer.getName() != null && initializer.getName().getSym
bol() != null |
| 1712 && initializer.getName().getSymbol().getModifiers() != null |
| 1713 && initializer.getName().getSymbol().getModifiers().isFinal() |
| 1714 && !intializedFields.add(initializer.getName().getTargetName())) { |
| 1715 onError(initializer, ResolverErrorCode.DUPLICATE_PARAMETER, initialize
r.getName()); |
1690 } | 1716 } |
1691 } | 1717 } |
1692 | 1718 |
1693 checkConstructor(node, constructorElement); | 1719 checkConstructor(node, constructorElement); |
1694 } | 1720 } |
1695 | 1721 |
1696 private void onError(DartNode node, ErrorCode errorCode, Object... arguments
) { | 1722 private void onError(DartNode node, ErrorCode errorCode, Object... arguments
) { |
1697 context.onError(node, errorCode, arguments); | 1723 context.onError(node, errorCode, arguments); |
1698 } | 1724 } |
1699 | 1725 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1771 ClassElement nextClass = (ClassElement) nextConstructorElement.getEnclos
ingElement(); | 1797 ClassElement nextClass = (ClassElement) nextConstructorElement.getEnclos
ingElement(); |
1772 ClassElement currentClass = (ClassElement) constructor.getEnclosingEleme
nt(); | 1798 ClassElement currentClass = (ClassElement) constructor.getEnclosingEleme
nt(); |
1773 if (nextClass.getName().equals(currentClass.getName())) { | 1799 if (nextClass.getName().equals(currentClass.getName())) { |
1774 return nextConstructorElement; | 1800 return nextConstructorElement; |
1775 } | 1801 } |
1776 } | 1802 } |
1777 } | 1803 } |
1778 return null; | 1804 return null; |
1779 } | 1805 } |
1780 } | 1806 } |
OLD | NEW |