Chromium Code Reviews| Index: pkg/analyzer/lib/src/generated/error_verifier.dart |
| diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart |
| index abf47ca9ce73580466b2de0f6a13854fe26e50e1..80d001c3721bc3ec6702ccf4d5bf4a6b6e4fa36a 100644 |
| --- a/pkg/analyzer/lib/src/generated/error_verifier.dart |
| +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart |
| @@ -276,6 +276,12 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| new HashSet<String>(); |
| /** |
| + * The elements that will be defined later in the current scope, but right |
| + * now are not declared. |
| + */ |
| + HiddenElements _hiddenElements = null; |
| + |
| + /** |
| * A list of types used by the [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS] |
| * and [CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS] error codes. |
| */ |
| @@ -388,8 +394,13 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| @override |
| Object visitBlock(Block node) { |
| - _checkDuplicateDeclarationInStatements(node.statements); |
| - return super.visitBlock(node); |
| + _hiddenElements = new HiddenElements(_hiddenElements, node); |
| + try { |
| + _checkDuplicateDeclarationInStatements(node.statements); |
| + return super.visitBlock(node); |
| + } finally { |
| + _hiddenElements = _hiddenElements.outerElements; |
| + } |
| } |
| @override |
| @@ -747,6 +758,11 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| @override |
| Object visitFunctionDeclaration(FunctionDeclaration node) { |
| + ExecutableElement functionElement = node.element; |
| + if (functionElement != null && |
| + functionElement.enclosingElement is! CompilationUnitElement) { |
| + _hiddenElements.declare(functionElement); |
| + } |
| ExecutableElement outerFunction = _enclosingFunction; |
| try { |
| SimpleIdentifier identifier = node.name; |
| @@ -754,7 +770,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| if (identifier != null) { |
| methodName = identifier.name; |
| } |
| - _enclosingFunction = node.element; |
| + _enclosingFunction = functionElement; |
| TypeName returnType = node.returnType; |
| if (node.isSetter || node.isGetter) { |
| _checkForMismatchedAccessorTypes(node, methodName); |
| @@ -1111,6 +1127,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| @override |
| Object visitSimpleIdentifier(SimpleIdentifier node) { |
| + _checkForReferenceBeforeDeclaration(node); |
| _checkForImplicitThisReferenceInInitializer(node); |
| if (!_isUnqualifiedReferenceToNonLocalStaticMemberAllowed(node)) { |
| _checkForUnqualifiedReferenceToNonLocalStaticMember(node); |
| @@ -1220,6 +1237,15 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| _isInInstanceVariableInitializer = wasInInstanceVariableInitializer; |
| _namesForReferenceToDeclaredVariableInInitializer.remove(name); |
| } |
| + // declare the variable |
| + AstNode grandparent = node.parent.parent; |
| + if (grandparent is! TopLevelVariableDeclaration && |
| + grandparent is! FieldDeclaration) { |
| + VariableElement element = node.element; |
| + if (element != null) { |
| + _hiddenElements.declare(element); |
| + } |
| + } |
| // done |
| return null; |
| } |
| @@ -5420,6 +5446,17 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| redirectedConstructorNode); |
| } |
| + void _checkForReferenceBeforeDeclaration(SimpleIdentifier node) { |
| + if (!node.inDeclarationContext() && |
| + _hiddenElements != null && |
| + _hiddenElements.contains(node.staticElement)) { |
| + _errorReporter.reportErrorForNode( |
| + CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, |
| + node, |
| + [node.name]); |
| + } |
| + } |
| + |
| /** |
| * Check that the given rethrow [expression] is inside of a catch clause. |
| * |
| @@ -6609,6 +6646,63 @@ class GeneralizingElementVisitor_ErrorVerifier_hasTypedefSelfReference |
| } |
| /** |
| + * A record of the elements that will be declared in some scope (block), but are |
| + * not yet declared. |
| + */ |
| +class HiddenElements { |
| + /** |
| + * The elements hidden in outer scopes, or `null` if this is the outermost |
| + * scope. |
| + */ |
| + final HiddenElements outerElements; |
| + |
| + /** |
| + * A set containing the elements that will be declared in this scope, but are |
| + * not yet declared. |
| + */ |
| + Set<Element> _elements = new HashSet<Element>(); |
| + |
| + /** |
| + * Initialize a newly created set of hidden elements to include all of the |
| + * elements defined in the set of [outerElements] and all of the elements |
| + * declared in the given [block]. |
| + */ |
| + HiddenElements(this.outerElements, Block block) { |
| + _initializeElements(block); |
| + } |
| + |
| + /** |
| + * Return `true` if this set of elements contains the given [element]. |
| + */ |
| + bool contains(Element element) { |
| + if (_elements.contains(element)) { |
| + return true; |
| + } else if (outerElements != null) { |
| + return outerElements.contains(element); |
| + } |
| + return false; |
| + } |
| + |
| + /** |
| + * Record that the given [element] has been declared, so it is no longer |
| + * hidden. |
| + */ |
| + void declare(Element element) { |
| + _elements.remove(element); |
| + } |
| + |
| + /** |
| + * Initialize the list of elements that are not yet declared to be all of the |
| + * elements declared somewhere in the given [block]. |
| + */ |
| + void _initializeElements(Block block) { |
| + for (var element in BlockScope.elementsInBlock(block)) { |
| + _elements.add(element); |
| + } |
|
scheglov
2016/09/02 23:46:50
I think here it also could be written more concise
Brian Wilkerson
2016/09/03 17:12:37
I went with "_elements.addAll(BlockScope.elementsI
|
| + } |
| +} |
| + |
| +/** |
| * A class used to compute a list of the constants whose value needs to be |
| * computed before errors can be computed by the [VerifyUnitTask]. |
| */ |