Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(891)

Unified Diff: pkg/analyzer/lib/src/generated/resolver.dart

Issue 1669383002: More aggressively fail when associating an existing element model with an AST (issue 25678) (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/declaration_resolver_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/generated/resolver.dart
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index b38144176e94c7a8e9eec8cadc8af7ace27682fd..0c89d88f04d34df0b57f6133263d6774500e897f 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2030,8 +2030,8 @@ class DeadCodeVerifier extends RecursiveAstVisitor<Object> {
}
/**
- * Instances of the class `DeclarationResolver` are used to resolve declarations in an AST
- * structure to already built elements.
+ * A visitor that resolves declarations in an AST structure to already built
+ * elements.
*/
class DeclarationResolver extends RecursiveAstVisitor<Object> {
/**
@@ -2040,35 +2040,33 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
CompilationUnitElement _enclosingUnit;
/**
- * The function type alias containing the AST nodes being visited, or `null` if we are not
- * in the scope of a function type alias.
+ * 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.
+ * 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 method or function containing the AST nodes being visited, or `null` if
+ * we are not in the scope of a method or function.
*/
ExecutableElement _enclosingExecutable;
/**
- * The parameter containing the AST nodes being visited, or `null` if we are not in the
- * scope of a parameter.
+ * The parameter containing the AST nodes being visited, or `null` if we are
+ * not in the scope of a parameter.
*/
ParameterElement _enclosingParameter;
/**
- * Resolve the declarations within the given compilation unit to the elements rooted at the given
- * element.
- *
- * @param unit the compilation unit to be resolved
- * @param element the root of the element model used to resolve the AST nodes
+ * Resolve the declarations within the given compilation [unit] to the
+ * elements rooted at the given [element]. Throw an [ElementMismatchException]
+ * if the element model and compilation unit do not match each other.
*/
void resolve(CompilationUnit unit, CompilationUnitElement element) {
_enclosingUnit = element;
@@ -2122,9 +2120,17 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
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;
}
node.element = _enclosingExecutable as ConstructorElement;
@@ -2149,11 +2155,7 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
if (defaultValue != null) {
ExecutableElement outerExecutable = _enclosingExecutable;
try {
- if (element == null) {
- // TODO(brianwilkerson) Report this internal error.
- } else {
- _enclosingExecutable = element.initializer;
- }
+ _enclosingExecutable = element.initializer;
defaultValue.accept(this);
} finally {
_enclosingExecutable = outerExecutable;
@@ -2185,6 +2187,7 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
if (uri != null) {
LibraryElement library = _enclosingUnit.library;
ExportElement exportElement = _findExport(
+ node,
library.exports,
_enclosingUnit.context.sourceFactory
.resolveUri(_enclosingUnit.source, uri));
@@ -2229,10 +2232,18 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
_enclosingExecutable =
_findIdentifier(_enclosingExecutable.functions, functionName);
} else {
- PropertyAccessorElement accessor =
- _findIdentifier(_enclosingUnit.accessors, functionName);
- if ((property as KeywordToken).keyword == Keyword.SET) {
- accessor = accessor.variable.setter;
+ List<PropertyAccessorElement> accessors;
+ if (_enclosingClass != null) {
+ accessors = _enclosingClass.accessors;
+ } else {
+ accessors = _enclosingUnit.accessors;
+ }
+ PropertyAccessorElement accessor;
+ if ((property as KeywordToken).keyword == Keyword.GET) {
+ accessor = _findIdentifier(accessors, functionName);
+ } else if ((property as KeywordToken).keyword == Keyword.SET) {
+ accessor = _findWithNameAndOffset(accessors, functionName,
+ functionName.name + '=', functionName.offset);
functionName.staticElement = accessor;
}
_enclosingExecutable = accessor;
@@ -2248,8 +2259,8 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
@override
Object visitFunctionExpression(FunctionExpression node) {
if (node.parent is! FunctionDeclaration) {
- FunctionElement element =
- _findAtOffset(_enclosingExecutable.functions, node.beginToken.offset);
+ FunctionElement element = _findAtOffset(
+ _enclosingExecutable.functions, node, node.beginToken.offset);
node.element = element;
}
ExecutableElement outerExecutable = _enclosingExecutable;
@@ -2297,10 +2308,10 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
if (uri != null) {
LibraryElement library = _enclosingUnit.library;
ImportElement importElement = _findImport(
+ node,
library.imports,
_enclosingUnit.context.sourceFactory
- .resolveUri(_enclosingUnit.source, uri),
- node.prefix);
+ .resolveUri(_enclosingUnit.source, uri));
node.element = importElement;
}
return super.visitImportDirective(node);
@@ -2329,14 +2340,16 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
SimpleIdentifier methodName = node.name;
String nameOfMethod = methodName.name;
if (property == null) {
- _enclosingExecutable = _findWithNameAndOffset(
- _enclosingClass.methods, nameOfMethod, methodName.offset);
+ _enclosingExecutable = _findWithNameAndOffset(_enclosingClass.methods,
+ methodName, nameOfMethod, methodName.offset);
methodName.staticElement = _enclosingExecutable;
} else {
- PropertyAccessorElement accessor =
- _findIdentifier(_enclosingClass.accessors, methodName);
- if ((property as KeywordToken).keyword == Keyword.SET) {
- accessor = accessor.variable.setter;
+ PropertyAccessorElement accessor;
+ if ((property as KeywordToken).keyword == Keyword.GET) {
+ accessor = _findIdentifier(_enclosingClass.accessors, methodName);
+ } else if ((property as KeywordToken).keyword == Keyword.SET) {
+ accessor = _findWithNameAndOffset(_enclosingClass.accessors,
+ methodName, methodName.name + '=', methodName.offset);
methodName.staticElement = accessor;
}
_enclosingExecutable = accessor;
@@ -2353,7 +2366,7 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
if (uri != null) {
Source partSource = _enclosingUnit.context.sourceFactory
.resolveUri(_enclosingUnit.source, uri);
- node.element = _findPart(_enclosingUnit.library.parts, partSource);
+ node.element = _findPart(_enclosingUnit.library.parts, node, partSource);
}
return super.visitPartDirective(node);
}
@@ -2401,11 +2414,11 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
@override
Object visitTypeParameter(TypeParameter node) {
SimpleIdentifier parameterName = node.name;
-
- Element element;
+ Element element = null;
if (_enclosingExecutable != null) {
- element =
- _findIdentifier(_enclosingExecutable.typeParameters, parameterName);
+ element = _findIdentifier(
+ _enclosingExecutable.typeParameters, parameterName,
+ required: false);
}
if (element == null) {
if (_enclosingClass != null) {
@@ -2422,11 +2435,13 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
VariableElement element = null;
SimpleIdentifier variableName = node.name;
if (_enclosingExecutable != null) {
- element =
- _findIdentifier(_enclosingExecutable.localVariables, variableName);
+ element = _findIdentifier(
+ _enclosingExecutable.localVariables, variableName,
+ required: false);
}
if (element == null && _enclosingClass != null) {
- element = _findIdentifier(_enclosingClass.fields, variableName);
+ element = _findIdentifier(_enclosingClass.fields, variableName,
+ required: false);
}
if (element == null && _enclosingUnit != null) {
element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName);
@@ -2435,11 +2450,7 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
if (initializer != null) {
ExecutableElement outerExecutable = _enclosingExecutable;
try {
- if (element == null) {
- // TODO(brianwilkerson) Report this internal error.
- } else {
- _enclosingExecutable = element.initializer;
- }
+ _enclosingExecutable = element.initializer;
return super.visitVariableDeclaration(node);
} finally {
_enclosingExecutable = outerExecutable;
@@ -2449,63 +2460,61 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
}
/**
- * Return the element in the given array of elements that was created for the declaration at the
- * given offset. This method should only be used when there is no name
+ * 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.
*
- * @param elements the elements of the appropriate kind that exist in the current context
- * @param offset the offset of the name of the element to be returned
- * @return the element at the given offset
+ * This method should only be used when there is no name associated with the
+ * node.
*/
- Element _findAtOffset(List<Element> elements, int offset) =>
- _findWithNameAndOffset(elements, "", offset);
+ Element _findAtOffset(List<Element> elements, AstNode node, int offset) =>
+ _findWithNameAndOffset(elements, node, '', offset);
/**
- * Return the export element from the given array whose library has the given source, or
- * `null` if there is no such export.
- *
- * @param exports the export elements being searched
- * @param source the source of the library associated with the export element to being searched
- * for
- * @return the export element whose library has the given source
+ * Return the export element from the given list of [exports] whose library
+ * has the given [source]. Throw an [ElementMismatchException] if an element
+ * corresponding to the identifier cannot be found.
*/
- ExportElement _findExport(List<ExportElement> exports, Source source) {
+ ExportElement _findExport(
+ ExportDirective node, List<ExportElement> exports, Source source) {
for (ExportElement export in exports) {
if (export.exportedLibrary.source == source) {
return export;
}
}
- return null;
+ _mismatch("Could not find export element for '$source'", node);
+ return null; // Never reached
}
/**
- * Return the element in the given array of elements that was created for the declaration with the
- * given name.
- *
- * @param elements the elements of the appropriate kind that exist in the current context
- * @param identifier the name node in the declaration of the element to be returned
- * @return the element created for the declaration with the given name
+ * 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`.
*/
- Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier) {
- Element element =
- _findWithNameAndOffset(elements, identifier.name, identifier.offset);
+ Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier,
+ {bool required: true}) {
+ Element element = _findWithNameAndOffset(
+ elements, identifier, identifier.name, identifier.offset,
+ required: required);
identifier.staticElement = element;
return element;
}
/**
- * Return the import element from the given array whose library has the given source and that has
- * the given prefix, or `null` if there is no such import.
- *
- * @param imports the import elements being searched
- * @param source the source of the library associated with the import element to being searched
- * for
- * @param prefix the prefix with which the library was imported
- * @return the import element whose library has the given source and prefix
+ * Return the import element from the given list of [imports] whose library
+ * has the given [source] and that has the given [prefix]. Throw an
+ * [ElementMismatchException] if an element corresponding to the identifier
+ * cannot be found.
*/
ImportElement _findImport(
- List<ImportElement> imports, Source source, SimpleIdentifier prefix) {
+ ImportDirective node, List<ImportElement> imports, Source source) {
+ SimpleIdentifier prefix = node.prefix;
+ bool foundSource = false;
for (ImportElement element in imports) {
if (element.importedLibrary.source == source) {
+ foundSource = true;
PrefixElement prefixElement = element.prefix;
if (prefix == null) {
if (prefixElement == null) {
@@ -2519,52 +2528,76 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
}
}
}
- return null;
+ if (foundSource) {
+ if (prefix == null) {
+ _mismatch(
+ "Could not find import element for '$source' with no prefix", node);
+ }
+ _mismatch(
+ "Could not find import element for '$source' with prefix ${prefix.name}",
+ node);
+ }
+ _mismatch("Could not find import element for '$source'", node);
+ return null; // Never reached
}
/**
- * Return the element for the part with the given source, or `null` if there is no element
- * for the given source.
- *
- * @param parts the elements for the parts
- * @param partSource the source for the part whose element is to be returned
- * @return the element for the part with the given source
+ * Return the element in the given list of [parts] that was created for the
+ * part with the given [source]. Throw an [ElementMismatchException] if an
+ * element corresponding to the source cannot be found.
*/
- CompilationUnitElement _findPart(
- List<CompilationUnitElement> parts, Source partSource) {
+ CompilationUnitElement _findPart(List<CompilationUnitElement> parts,
+ PartDirective directive, Source source) {
for (CompilationUnitElement part in parts) {
- if (part.source == partSource) {
+ if (part.source == source) {
return part;
}
}
- return null;
+ _mismatch(
+ 'Could not find compilation unit element for "$source"', directive);
+ return null; // Never reached
}
/**
- * Return the element in the given array of elements that was created for the declaration with the
- * given name at the given offset.
- *
- * @param elements the elements of the appropriate kind that exist in the current context
- * @param name the name of the element to be returned
- * @param offset the offset of the name of the element to be returned
- * @return the element with the given name and offset
+ * 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, String name, int offset) {
+ List<Element> elements, AstNode node, String name, int offset,
+ {bool required: true}) {
for (Element element in elements) {
- if (element.nameOffset == offset && element.displayName == name) {
+ if (element.nameOffset == offset && element.name == name) {
return element;
}
}
- return null;
+ if (!required) {
+ return null;
+ }
+ for (Element element in elements) {
+ 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 parameters for a parameter with the given name.
- *
- * @param node the node defining the parameter with the given name
- * @param parameterName the name of the parameter being searched for
- * @return the element representing the parameter with that name
+ * 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) {
@@ -2578,32 +2611,22 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
if (parameters == null && _enclosingAlias != null) {
parameters = _enclosingAlias.parameters;
}
- ParameterElement element =
- parameters == null ? null : _findIdentifier(parameters, parameterName);
- if (element == null) {
+ if (parameters == null) {
StringBuffer buffer = new StringBuffer();
- buffer.writeln("Invalid state found in the Analysis Engine:");
+ buffer.writeln('Could not find parameter in enclosing scope');
buffer.writeln(
- "DeclarationResolver.getElementForParameter() is visiting a parameter that does not appear to be in a method or function.");
- buffer.writeln("Ancestors:");
- AstNode parent = node.parent;
- while (parent != null) {
- buffer.writeln(parent.runtimeType.toString());
- buffer.writeln("---------");
- parent = parent.parent;
- }
- AnalysisEngine.instance.logger.logError(buffer.toString(),
- new CaughtException(new AnalysisException(), null));
+ '(_enclosingParameter == null) == ${_enclosingParameter == null}');
+ buffer.writeln(
+ '(_enclosingExecutable == null) == ${_enclosingExecutable == null}');
+ buffer.writeln('(_enclosingAlias == null) == ${_enclosingAlias == null}');
+ _mismatch(buffer.toString(), parameterName);
}
- return element;
+ return _findIdentifier(parameters, parameterName);
}
/**
- * Return the value of the given string literal, or `null` if the string is not a constant
- * string without any string interpolation.
- *
- * @param literal the string literal whose value is to be returned
- * @return the value of the given string literal
+ * Return the value of the given string [literal], or `null` if the string is
+ * not a constant string without any string interpolation.
*/
String _getStringValue(StringLiteral literal) {
if (literal is StringInterpolation) {
@@ -2611,6 +2634,26 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
}
return literal.stringValue;
}
+
+ /**
+ * 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.
+ */
+ void _mismatch(String message, AstNode node) {
+ StringBuffer buffer = new StringBuffer();
+ 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;
+ }
+ throw new ElementMismatchException(buffer.toString());
+ }
}
/**
@@ -2974,6 +3017,15 @@ class ElementHolder {
}
}
+class ElementMismatchException extends AnalysisException {
+ /**
+ * Initialize a newly created exception to have the given [message] and
+ * [cause].
+ */
+ ElementMismatchException(String message, [CaughtException cause = null])
+ : super(message, cause);
+}
+
/**
* Instances of the class `EnclosedScope` implement a scope that is lexically enclosed in
* another scope.
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/declaration_resolver_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698