Index: pkg/analyzer/lib/src/generated/declaration_resolver.dart |
diff --git a/pkg/analyzer/lib/src/generated/declaration_resolver.dart b/pkg/analyzer/lib/src/generated/declaration_resolver.dart |
index bc34f2a1c1fb8cf23ac76043add64d3b0ac1d8c2..d67bc4c02fed6bfa911fa18ea90dd0b41c59bd12 100644 |
--- a/pkg/analyzer/lib/src/generated/declaration_resolver.dart |
+++ b/pkg/analyzer/lib/src/generated/declaration_resolver.dart |
@@ -4,13 +4,10 @@ |
library analyzer.src.generated.declaration_resolver; |
-import 'dart:collection'; |
- |
import 'package:analyzer/dart/ast/ast.dart'; |
import 'package:analyzer/dart/ast/token.dart'; |
import 'package:analyzer/dart/ast/visitor.dart'; |
import 'package:analyzer/dart/element/element.dart'; |
-import 'package:analyzer/dart/element/visitor.dart'; |
import 'package:analyzer/exception/exception.dart'; |
import 'package:analyzer/src/dart/element/element.dart'; |
@@ -23,37 +20,17 @@ import 'package:analyzer/src/dart/element/element.dart'; |
* This class must not assume that the [CompilationUnitElement] passed to it is |
* any more complete than a [COMPILATION_UNIT_ELEMENT]. |
*/ |
-class DeclarationResolver extends RecursiveAstVisitor<Object> |
- with _ExistingElementResolver { |
- /** |
- * The elements that are reachable from the compilation unit element. When a |
- * compilation unit has been resolved, this set should be empty. |
- */ |
- Set<Element> _expectedElements; |
- |
+class DeclarationResolver extends RecursiveAstVisitor<Object> { |
/** |
- * The function type alias containing the AST nodes being visited, or `null` |
- * if we are not in the scope of a function type alias. |
- */ |
- FunctionTypeAliasElement _enclosingAlias; |
- |
- /** |
- * The class containing the AST nodes being visited, or `null` if we are not |
- * in the scope of a class. |
- */ |
- ClassElement _enclosingClass; |
- |
- /** |
- * The method or function containing the AST nodes being visited, or `null` if |
- * we are not in the scope of a method or function. |
+ * The compilation unit containing the AST nodes being visited. |
*/ |
- ExecutableElement _enclosingExecutable; |
+ CompilationUnitElementImpl _enclosingUnit; |
/** |
- * The parameter containing the AST nodes being visited, or `null` if we are |
- * not in the scope of a parameter. |
+ * The [ElementWalker] we are using to keep track of progress through the |
+ * element model. |
*/ |
- ParameterElement _enclosingParameter; |
+ ElementWalker _walker; |
/** |
* Resolve the declarations within the given compilation [unit] to the |
@@ -61,26 +38,26 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
* if the element model and compilation unit do not match each other. |
*/ |
void resolve(CompilationUnit unit, CompilationUnitElement element) { |
- _ElementGatherer gatherer = new _ElementGatherer(); |
- element.accept(gatherer); |
- _expectedElements = gatherer.elements; |
_enclosingUnit = element; |
- _expectedElements.remove(element); |
+ _walker = new ElementWalker.forCompilationUnit(element); |
unit.element = element; |
- unit.accept(this); |
- _validateResolution(); |
+ try { |
+ unit.accept(this); |
+ _walker.validate(); |
+ } on Error catch (e, st) { |
+ throw new _ElementMismatchException( |
+ element, _walker.element, new CaughtException(e, st)); |
+ } |
} |
@override |
Object visitCatchClause(CatchClause node) { |
SimpleIdentifier exceptionParameter = node.exceptionParameter; |
if (exceptionParameter != null) { |
- List<LocalVariableElement> localVariables = |
- _enclosingExecutable.localVariables; |
- _findIdentifier(localVariables, exceptionParameter); |
+ _match(exceptionParameter, _walker.getVariable()); |
SimpleIdentifier stackTraceParameter = node.stackTraceParameter; |
if (stackTraceParameter != null) { |
- _findIdentifier(localVariables, stackTraceParameter); |
+ _match(stackTraceParameter, _walker.getVariable()); |
} |
} |
return super.visitCatchClause(node); |
@@ -88,67 +65,38 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitClassDeclaration(ClassDeclaration node) { |
- ClassElement outerClass = _enclosingClass; |
- try { |
- SimpleIdentifier className = node.name; |
- _enclosingClass = _findIdentifier(_enclosingUnit.types, className); |
+ ClassElement element = _match(node.name, _walker.getClass()); |
+ _walk(new ElementWalker.forClass(element), () { |
super.visitClassDeclaration(node); |
- _resolveMetadata(node, node.metadata, _enclosingClass); |
- return null; |
- } finally { |
- _enclosingClass = outerClass; |
- } |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
} |
@override |
Object visitClassTypeAlias(ClassTypeAlias node) { |
- ClassElement outerClass = _enclosingClass; |
- try { |
- SimpleIdentifier className = node.name; |
- _enclosingClass = _findIdentifier(_enclosingUnit.types, className); |
+ ClassElement element = _match(node.name, _walker.getClass()); |
+ _walk(new ElementWalker.forClass(element), () { |
super.visitClassTypeAlias(node); |
- _resolveMetadata(node, node.metadata, _enclosingClass); |
- return null; |
- } finally { |
- _enclosingClass = outerClass; |
- } |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
} |
@override |
Object visitConstructorDeclaration(ConstructorDeclaration node) { |
- ExecutableElement outerExecutable = _enclosingExecutable; |
- try { |
- SimpleIdentifier constructorName = node.name; |
- if (constructorName == null) { |
- _enclosingExecutable = _enclosingClass.unnamedConstructor; |
- if (_enclosingExecutable == null) { |
- _mismatch('Could not find default constructor', node); |
- } |
- } else { |
- _enclosingExecutable = |
- _enclosingClass.getNamedConstructor(constructorName.name); |
- if (_enclosingExecutable == null) { |
- _mismatch( |
- 'Could not find constructor element with name "${constructorName.name}', |
- node); |
- } |
- constructorName.staticElement = _enclosingExecutable; |
- } |
- _expectedElements.remove(_enclosingExecutable); |
- node.element = _enclosingExecutable as ConstructorElement; |
+ ConstructorElement element = _match(node.name, _walker.getConstructor()); |
+ _walk(new ElementWalker.forExecutable(element), () { |
+ node.element = element; |
super.visitConstructorDeclaration(node); |
- _resolveMetadata(node, node.metadata, _enclosingExecutable); |
- return null; |
- } finally { |
- _enclosingExecutable = outerExecutable; |
- } |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
} |
@override |
Object visitDeclaredIdentifier(DeclaredIdentifier node) { |
- SimpleIdentifier variableName = node.identifier; |
- Element element = |
- _findIdentifier(_enclosingExecutable.localVariables, variableName); |
+ VariableElement element = _match(node.identifier, _walker.getVariable()); |
super.visitDeclaredIdentifier(node); |
_resolveMetadata(node, node.metadata, element); |
return null; |
@@ -156,39 +104,31 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
- SimpleIdentifier parameterName = node.parameter.identifier; |
- ParameterElement element = _getElementForParameter(node, parameterName); |
+ ParameterElement element = |
+ _match(node.parameter.identifier, _walker.getParameter()); |
Expression defaultValue = node.defaultValue; |
if (defaultValue != null) { |
- ExecutableElement outerExecutable = _enclosingExecutable; |
- try { |
- _enclosingExecutable = element.initializer; |
+ _walk(new ElementWalker.forExecutable(element.initializer), () { |
defaultValue.accept(this); |
- } finally { |
- _enclosingExecutable = outerExecutable; |
- } |
+ }); |
} |
- ParameterElement outerParameter = _enclosingParameter; |
- try { |
- _enclosingParameter = element; |
+ _walk(new ElementWalker.forParameter(element), () { |
super.visitDefaultFormalParameter(node); |
- _resolveMetadata(node, node.metadata, element); |
- return null; |
- } finally { |
- _enclosingParameter = outerParameter; |
- } |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
} |
@override |
Object visitEnumDeclaration(EnumDeclaration node) { |
- ClassElement enclosingEnum = |
- _findIdentifier(_enclosingUnit.enums, node.name); |
- List<FieldElement> constants = enclosingEnum.fields; |
- for (EnumConstantDeclaration constant in node.constants) { |
- _findIdentifier(constants, constant.name); |
- } |
- super.visitEnumDeclaration(node); |
- _resolveMetadata(node, node.metadata, enclosingEnum); |
+ ClassElement element = _match(node.name, _walker.getEnum()); |
+ _walk(new ElementWalker.forClass(element), () { |
+ for (EnumConstantDeclaration constant in node.constants) { |
+ _match(constant.name, _walker.getVariable()); |
+ } |
+ super.visitEnumDeclaration(node); |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
return null; |
} |
@@ -210,17 +150,13 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitFieldFormalParameter(FieldFormalParameter node) { |
if (node.parent is! DefaultFormalParameter) { |
- SimpleIdentifier parameterName = node.identifier; |
- ParameterElement element = _getElementForParameter(node, parameterName); |
- ParameterElement outerParameter = _enclosingParameter; |
- try { |
- _enclosingParameter = element; |
+ ParameterElement element = |
+ _match(node.identifier, _walker.getParameter()); |
+ _walk(new ElementWalker.forParameter(element), () { |
super.visitFieldFormalParameter(node); |
- _resolveMetadata(node, node.metadata, element); |
- return null; |
- } finally { |
- _enclosingParameter = outerParameter; |
- } |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
} else { |
return super.visitFieldFormalParameter(node); |
} |
@@ -228,96 +164,64 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitFunctionDeclaration(FunctionDeclaration node) { |
- ExecutableElement outerExecutable = _enclosingExecutable; |
- try { |
- SimpleIdentifier functionName = node.name; |
- Token property = node.propertyKeyword; |
- if (property == null) { |
- if (_enclosingExecutable != null) { |
- _enclosingExecutable = |
- _findIdentifier(_enclosingExecutable.functions, functionName); |
- } else { |
- _enclosingExecutable = |
- _findIdentifier(_enclosingUnit.functions, functionName); |
- } |
+ SimpleIdentifier functionName = node.name; |
+ Token property = node.propertyKeyword; |
+ ExecutableElement element; |
+ if (property == null) { |
+ element = _match(functionName, _walker.getFunction()); |
+ } else { |
+ if (_walker.element is ExecutableElement) { |
+ element = _match(functionName, _walker.getFunction()); |
+ } else if (property.keyword == Keyword.GET) { |
+ element = _match(functionName, _walker.getAccessor()); |
} else { |
- if (_enclosingExecutable != null) { |
- _enclosingExecutable = |
- _findIdentifier(_enclosingExecutable.functions, functionName); |
- } else { |
- List<PropertyAccessorElement> accessors; |
- if (_enclosingClass != null) { |
- accessors = _enclosingClass.accessors; |
- } else { |
- accessors = _enclosingUnit.accessors; |
- } |
- PropertyAccessorElement accessor; |
- if (property.keyword == Keyword.GET) { |
- accessor = _findIdentifier(accessors, functionName); |
- } else if (property.keyword == Keyword.SET) { |
- accessor = _findWithNameAndOffset(accessors, functionName, |
- functionName.name + '=', functionName.offset); |
- _expectedElements.remove(accessor); |
- functionName.staticElement = accessor; |
- } |
- _enclosingExecutable = accessor; |
- } |
+ assert(property.keyword == Keyword.SET); |
+ element = _match(functionName, _walker.getAccessor(), |
+ elementName: functionName.name + '='); |
} |
- node.functionExpression.element = _enclosingExecutable; |
- super.visitFunctionDeclaration(node); |
- _resolveMetadata(node, node.metadata, _enclosingExecutable); |
- return null; |
- } finally { |
- _enclosingExecutable = outerExecutable; |
} |
+ node.functionExpression.element = element; |
+ _walk(new ElementWalker.forExecutable(element), () { |
+ super.visitFunctionDeclaration(node); |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
} |
@override |
Object visitFunctionExpression(FunctionExpression node) { |
if (node.parent is! FunctionDeclaration) { |
- FunctionElement element = _findAtOffset( |
- _enclosingExecutable.functions, node, node.beginToken.offset); |
- _expectedElements.remove(element); |
+ FunctionElement element = _walker.getFunction(); |
node.element = element; |
- } |
- ExecutableElement outerExecutable = _enclosingExecutable; |
- try { |
- _enclosingExecutable = node.element; |
+ _walk(new ElementWalker.forExecutable(element), () { |
+ super.visitFunctionExpression(node); |
+ }); |
+ return null; |
+ } else { |
return super.visitFunctionExpression(node); |
- } finally { |
- _enclosingExecutable = outerExecutable; |
} |
} |
@override |
Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
- FunctionTypeAliasElement outerAlias = _enclosingAlias; |
- try { |
- SimpleIdentifier aliasName = node.name; |
- _enclosingAlias = |
- _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName); |
+ FunctionTypeAliasElement element = _match(node.name, _walker.getTypedef()); |
+ _walk(new ElementWalker.forTypedef(element), () { |
super.visitFunctionTypeAlias(node); |
- _resolveMetadata(node, node.metadata, _enclosingAlias); |
- return null; |
- } finally { |
- _enclosingAlias = outerAlias; |
- } |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
} |
@override |
Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
if (node.parent is! DefaultFormalParameter) { |
- SimpleIdentifier parameterName = node.identifier; |
- ParameterElement element = _getElementForParameter(node, parameterName); |
- ParameterElement outerParameter = _enclosingParameter; |
- try { |
- _enclosingParameter = element; |
+ ParameterElement element = |
+ _match(node.identifier, _walker.getParameter()); |
+ _walk(new ElementWalker.forParameter(element), () { |
super.visitFunctionTypedFormalParameter(node); |
- _resolveMetadata(node, node.metadata, _enclosingParameter); |
- return null; |
- } finally { |
- _enclosingParameter = outerParameter; |
- } |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
} else { |
return super.visitFunctionTypedFormalParameter(node); |
} |
@@ -334,8 +238,7 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitLabeledStatement(LabeledStatement node) { |
for (Label label in node.labels) { |
- SimpleIdentifier labelName = label.label; |
- _findIdentifier(_enclosingExecutable.labels, labelName); |
+ _match(label.label, _walker.getLabel()); |
} |
return super.visitLabeledStatement(node); |
} |
@@ -350,39 +253,32 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitMethodDeclaration(MethodDeclaration node) { |
- ExecutableElement outerExecutable = _enclosingExecutable; |
- try { |
- Token property = node.propertyKeyword; |
- SimpleIdentifier methodName = node.name; |
- String nameOfMethod = methodName.name; |
- if (property == null) { |
- String elementName = nameOfMethod == '-' && |
- node.parameters != null && |
- node.parameters.parameters.isEmpty |
- ? 'unary-' |
- : nameOfMethod; |
- _enclosingExecutable = _findWithNameAndOffset(_enclosingClass.methods, |
- methodName, elementName, methodName.offset); |
- _expectedElements.remove(_enclosingExecutable); |
- methodName.staticElement = _enclosingExecutable; |
+ Token property = node.propertyKeyword; |
+ SimpleIdentifier methodName = node.name; |
+ String nameOfMethod = methodName.name; |
+ ExecutableElement element; |
+ if (property == null) { |
+ String elementName = nameOfMethod == '-' && |
+ node.parameters != null && |
+ node.parameters.parameters.isEmpty |
+ ? 'unary-' |
+ : nameOfMethod; |
+ element = |
+ _match(methodName, _walker.getFunction(), elementName: elementName); |
+ } else { |
+ if (property.keyword == Keyword.GET) { |
+ element = _match(methodName, _walker.getAccessor()); |
} else { |
- PropertyAccessorElement accessor; |
- if (property.keyword == Keyword.GET) { |
- accessor = _findIdentifier(_enclosingClass.accessors, methodName); |
- } else if (property.keyword == Keyword.SET) { |
- accessor = _findWithNameAndOffset(_enclosingClass.accessors, |
- methodName, nameOfMethod + '=', methodName.offset); |
- _expectedElements.remove(accessor); |
- methodName.staticElement = accessor; |
- } |
- _enclosingExecutable = accessor; |
+ assert(property.keyword == Keyword.SET); |
+ element = _match(methodName, _walker.getAccessor(), |
+ elementName: nameOfMethod + '='); |
} |
- super.visitMethodDeclaration(node); |
- _resolveMetadata(node, node.metadata, _enclosingExecutable); |
- return null; |
- } finally { |
- _enclosingExecutable = outerExecutable; |
} |
+ _walk(new ElementWalker.forExecutable(element), () { |
+ super.visitMethodDeclaration(node); |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
} |
@override |
@@ -402,26 +298,22 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitSimpleFormalParameter(SimpleFormalParameter node) { |
if (node.parent is! DefaultFormalParameter) { |
- SimpleIdentifier parameterName = node.identifier; |
- ParameterElement element = _getElementForParameter(node, parameterName); |
- ParameterElement outerParameter = _enclosingParameter; |
- try { |
- _enclosingParameter = element; |
+ ParameterElement element = |
+ _match(node.identifier, _walker.getParameter()); |
+ _walk(new ElementWalker.forParameter(element), () { |
super.visitSimpleFormalParameter(node); |
- _resolveMetadata(node, node.metadata, element); |
- return null; |
- } finally { |
- _enclosingParameter = outerParameter; |
- } |
- } else {} |
- return super.visitSimpleFormalParameter(node); |
+ }); |
+ _resolveMetadata(node, node.metadata, element); |
+ return null; |
+ } else { |
+ return super.visitSimpleFormalParameter(node); |
+ } |
} |
@override |
Object visitSwitchCase(SwitchCase node) { |
for (Label label in node.labels) { |
- SimpleIdentifier labelName = label.label; |
- _findIdentifier(_enclosingExecutable.labels, labelName); |
+ _match(label.label, _walker.getLabel()); |
} |
return super.visitSwitchCase(node); |
} |
@@ -429,8 +321,7 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitSwitchDefault(SwitchDefault node) { |
for (Label label in node.labels) { |
- SimpleIdentifier labelName = label.label; |
- _findIdentifier(_enclosingExecutable.labels, labelName); |
+ _match(label.label, _walker.getLabel()); |
} |
return super.visitSwitchDefault(node); |
} |
@@ -444,28 +335,7 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitTypeParameter(TypeParameter node) { |
- SimpleIdentifier parameterName = node.name; |
- Element element = null; |
- if (_enclosingExecutable != null) { |
- element = _findIdentifier( |
- _enclosingExecutable.typeParameters, parameterName, |
- required: false); |
- } |
- if (element == null) { |
- if (_enclosingClass != null) { |
- element = |
- _findIdentifier(_enclosingClass.typeParameters, parameterName); |
- } else if (_enclosingAlias != null) { |
- element = |
- _findIdentifier(_enclosingAlias.typeParameters, parameterName); |
- } |
- } |
- if (element == null) { |
- String name = parameterName.name; |
- int offset = parameterName.offset; |
- _mismatch( |
- 'Could not find type parameter with name "$name" at $offset', node); |
- } |
+ Element element = _match(node.name, _walker.getTypeParameter()); |
super.visitTypeParameter(node); |
_resolveMetadata(node, node.metadata, element); |
return null; |
@@ -473,31 +343,16 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
@override |
Object visitVariableDeclaration(VariableDeclaration node) { |
- VariableElement element = null; |
- SimpleIdentifier variableName = node.name; |
- if (_enclosingExecutable != null) { |
- element = _findIdentifier( |
- _enclosingExecutable.localVariables, variableName, |
- required: false); |
- } |
- if (element == null && _enclosingClass != null) { |
- element = _findIdentifier(_enclosingClass.fields, variableName, |
- required: false); |
- } |
- if (element == null && _enclosingUnit != null) { |
- element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName); |
- } |
+ VariableElement element = _match(node.name, _walker.getVariable()); |
Expression initializer = node.initializer; |
if (initializer != null) { |
- ExecutableElement outerExecutable = _enclosingExecutable; |
- try { |
- _enclosingExecutable = element.initializer; |
- return super.visitVariableDeclaration(node); |
- } finally { |
- _enclosingExecutable = outerExecutable; |
- } |
+ _walk(new ElementWalker.forExecutable(element.initializer), () { |
+ super.visitVariableDeclaration(node); |
+ }); |
+ return null; |
+ } else { |
+ return super.visitVariableDeclaration(node); |
} |
- return super.visitVariableDeclaration(node); |
} |
@override |
@@ -511,103 +366,28 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
} |
/** |
- * Return the element in the given list of [elements] that was created for the |
- * declaration at the given [offset]. Throw an [ElementMismatchException] if |
- * an element at that offset cannot be found. |
+ * Updates [identifier] to point to [element], after ensuring that the |
+ * element has the expected name. |
* |
- * This method should only be used when there is no name associated with the |
- * node. |
- */ |
- Element _findAtOffset(List<Element> elements, AstNode node, int offset) => |
- _findWithNameAndOffset(elements, node, '', offset); |
- |
- /** |
- * Return the element in the given list of [elements] that was created for the |
- * declaration with the given [identifier]. As a side-effect, associate the |
- * returned element with the identifier. Throw an [ElementMismatchException] |
- * if an element corresponding to the identifier cannot be found unless |
- * [required] is `false`, in which case return `null`. |
+ * If no [elementName] is given, it defaults to the name of the [identifier] |
+ * (or the empty string if [identifier] is `null`). |
+ * |
+ * If [identifier] is `null`, nothing is updated, but the element name is |
+ * still checked. |
*/ |
- Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier, |
- {bool required: true}) { |
- Element element = _findWithNameAndOffset( |
- elements, identifier, identifier.name, identifier.offset, |
- required: required); |
- _expectedElements.remove(element); |
- identifier.staticElement = element; |
+ Element/*=E*/ _match/*<E extends Element>*/( |
+ SimpleIdentifier identifier, Element/*=E*/ element, |
+ {String elementName}) { |
+ elementName ??= identifier?.name ?? ''; |
+ if (element.name != elementName) { |
+ throw new StateError( |
+ 'Expected an element matching `$elementName`, got `${element.name}`'); |
+ } |
+ identifier?.staticElement = element; |
return element; |
} |
/** |
- * Return the element in the given list of [elements] that was created for the |
- * declaration with the given [name] at the given [offset]. Throw an |
- * [ElementMismatchException] if an element corresponding to the identifier |
- * cannot be found unless [required] is `false`, in which case return `null`. |
- */ |
- Element _findWithNameAndOffset( |
- List<Element> elements, AstNode node, String name, int offset, |
- {bool required: true}) { |
- int length = elements.length; |
- for (int i = 0; i < length; i++) { |
- Element element = elements[i]; |
- if (element.nameOffset == offset && element.name == name) { |
- return element; |
- } |
- } |
- if (!required) { |
- return null; |
- } |
- for (int i = 0; i < length; i++) { |
- Element element = elements[i]; |
- if (element.name == name) { |
- _mismatch( |
- 'Found element with name "$name" at ${element.nameOffset}, ' |
- 'but expected offset of $offset', |
- node); |
- } |
- if (element.nameOffset == offset) { |
- _mismatch( |
- 'Found element with name "${element.name}" at $offset, ' |
- 'but expected element with name "$name"', |
- node); |
- } |
- } |
- _mismatch('Could not find element with name "$name" at $offset', node); |
- return null; // Never reached |
- } |
- |
- /** |
- * Search the most closely enclosing list of parameter elements for a |
- * parameter, defined by the given [node], with the given [parameterName]. |
- * Return the element that was found, or throw an [ElementMismatchException] |
- * if an element corresponding to the identifier cannot be found. |
- */ |
- ParameterElement _getElementForParameter( |
- FormalParameter node, SimpleIdentifier parameterName) { |
- List<ParameterElement> parameters = null; |
- if (_enclosingParameter != null) { |
- parameters = _enclosingParameter.parameters; |
- } |
- if (parameters == null && _enclosingExecutable != null) { |
- parameters = _enclosingExecutable.parameters; |
- } |
- if (parameters == null && _enclosingAlias != null) { |
- parameters = _enclosingAlias.parameters; |
- } |
- if (parameters == null) { |
- StringBuffer buffer = new StringBuffer(); |
- buffer.writeln('Could not find parameter in enclosing scope'); |
- buffer.writeln( |
- '(_enclosingParameter == null) == ${_enclosingParameter == null}'); |
- buffer.writeln( |
- '(_enclosingExecutable == null) == ${_enclosingExecutable == null}'); |
- buffer.writeln('(_enclosingAlias == null) == ${_enclosingAlias == null}'); |
- _mismatch(buffer.toString(), parameterName); |
- } |
- return _findIdentifier(parameters, parameterName); |
- } |
- |
- /** |
* Associate each of the annotation [nodes] with the corresponding |
* [ElementAnnotation] in [annotations]. If there is a problem, report it |
* against the given [parent] node. |
@@ -616,10 +396,8 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
List<ElementAnnotation> annotations) { |
int nodeCount = nodes.length; |
if (nodeCount != annotations.length) { |
- _mismatch( |
- 'Found $nodeCount annotation nodes and ' |
- '${annotations.length} element annotations', |
- parent); |
+ throw new StateError('Found $nodeCount annotation nodes and ' |
+ '${annotations.length} element annotations'); |
} |
for (int i = 0; i < nodeCount; i++) { |
nodes[i].elementAnnotation = annotations[i]; |
@@ -643,87 +421,208 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> |
} |
/** |
- * Throw an exception if there are non-synthetic elements in the element model |
- * that were not associated with an AST node. |
+ * Recurses through the element model and AST, verifying that all elements are |
+ * matched. |
+ * |
+ * Executes [callback] with [_walker] pointing to the given [walker] (which |
+ * should be a new instance of [ElementWalker]). Once [callback] returns, |
+ * uses [ElementWalker.validate] to verify that all expected elements have |
+ * been matched. |
*/ |
- void _validateResolution() { |
- if (_expectedElements.isNotEmpty) { |
- StringBuffer buffer = new StringBuffer(); |
- buffer.write(_expectedElements.length); |
- buffer.writeln(' unmatched elements found:'); |
- for (Element element in _expectedElements) { |
- buffer.write(' '); |
- buffer.writeln(element); |
- } |
- throw new _ElementMismatchException(buffer.toString()); |
- } |
+ void _walk(ElementWalker walker, void callback()) { |
+ ElementWalker outerWalker = _walker; |
+ _walker = walker; |
+ callback(); |
+ walker.validate(); |
+ _walker = outerWalker; |
} |
} |
/** |
- * A visitor that can be used to collect all of the non-synthetic elements in an |
- * element model. |
+ * Keeps track of the set of non-synthetic child elements of an element, |
+ * yielding them one at a time in response to "get" method calls. |
*/ |
-class _ElementGatherer extends GeneralizingElementVisitor { |
+class ElementWalker { |
/** |
- * The set in which the elements are collected. |
+ * The element whose child elements are being walked. |
*/ |
- final Set<Element> elements = new HashSet<Element>(); |
+ final Element element; |
+ |
+ List<PropertyAccessorElement> _accessors; |
+ int _accessorIndex = 0; |
+ List<ClassElement> _classes; |
+ int _classIndex = 0; |
+ List<ConstructorElement> _constructors; |
+ int _constructorIndex = 0; |
+ List<ClassElement> _enums; |
+ int _enumIndex = 0; |
+ List<ExecutableElement> _functions; |
+ int _functionIndex = 0; |
+ List<LabelElement> _labels; |
+ int _labelIndex = 0; |
+ List<ParameterElement> _parameters; |
+ int _parameterIndex = 0; |
+ List<FunctionTypeAliasElement> _typedefs; |
+ int _typedefIndex = 0; |
+ List<TypeParameterElement> _typeParameters; |
+ int _typeParameterIndex = 0; |
+ List<VariableElement> _variables; |
+ int _variableIndex = 0; |
/** |
- * Initialize the visitor. |
+ * Creates an [ElementWalker] which walks the child elements of a class |
+ * element. |
*/ |
- _ElementGatherer(); |
+ ElementWalker.forClass(ClassElement element) |
+ : element = element, |
+ _accessors = element.accessors.where(_isNotSynthetic).toList(), |
+ _constructors = element.isMixinApplication |
+ ? null |
+ : element.constructors.where(_isNotSynthetic).toList(), |
+ _functions = element.methods, |
+ _typeParameters = element.typeParameters, |
+ _variables = element.fields.where(_isNotSynthetic).toList(); |
- @override |
- void visitElement(Element element) { |
- if (!element.isSynthetic) { |
- elements.add(element); |
- } |
- super.visitElement(element); |
- } |
-} |
+ /** |
+ * Creates an [ElementWalker] which walks the child elements of a compilation |
+ * unit element. |
+ */ |
+ ElementWalker.forCompilationUnit(CompilationUnitElement compilationUnit) |
+ : element = compilationUnit, |
+ _accessors = compilationUnit.accessors.where(_isNotSynthetic).toList(), |
+ _classes = compilationUnit.types, |
+ _enums = compilationUnit.enums, |
+ _functions = compilationUnit.functions, |
+ _typedefs = compilationUnit.functionTypeAliases, |
+ _variables = |
+ compilationUnit.topLevelVariables.where(_isNotSynthetic).toList(); |
-class _ElementMismatchException extends AnalysisException { |
/** |
- * Initialize a newly created exception to have the given [message] and |
- * [cause]. |
+ * Creates an [ElementWalker] which walks the child elements of a compilation |
+ * unit element. |
*/ |
- _ElementMismatchException(String message, [CaughtException cause = null]) |
- : super(message, cause); |
-} |
+ ElementWalker.forExecutable(ExecutableElement element) |
+ : element = element, |
+ _functions = element.functions, |
+ _labels = element.labels, |
+ _parameters = element.parameters, |
+ _typeParameters = element.typeParameters, |
+ _variables = element.localVariables; |
-/** |
- * A mixin for classes that use an existing element model to resolve a portion |
- * of an AST structure. |
- */ |
-class _ExistingElementResolver { |
/** |
- * The compilation unit containing the AST nodes being visited. |
+ * Creates an [ElementWalker] which walks the child elements of a parameter |
+ * element. |
*/ |
- CompilationUnitElementImpl _enclosingUnit; |
+ ElementWalker.forParameter(ParameterElement element) |
+ : element = element, |
+ _parameters = element.parameters; |
/** |
- * Throw an [ElementMismatchException] to report that the element model and the |
- * AST do not match. The [message] will have the path to the given [node] |
- * appended to it. |
+ * Creates an [ElementWalker] which walks the child elements of a typedef |
+ * element. |
*/ |
- void _mismatch(String message, AstNode node) { |
- StringBuffer buffer = new StringBuffer(); |
- buffer.write('Mismatch in '); |
- buffer.write(runtimeType); |
- buffer.write(' while resolving '); |
- buffer.writeln(_enclosingUnit?.source?.fullName); |
- buffer.writeln(message); |
- buffer.write('Path to root:'); |
- String separator = ' '; |
- AstNode parent = node; |
- while (parent != null) { |
- buffer.write(separator); |
- buffer.write(parent.runtimeType.toString()); |
- separator = ', '; |
- parent = parent.parent; |
+ ElementWalker.forTypedef(FunctionTypeAliasElement element) |
+ : element = element, |
+ _parameters = element.parameters, |
+ _typeParameters = element.typeParameters; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is an accessor; |
+ * throws an [IndexError] if there are no more. |
+ */ |
+ PropertyAccessorElement getAccessor() => _accessors[_accessorIndex++]; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is a class; throws |
+ * an [IndexError] if there are no more. |
+ */ |
+ ClassElement getClass() => _classes[_classIndex++]; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is a constructor; |
+ * throws an [IndexError] if there are no more. |
+ */ |
+ ConstructorElement getConstructor() => _constructors[_constructorIndex++]; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is an enum; throws |
+ * an [IndexError] if there are no more. |
+ */ |
+ ClassElement getEnum() => _enums[_enumIndex++]; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is a top level |
+ * function, method, or local function; throws an [IndexError] if there are no |
+ * more. |
+ */ |
+ ExecutableElement getFunction() => _functions[_functionIndex++]; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is a label; throws |
+ * an [IndexError] if there are no more. |
+ */ |
+ LabelElement getLabel() => _labels[_labelIndex++]; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is a parameter; |
+ * throws an [IndexError] if there are no more. |
+ */ |
+ ParameterElement getParameter() => _parameters[_parameterIndex++]; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is a typedef; |
+ * throws an [IndexError] if there are no more. |
+ */ |
+ FunctionTypeAliasElement getTypedef() => _typedefs[_typedefIndex++]; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is a type |
+ * parameter; throws an [IndexError] if there are no more. |
+ */ |
+ TypeParameterElement getTypeParameter() => |
+ _typeParameters[_typeParameterIndex++]; |
+ |
+ /** |
+ * Returns the next non-synthetic child of [element] which is a top level |
+ * variable, field, or local variable; throws an [IndexError] if there are no |
+ * more. |
+ */ |
+ VariableElement getVariable() => _variables[_variableIndex++]; |
+ |
+ /** |
+ * Verifies that all non-synthetic children of [element] have been obtained |
+ * from their corresponding "get" method calls; if not, throws a [StateError]. |
+ */ |
+ void validate() { |
+ void check(List<Element> elements, int index) { |
+ if (elements != null && elements.length != index) { |
+ throw new StateError( |
+ 'Unmatched ${elements[index].runtimeType} ${elements[index]}'); |
+ } |
} |
- throw new _ElementMismatchException(buffer.toString()); |
+ |
+ check(_accessors, _accessorIndex); |
+ check(_classes, _classIndex); |
+ check(_constructors, _constructorIndex); |
+ check(_enums, _enumIndex); |
+ check(_functions, _functionIndex); |
+ check(_labels, _labelIndex); |
+ check(_parameters, _parameterIndex); |
+ check(_typedefs, _typedefIndex); |
+ check(_typeParameters, _typeParameterIndex); |
+ check(_variables, _variableIndex); |
} |
+ |
+ static bool _isNotSynthetic(Element e) => !e.isSynthetic; |
+} |
+ |
+class _ElementMismatchException extends AnalysisException { |
+ /** |
+ * Creates an exception to refer to the given [compilationUnit], [element], |
+ * and [cause]. |
+ */ |
+ _ElementMismatchException( |
+ CompilationUnitElement compilationUnit, Element element, |
+ [CaughtException cause = null]) |
+ : super('Element mismatch in $compilationUnit at $element', cause); |
} |