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

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

Issue 22285004: New analyzer_experimental snapshot. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 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
Index: pkg/analyzer_experimental/lib/src/generated/resolver.dart
diff --git a/pkg/analyzer_experimental/lib/src/generated/resolver.dart b/pkg/analyzer_experimental/lib/src/generated/resolver.dart
index 38919348c9fa7810d3c60e8bc15cf15c46db220c..2b056f4fb0cc30321c426187bce518ed4102dd63 100644
--- a/pkg/analyzer_experimental/lib/src/generated/resolver.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/resolver.dart
@@ -1248,6 +1248,625 @@ class HtmlUnitBuilder implements ht.XmlVisitor<Object> {
}
}
/**
+ * Instances of the class `DeadCodeVerifier` traverse an AST structure looking for cases of
+ * [HintCode#DEAD_CODE].
+ *
+ * @coverage dart.engine.resolver
+ */
+class DeadCodeVerifier extends RecursiveASTVisitor<Object> {
+
+ /**
+ * The error reporter by which errors will be reported.
+ */
+ ErrorReporter _errorReporter;
+
+ /**
+ * Create a new instance of the [DeadCodeVerifier].
+ *
+ * @param errorReporter the error reporter
+ */
+ DeadCodeVerifier(ErrorReporter errorReporter) {
+ this._errorReporter = errorReporter;
+ }
+ Object visitBinaryExpression(BinaryExpression node) {
+ sc.Token operator = node.operator;
+ bool isAmpAmp = identical(operator.type, sc.TokenType.AMPERSAND_AMPERSAND);
+ bool isBarBar = identical(operator.type, sc.TokenType.BAR_BAR);
+ if (isAmpAmp || isBarBar) {
+ Expression lhsCondition = node.leftOperand;
+ ValidResult lhsResult = getConstantBooleanValue(lhsCondition);
+ if (lhsResult != null) {
+ if (identical(lhsResult, ValidResult.RESULT_TRUE) && isBarBar) {
+ _errorReporter.reportError2(HintCode.DEAD_CODE, node.rightOperand, []);
+ safelyVisit(lhsCondition);
+ return null;
+ } else if (identical(lhsResult, ValidResult.RESULT_FALSE) && isAmpAmp) {
+ _errorReporter.reportError2(HintCode.DEAD_CODE, node.rightOperand, []);
+ safelyVisit(lhsCondition);
+ return null;
+ }
+ }
+ }
+ return super.visitBinaryExpression(node);
+ }
+
+ /**
+ * For each [Block], this method reports and error on all statements between the end of the
+ * block and the first return statement (assuming there it is not at the end of the block.)
+ *
+ * @param node the block to evaluate
+ */
+ Object visitBlock(Block node) {
+ NodeList<Statement> statements = node.statements;
+ int size = statements.length;
+ for (int i = 0; i < size; i++) {
+ Statement currentStatement = statements[i];
+ safelyVisit(currentStatement);
+ if (currentStatement is ReturnStatement && i != size - 1) {
+ Statement nextStatement = statements[i + 1];
+ Statement lastStatement = statements[size - 1];
+ int offset = nextStatement.offset;
+ int length = lastStatement.end - offset;
+ _errorReporter.reportError3(HintCode.DEAD_CODE, offset, length, []);
+ return null;
+ }
+ }
+ return null;
+ }
+ Object visitConditionalExpression(ConditionalExpression node) {
+ Expression conditionExpression = node.condition;
+ ValidResult result = getConstantBooleanValue(conditionExpression);
+ if (result != null) {
+ if (identical(result, ValidResult.RESULT_TRUE)) {
+ _errorReporter.reportError2(HintCode.DEAD_CODE, node.elseExpression, []);
+ safelyVisit(node.thenExpression);
+ return null;
+ } else {
+ _errorReporter.reportError2(HintCode.DEAD_CODE, node.thenExpression, []);
+ safelyVisit(node.elseExpression);
+ return null;
+ }
+ }
+ return super.visitConditionalExpression(node);
+ }
+ Object visitIfStatement(IfStatement node) {
+ Expression conditionExpression = node.condition;
+ ValidResult result = getConstantBooleanValue(conditionExpression);
+ if (result != null) {
+ if (identical(result, ValidResult.RESULT_TRUE)) {
+ Statement elseStatement = node.elseStatement;
+ if (elseStatement != null) {
+ _errorReporter.reportError2(HintCode.DEAD_CODE, elseStatement, []);
+ safelyVisit(node.thenStatement);
+ return null;
+ }
+ } else {
+ _errorReporter.reportError2(HintCode.DEAD_CODE, node.thenStatement, []);
+ safelyVisit(node.elseStatement);
+ return null;
+ }
+ }
+ return super.visitIfStatement(node);
+ }
+ Object visitTryStatement(TryStatement node) {
+ safelyVisit(node.body);
+ safelyVisit(node.finallyClause);
+ NodeList<CatchClause> catchClauses = node.catchClauses;
+ int numOfCatchClauses = catchClauses.length;
+ List<Type2> visitedTypes = new List<Type2>();
+ for (int i = 0; i < numOfCatchClauses; i++) {
+ CatchClause catchClause = catchClauses[i];
+ if (catchClause.onKeyword != null) {
+ TypeName typeName = catchClause.exceptionType;
+ if (typeName != null && typeName.type != null) {
+ Type2 currentType = typeName.type;
+ if (currentType.isObject) {
+ safelyVisit(catchClause);
+ if (i + 1 != numOfCatchClauses) {
+ CatchClause nextCatchClause = catchClauses[i + 1];
+ CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
+ int offset = nextCatchClause.offset;
+ int length = lastCatchClause.end - offset;
+ _errorReporter.reportError3(HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length, []);
+ return null;
+ }
+ }
+ for (Type2 type in visitedTypes) {
+ if (currentType.isSubtypeOf(type)) {
+ CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
+ int offset = catchClause.offset;
+ int length = lastCatchClause.end - offset;
+ _errorReporter.reportError3(HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, offset, length, [currentType.displayName, type.displayName]);
+ return null;
+ }
+ }
+ visitedTypes.add(currentType);
+ }
+ safelyVisit(catchClause);
+ } else {
+ safelyVisit(catchClause);
+ if (i + 1 != numOfCatchClauses) {
+ CatchClause nextCatchClause = catchClauses[i + 1];
+ CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
+ int offset = nextCatchClause.offset;
+ int length = lastCatchClause.end - offset;
+ _errorReporter.reportError3(HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length, []);
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+ Object visitWhileStatement(WhileStatement node) {
+ Expression conditionExpression = node.condition;
+ safelyVisit(conditionExpression);
+ ValidResult result = getConstantBooleanValue(conditionExpression);
+ if (result != null) {
+ if (identical(result, ValidResult.RESULT_FALSE)) {
+ _errorReporter.reportError2(HintCode.DEAD_CODE, node.body, []);
+ return null;
+ }
+ }
+ safelyVisit(node.body);
+ return null;
+ }
+
+ /**
+ * Given some [Expression], this method returns [ValidResult#RESULT_TRUE] if it is
+ * `true`, [ValidResult#RESULT_FALSE] if it is `false`, or `null` if the
+ * expression is not a constant boolean value.
+ *
+ * @param expression the expression to evaluate
+ * @return [ValidResult#RESULT_TRUE] if it is `true`, [ValidResult#RESULT_FALSE]
+ * if it is `false`, or `null` if the expression is not a constant boolean
+ * value
+ */
+ ValidResult getConstantBooleanValue(Expression expression) {
+ if (expression is BooleanLiteral) {
+ if (((expression as BooleanLiteral)).value) {
+ return ValidResult.RESULT_TRUE;
+ } else {
+ return ValidResult.RESULT_FALSE;
+ }
+ } else {
+ EvaluationResultImpl result = expression.accept(new ConstantVisitor());
+ if (identical(result, ValidResult.RESULT_TRUE)) {
+ return ValidResult.RESULT_TRUE;
+ } else if (identical(result, ValidResult.RESULT_FALSE)) {
+ return ValidResult.RESULT_FALSE;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * If the given node is not `null`, visit this instance of the dead code verifier.
+ *
+ * @param node the node to be visited
+ */
+ void safelyVisit(ASTNode node) {
+ if (node != null) {
+ node.accept(this);
+ }
+ }
+}
+/**
+ * Instances of the class `HintGenerator` traverse a library's worth of dart code at a time to
+ * generate hints over the set of sources.
+ *
+ * @see HintCode
+ * @coverage dart.engine.resolver
+ */
+class HintGenerator {
+ List<CompilationUnit> _compilationUnits;
+ AnalysisContext _context;
+ AnalysisErrorListener _errorListener;
+ ImportsVerifier _importsVerifier;
+ DeadCodeVerifier _deadCodeVerifier;
+ HintGenerator(List<CompilationUnit> compilationUnits, AnalysisContext context, AnalysisErrorListener errorListener) {
+ this._compilationUnits = compilationUnits;
+ this._context = context;
+ this._errorListener = errorListener;
+ LibraryElement library = compilationUnits[0].element.library;
+ _importsVerifier = new ImportsVerifier(library);
+ }
+ void generateForLibrary() {
+ for (int i = 0; i < _compilationUnits.length; i++) {
+ CompilationUnitElement element = _compilationUnits[i].element;
+ if (element != null) {
+ if (i == 0) {
+ _importsVerifier.inDefiningCompilationUnit = true;
+ generateForCompilationUnit(_compilationUnits[i], element.source);
+ _importsVerifier.inDefiningCompilationUnit = false;
+ } else {
+ generateForCompilationUnit(_compilationUnits[i], element.source);
+ }
+ }
+ }
+ _importsVerifier.generateUnusedImportHints(new ErrorReporter(_errorListener, _compilationUnits[0].element.source));
+ }
+ void generateForCompilationUnit(CompilationUnit unit, Source source) {
+ ErrorReporter errorReporter = new ErrorReporter(_errorListener, source);
+ _importsVerifier.visitCompilationUnit(unit);
+ _deadCodeVerifier = new DeadCodeVerifier(errorReporter);
+ _deadCodeVerifier.visitCompilationUnit(unit);
+ }
+}
+/**
+ * Instances of the class `ImportsVerifier` visit all of the referenced libraries in the
+ * source code verifying that all of the imports are used, otherwise a
+ * [HintCode#UNUSED_IMPORT] is generated with
+ * [generateUnusedImportHints].
+ *
+ * While this class does not yet have support for an "Organize Imports" action, this logic built up
+ * in this class could be used for such an action in the future.
+ *
+ * @coverage dart.engine.resolver
+ */
+class ImportsVerifier extends RecursiveASTVisitor<Object> {
+
+ /**
+ * This is set to `true` if the current compilation unit which is being visited is the
+ * defining compilation unit for the library, its value can be set with
+ * [setInDefiningCompilationUnit].
+ */
+ bool _inDefiningCompilationUnit = false;
+
+ /**
+ * The current library.
+ */
+ LibraryElement _currentLibrary;
+
+ /**
+ * A list of [ImportDirective]s that the current library imports, as identifiers are visited
+ * by this visitor and an import has been identified as being used by the library, the
+ * [ImportDirective] is removed from this list. After all the sources in the library have
+ * been evaluated, this list represents the set of unused imports.
+ *
+ * @see ImportsVerifier#generateUnusedImportErrors(ErrorReporter)
+ */
+ List<ImportDirective> _unusedImports;
+
+ /**
+ * This is a map between the set of [LibraryElement]s that the current library imports, and
+ * a list of [ImportDirective]s that imports the library. In cases where the current library
+ * imports a library with a single directive (such as `import lib1.dart;`), the library
+ * element will map to a list of one [ImportDirective], which will then be removed from the
+ * [unusedImports] list. In cases where the current library imports a library with multiple
+ * directives (such as `import lib1.dart; import lib1.dart show C;`), the
+ * [LibraryElement] will be mapped to a list of the import directives, and the namespace
+ * will need to be used to compute the correct [ImportDirective] being used, see
+ * [namespaceMap].
+ */
+ Map<LibraryElement, List<ImportDirective>> _libraryMap;
+
+ /**
+ * In cases where there is more than one import directive per library element, this mapping is
+ * used to determine which of the multiple import directives are used by generating a
+ * [Namespace] for each of the imports to do lookups in the same way that they are done from
+ * the [ElementResolver].
+ */
+ Map<ImportDirective, Namespace> _namespaceMap;
+
+ /**
+ * This is a map between prefix elements and the import directive from which they are derived. In
+ * cases where a type is referenced via a prefix element, the import directive can be marked as
+ * used (removed from the unusedImports) by looking at the resolved `lib` in `lib.X`,
+ * instead of looking at which library the `lib.X` resolves.
+ */
+ Map<PrefixElement, ImportDirective> _prefixElementMap;
+
+ /**
+ * Create a new instance of the [ImportsVerifier].
+ *
+ * @param errorReporter the error reporter
+ */
+ ImportsVerifier(LibraryElement library) {
+ this._currentLibrary = library;
+ this._unusedImports = new List<ImportDirective>();
+ this._libraryMap = new Map<LibraryElement, List<ImportDirective>>();
+ this._namespaceMap = new Map<ImportDirective, Namespace>();
+ this._prefixElementMap = new Map<PrefixElement, ImportDirective>();
+ }
+
+ /**
+ * After all of the compilation units have been visited by this visitor, this method can be called
+ * to report an [HintCode#UNUSED_IMPORT] hint for each of the import directives in the
+ * [unusedImports] list.
+ *
+ * @param errorReporter the error reporter to report the set of [HintCode#UNUSED_IMPORT]
+ * hints to
+ */
+ void generateUnusedImportHints(ErrorReporter errorReporter) {
+ for (ImportDirective unusedImport in _unusedImports) {
+ errorReporter.reportError2(HintCode.UNUSED_IMPORT, unusedImport.uri, []);
+ }
+ }
+ Object visitCompilationUnit(CompilationUnit node) {
+ if (_inDefiningCompilationUnit) {
+ NodeList<Directive> directives = node.directives;
+ for (Directive directive in directives) {
+ if (directive is ImportDirective) {
+ ImportDirective importDirective = directive as ImportDirective;
+ LibraryElement libraryElement = importDirective.uriElement;
+ if (libraryElement != null) {
+ _unusedImports.add(importDirective);
+ if (importDirective.asToken != null) {
+ SimpleIdentifier prefixIdentifier = importDirective.prefix;
+ if (prefixIdentifier != null) {
+ Element element = prefixIdentifier.element;
+ if (element is PrefixElement) {
+ PrefixElement prefixElementKey = element as PrefixElement;
+ _prefixElementMap[prefixElementKey] = importDirective;
+ }
+ }
+ }
+ putIntoLibraryMap(libraryElement, importDirective);
+ addAdditionalLibrariesForExports(_libraryMap, libraryElement, importDirective, new List<LibraryElement>());
+ }
+ }
+ }
+ }
+ if (_unusedImports.isEmpty) {
+ return null;
+ }
+ return super.visitCompilationUnit(node);
+ }
+ Object visitExportDirective(ExportDirective node) => null;
+ Object visitImportDirective(ImportDirective node) => null;
+ Object visitLibraryDirective(LibraryDirective node) => null;
+ Object visitPrefixedIdentifier(PrefixedIdentifier node) {
+ SimpleIdentifier prefixIdentifier = node.prefix;
+ Element element = prefixIdentifier.element;
+ if (element is PrefixElement) {
+ _unusedImports.remove(_prefixElementMap[element]);
+ return null;
+ }
+ return visitIdentifier(element, prefixIdentifier.name);
+ }
+ Object visitSimpleIdentifier(SimpleIdentifier node) => visitIdentifier(node.element, node.name);
+ void set inDefiningCompilationUnit(bool inDefiningCompilationUnit2) {
+ this._inDefiningCompilationUnit = inDefiningCompilationUnit2;
+ }
+
+ /**
+ * Recursively add any exported library elements into the [libraryMap].
+ */
+ void addAdditionalLibrariesForExports(Map<LibraryElement, List<ImportDirective>> map, LibraryElement library, ImportDirective importDirective, List<LibraryElement> exportPath) {
+ if (exportPath.contains(library)) {
+ return;
+ }
+ for (LibraryElement exportedLibraryElt in library.exportedLibraries) {
+ putIntoLibraryMap(exportedLibraryElt, importDirective);
+ exportPath.add(exportedLibraryElt);
+ addAdditionalLibrariesForExports(map, exportedLibraryElt, importDirective, exportPath);
+ }
+ }
+
+ /**
+ * Lookup and return the [Namespace] from the [namespaceMap], if the map does not
+ * have the computed namespace, compute it and cache it in the map. If the import directive is not
+ * resolved or is not resolvable, `null` is returned.
+ *
+ * @param importDirective the import directive used to compute the returned namespace
+ * @return the computed or looked up [Namespace]
+ */
+ Namespace computeNamespace(ImportDirective importDirective) {
+ Namespace namespace = _namespaceMap[importDirective];
+ if (namespace == null) {
+ ImportElement importElement = importDirective.element as ImportElement;
+ if (importElement != null) {
+ NamespaceBuilder builder = new NamespaceBuilder();
+ namespace = builder.createImportNamespace(importElement);
+ _namespaceMap[importDirective] = namespace;
+ }
+ }
+ return namespace;
+ }
+
+ /**
+ * The [libraryMap] is a mapping between a library elements and a list of import
+ * directives, but when adding these mappings into the [libraryMap], this method can be
+ * used to simply add the mapping between the library element an an import directive without
+ * needing to check to see if a list needs to be created.
+ */
+ void putIntoLibraryMap(LibraryElement libraryElement, ImportDirective importDirective) {
+ List<ImportDirective> importList = _libraryMap[libraryElement];
+ if (importList == null) {
+ importList = new List<ImportDirective>();
+ _libraryMap[libraryElement] = importList;
+ }
+ importList.add(importDirective);
+ }
+ Object visitIdentifier(Element element, String name) {
+ if (element == null) {
+ return null;
+ }
+ if (element is MultiplyDefinedElement) {
+ MultiplyDefinedElement multiplyDefinedElement = element as MultiplyDefinedElement;
+ for (Element elt in multiplyDefinedElement.conflictingElements) {
+ visitIdentifier(elt, name);
+ }
+ return null;
+ }
+ LibraryElement containingLibrary = element.library;
+ if (containingLibrary == null) {
+ return null;
+ }
+ if (_currentLibrary == containingLibrary) {
+ return null;
+ }
+ List<ImportDirective> importsFromSameLibrary = _libraryMap[containingLibrary];
+ if (importsFromSameLibrary == null) {
+ return null;
+ }
+ if (importsFromSameLibrary.length == 1) {
+ ImportDirective usedImportDirective = importsFromSameLibrary[0];
+ _unusedImports.remove(usedImportDirective);
+ } else {
+ for (ImportDirective importDirective in importsFromSameLibrary) {
+ Namespace namespace = computeNamespace(importDirective);
+ if (namespace != null && namespace.get(name) != null) {
+ _unusedImports.remove(importDirective);
+ }
+ }
+ }
+ return null;
+ }
+}
+/**
+ * Instances of the class `PubVerifier` traverse an AST structure looking for deviations from
+ * pub best practices.
+ */
+class PubVerifier extends RecursiveASTVisitor<Object> {
+ static String _PUBSPEC_YAML = "pubspec.yaml";
+
+ /**
+ * The analysis context containing the sources to be analyzed
+ */
+ AnalysisContext _context;
+
+ /**
+ * The error reporter by which errors will be reported.
+ */
+ ErrorReporter _errorReporter;
+ PubVerifier(AnalysisContext context, ErrorReporter errorReporter) {
+ this._context = context;
+ this._errorReporter = errorReporter;
+ }
+ Object visitImportDirective(ImportDirective directive) {
+ return null;
+ }
+
+ /**
+ * This verifies that the passed file import directive is not contained in a source inside a
+ * package "lib" directory hierarchy referencing a source outside that package "lib" directory
+ * hierarchy.
+ *
+ * @param uriLiteral the import URL (not `null`)
+ * @param path the file path being verified (not `null`)
+ * @return `true` if and only if an error code is generated on the passed node
+ * @see PubSuggestionCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE
+ */
+ bool checkForFileImportInsideLibReferencesFileOutside(StringLiteral uriLiteral, String path) {
+ Source source = getSource(uriLiteral);
+ String fullName = getSourceFullName(source);
+ if (fullName != null) {
+ int pathIndex = 0;
+ int fullNameIndex = fullName.length;
+ while (pathIndex < path.length && JavaString.startsWithBefore(path, "../", pathIndex)) {
+ fullNameIndex = JavaString.lastIndexOf(fullName, '/', fullNameIndex);
+ if (fullNameIndex < 4) {
+ return false;
+ }
+ if (JavaString.startsWithBefore(fullName, "/lib", fullNameIndex - 4)) {
+ String relativePubspecPath = path.substring(0, pathIndex + 3) + _PUBSPEC_YAML;
+ Source pubspecSource = _context.sourceFactory.resolveUri(source, relativePubspecPath);
+ if (pubspecSource.exists()) {
+ _errorReporter.reportError2(PubSuggestionCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE, uriLiteral, []);
+ }
+ return true;
+ }
+ pathIndex += 3;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This verifies that the passed file import directive is not contained in a source outside a
+ * package "lib" directory hierarchy referencing a source inside that package "lib" directory
+ * hierarchy.
+ *
+ * @param uriLiteral the import URL (not `null`)
+ * @param path the file path being verified (not `null`)
+ * @return `true` if and only if an error code is generated on the passed node
+ * @see PubSuggestionCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE
+ */
+ bool checkForFileImportOutsideLibReferencesFileInside(StringLiteral uriLiteral, String path) {
+ if (path.startsWith("lib/")) {
+ if (checkForFileImportOutsideLibReferencesFileInside2(uriLiteral, path, 0)) {
+ return true;
+ }
+ }
+ int pathIndex = path.indexOf("/lib/");
+ while (pathIndex != -1) {
+ if (checkForFileImportOutsideLibReferencesFileInside2(uriLiteral, path, pathIndex + 1)) {
+ return true;
+ }
+ pathIndex = JavaString.indexOf(path, "/lib/", pathIndex + 4);
+ }
+ return false;
+ }
+ bool checkForFileImportOutsideLibReferencesFileInside2(StringLiteral uriLiteral, String path, int pathIndex) {
+ Source source = getSource(uriLiteral);
+ String relativePubspecPath = path.substring(0, pathIndex) + _PUBSPEC_YAML;
+ Source pubspecSource = _context.sourceFactory.resolveUri(source, relativePubspecPath);
+ if (!pubspecSource.exists()) {
+ return false;
+ }
+ String fullName = getSourceFullName(source);
+ if (fullName != null) {
+ if (!fullName.contains("/lib/")) {
+ _errorReporter.reportError2(PubSuggestionCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE, uriLiteral, []);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This verifies that the passed package import directive does not contain ".."
+ *
+ * @param uriLiteral the import URL (not `null`)
+ * @param path the path to be validated (not `null`)
+ * @return `true` if and only if an error code is generated on the passed node
+ * @see PubSuggestionCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT
+ */
+ bool checkForPackageImportContainsDotDot(StringLiteral uriLiteral, String path) {
+ if (path.startsWith("../") || path.contains("/../")) {
+ _errorReporter.reportError2(PubSuggestionCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT, uriLiteral, []);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Answer the source associated with the compilation unit containing the given AST node.
+ *
+ * @param node the node (not `null`)
+ * @return the source or `null` if it could not be determined
+ */
+ Source getSource(ASTNode node) {
+ Source source = null;
+ CompilationUnit unit = node.getAncestor(CompilationUnit);
+ if (unit != null) {
+ CompilationUnitElement element = unit.element;
+ if (element != null) {
+ source = element.source;
+ }
+ }
+ return source;
+ }
+
+ /**
+ * Answer the full name of the given source. The returned value will have all
+ * [File#separatorChar] replace by '/'.
+ *
+ * @param source the source
+ * @return the full name or `null` if it could not be determined
+ */
+ String getSourceFullName(Source source) {
+ if (source != null) {
+ String fullName = source.fullName;
+ if (fullName != null) {
+ return fullName.replaceAll(r'\', '/');
+ }
+ }
+ return null;
+ }
+}
+/**
* Instances of the class `DeclarationResolver` are used to resolve declarations in an AST
* structure to already built elements.
*/
@@ -1889,7 +2508,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
* The name of the method that will be invoked if an attempt is made to invoke an undefined method
* on an object.
*/
- static String _NO_SUCH_METHOD_METHOD_NAME = "noSuchMethod";
+ static String NO_SUCH_METHOD_METHOD_NAME = "noSuchMethod";
/**
* Initialize a newly created visitor to resolve the nodes in a compilation unit.
@@ -1913,7 +2532,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
node.staticElement = staticMethod;
Type2 propagatedType = getPropagatedType(leftHandSide);
MethodElement propagatedMethod = lookUpMethod(leftHandSide, propagatedType, methodName);
- node.element = select2(staticMethod, propagatedMethod);
+ node.propagatedElement = propagatedMethod;
if (shouldReportMissingMember(staticType, staticMethod) && (_strictMode || propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
_resolver.reportError6(StaticTypeWarningCode.UNDEFINED_METHOD, operator, [methodName, staticType.displayName]);
}
@@ -1932,7 +2551,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
node.staticElement = staticMethod;
Type2 propagatedType = getPropagatedType(leftOperand);
MethodElement propagatedMethod = lookUpMethod(leftOperand, propagatedType, methodName);
- node.element = select2(staticMethod, propagatedMethod);
+ node.propagatedElement = propagatedMethod;
if (shouldReportMissingMember(staticType, staticMethod) && (_strictMode || propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
_resolver.reportError6(StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [methodName, staticType.displayName]);
}
@@ -2235,15 +2854,15 @@ class ElementResolver extends SimpleASTVisitor<Object> {
recordResolution2(methodName, staticElement, propagatedElement);
ArgumentList argumentList = node.argumentList;
if (staticElement != null) {
- List<ParameterElement> parameters = computePropagatedParameters(argumentList, staticElement);
+ List<ParameterElement> parameters = computeCorrespondingParameters(argumentList, staticElement);
if (parameters != null) {
argumentList.correspondingStaticParameters = parameters;
}
}
if (propagatedElement != null) {
- List<ParameterElement> parameters = computePropagatedParameters(argumentList, propagatedElement);
+ List<ParameterElement> parameters = computeCorrespondingParameters(argumentList, propagatedElement);
if (parameters != null) {
- argumentList.correspondingParameters = parameters;
+ argumentList.correspondingPropagatedParameters = parameters;
}
}
ErrorCode errorCode = checkForInvocationError(target, staticElement);
@@ -2290,7 +2909,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
node.staticElement = staticMethod;
Type2 propagatedType = getPropagatedType(operand);
MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, methodName);
- node.element = select2(staticMethod, propagatedMethod);
+ node.propagatedElement = propagatedMethod;
if (shouldReportMissingMember(staticType, staticMethod) && (_strictMode || propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
_resolver.reportError6(StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [methodName, staticType.displayName]);
}
@@ -2341,7 +2960,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
node.staticElement = staticMethod;
Type2 propagatedType = getPropagatedType(operand);
MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, methodName);
- node.element = select2(staticMethod, propagatedMethod);
+ node.propagatedElement = propagatedMethod;
if (shouldReportMissingMember(staticType, staticMethod) && (_strictMode || propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
_resolver.reportError6(StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [methodName, staticType.displayName]);
}
@@ -2385,16 +3004,16 @@ class ElementResolver extends SimpleASTVisitor<Object> {
return null;
}
Object visitSimpleIdentifier(SimpleIdentifier node) {
- if (node.element != null) {
+ if (node.staticElement != null || node.element != null) {
return null;
}
Element element = resolveSimpleIdentifier(node);
if (isFactoryConstructorReturnType(node) && element != _resolver.enclosingClass) {
_resolver.reportError(CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS, node, []);
- } else if (element == null) {
+ } else if (element == null || (element is PrefixElement && !isValidAsPrefix(node))) {
if (isConstructorReturnType(node)) {
_resolver.reportError(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
- } else if (!classDeclaresNoSuchMethod(_resolver.enclosingClass)) {
+ } else {
_resolver.reportError(StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]);
}
}
@@ -2491,22 +3110,22 @@ class ElementResolver extends SimpleASTVisitor<Object> {
* @param element the element to be invoked
* @return the error code that should be reported
*/
- ErrorCode checkForInvocationError(Expression target, Element element2) {
- if (element2 is PropertyAccessorElement) {
- FunctionType getterType = ((element2 as PropertyAccessorElement)).type;
+ ErrorCode checkForInvocationError(Expression target, Element element) {
+ if (element is PropertyAccessorElement) {
+ FunctionType getterType = ((element as PropertyAccessorElement)).type;
if (getterType != null) {
Type2 returnType = getterType.returnType;
if (!isExecutableType(returnType)) {
return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
}
}
- } else if (element2 is ExecutableElement) {
+ } else if (element is ExecutableElement) {
return null;
- } else if (element2 == null && target is SuperExpression) {
+ } else if (element == null && target is SuperExpression) {
return StaticTypeWarningCode.UNDEFINED_SUPER_METHOD;
} else {
- if (element2 is PropertyInducingElement) {
- PropertyAccessorElement getter = ((element2 as PropertyInducingElement)).getter;
+ if (element is PropertyInducingElement) {
+ PropertyAccessorElement getter = ((element as PropertyInducingElement)).getter;
FunctionType getterType = getter.type;
if (getterType != null) {
Type2 returnType = getterType.returnType;
@@ -2514,8 +3133,8 @@ class ElementResolver extends SimpleASTVisitor<Object> {
return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
}
}
- } else if (element2 is VariableElement) {
- Type2 variableType = ((element2 as VariableElement)).type;
+ } else if (element is VariableElement) {
+ Type2 variableType = ((element as VariableElement)).type;
if (!isExecutableType(variableType)) {
return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
}
@@ -2524,10 +3143,8 @@ class ElementResolver extends SimpleASTVisitor<Object> {
ClassElement enclosingClass = _resolver.enclosingClass;
if (enclosingClass == null) {
return StaticTypeWarningCode.UNDEFINED_FUNCTION;
- } else if (element2 == null) {
- if (!classDeclaresNoSuchMethod(enclosingClass)) {
- return StaticTypeWarningCode.UNDEFINED_METHOD;
- }
+ } else if (element == null) {
+ return StaticTypeWarningCode.UNDEFINED_METHOD;
} else {
return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
}
@@ -2535,7 +3152,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
Type2 targetType = getStaticType(target);
if (targetType == null) {
return StaticTypeWarningCode.UNDEFINED_FUNCTION;
- } else if (!targetType.isDynamic && !classDeclaresNoSuchMethod2(targetType.element)) {
+ } else if (!targetType.isDynamic) {
return StaticTypeWarningCode.UNDEFINED_METHOD;
}
}
@@ -2545,36 +3162,6 @@ class ElementResolver extends SimpleASTVisitor<Object> {
}
/**
- * Return `true` if the given class declares a method named "noSuchMethod" and is not the
- * class 'Object'.
- *
- * @param element the class being tested
- * @return `true` if the given class declares a method named "noSuchMethod"
- */
- bool classDeclaresNoSuchMethod(ClassElement classElement) {
- if (classElement == null) {
- return false;
- }
- MethodElement methodElement = classElement.lookUpMethod(_NO_SUCH_METHOD_METHOD_NAME, _resolver.definingLibrary);
- return methodElement != null && methodElement.enclosingElement.supertype != null;
- }
-
- /**
- * Return `true` if the given element represents a class that declares a method named
- * "noSuchMethod" and is not the class 'Object'.
- *
- * @param element the element being tested
- * @return `true` if the given element represents a class that declares a method named
- * "noSuchMethod"
- */
- bool classDeclaresNoSuchMethod2(Element element) {
- if (element is ClassElement) {
- return classDeclaresNoSuchMethod((element as ClassElement));
- }
- return false;
- }
-
- /**
* Given a list of arguments and the element that will be invoked using those argument, compute
* the list of parameters that correspond to the list of arguments. Return the parameters that
* correspond to the arguments, or `null` if no correspondence could be computed.
@@ -2583,7 +3170,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
* @param executableElement the element that will be invoked with the arguments
* @return the parameters that correspond to the arguments
*/
- List<ParameterElement> computePropagatedParameters(ArgumentList argumentList, Element element2) {
+ List<ParameterElement> computeCorrespondingParameters(ArgumentList argumentList, Element element2) {
if (element2 is PropertyAccessorElement) {
FunctionType getterType = ((element2 as PropertyAccessorElement)).type;
if (getterType != null) {
@@ -2780,6 +3367,28 @@ class ElementResolver extends SimpleASTVisitor<Object> {
}
/**
+ * Return `true` if the given node can validly be resolved to a prefix:
+ *
+ * * it is the prefix in an import directive, or
+ * * it is the prefix in a prefixed identifier.
+ *
+ *
+ * @param node the node being tested
+ * @return `true` if the given node is the prefix in an import directive
+ */
+ bool isValidAsPrefix(SimpleIdentifier node) {
+ ASTNode parent = node.parent;
+ if (parent is ImportDirective) {
+ return identical(((parent as ImportDirective)).prefix, node);
+ } else if (parent is PrefixedIdentifier) {
+ return true;
+ } else if (parent is MethodInvocation) {
+ return identical(((parent as MethodInvocation)).target, node);
+ }
+ return false;
+ }
+
+ /**
* Looks up the method element with the given name for index expression, reports
* [StaticWarningCode#UNDEFINED_OPERATOR] if not found.
*
@@ -2793,7 +3402,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
MethodElement staticMethod = lookUpMethod(target, staticType, methodName);
MethodElement propagatedMethod = lookUpMethod(target, propagatedType, methodName);
node.staticElement = staticMethod;
- node.element = select2(staticMethod, propagatedMethod);
+ node.propagatedElement = propagatedMethod;
if (shouldReportMissingMember(staticType, staticMethod) && (_strictMode || propagatedType == null || shouldReportMissingMember(propagatedType, propagatedMethod))) {
sc.Token leftBracket = node.leftBracket;
sc.Token rightBracket = node.rightBracket;
@@ -3315,7 +3924,7 @@ class ElementResolver extends SimpleASTVisitor<Object> {
String name = nameNode.name;
ParameterElement element = namedParameters[name];
if (element == null) {
- ErrorCode errorCode = reportError2 ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER : StaticWarningCode.UNDEFINED_NAMED_PARAMETER;
+ ErrorCode errorCode = (reportError2 ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER : StaticWarningCode.UNDEFINED_NAMED_PARAMETER) as ErrorCode;
_resolver.reportError(errorCode, nameNode, [name]);
} else {
resolvedParameters[i] = element;
@@ -3332,10 +3941,10 @@ class ElementResolver extends SimpleASTVisitor<Object> {
}
}
if (positionalArgumentCount < requiredParameters.length) {
- ErrorCode errorCode = reportError2 ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS;
+ ErrorCode errorCode = (reportError2 ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS) as ErrorCode;
_resolver.reportError(errorCode, argumentList, [requiredParameters.length, positionalArgumentCount]);
} else if (positionalArgumentCount > unnamedParameterCount) {
- ErrorCode errorCode = reportError2 ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS;
+ ErrorCode errorCode = (reportError2 ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS) as ErrorCode;
_resolver.reportError(errorCode, argumentList, [unnamedParameterCount, positionalArgumentCount]);
}
return resolvedParameters;
@@ -3462,25 +4071,21 @@ class ElementResolver extends SimpleASTVisitor<Object> {
Element selectedElement = select(staticElement, propagatedElement);
propertyName.element = selectedElement;
if (shouldReportMissingMember(staticType, staticElement) && (_strictMode || propagatedType == null || shouldReportMissingMember(propagatedType, propagatedElement))) {
- bool staticNoSuchMethod = staticType != null && classDeclaresNoSuchMethod2(staticType.element);
- bool propagatedNoSuchMethod = propagatedType != null && classDeclaresNoSuchMethod2(propagatedType.element);
- if (!staticNoSuchMethod && (_strictMode || !propagatedNoSuchMethod)) {
- bool isStaticProperty = isStatic(selectedElement);
- if (propertyName.inSetterContext()) {
- if (isStaticProperty) {
- _resolver.reportError(StaticWarningCode.UNDEFINED_SETTER, propertyName, [propertyName.name, staticType.displayName]);
- } else {
- _resolver.reportError(StaticTypeWarningCode.UNDEFINED_SETTER, propertyName, [propertyName.name, staticType.displayName]);
- }
- } else if (propertyName.inGetterContext()) {
- if (isStaticProperty) {
- _resolver.reportError(StaticWarningCode.UNDEFINED_GETTER, propertyName, [propertyName.name, staticType.displayName]);
- } else {
- _resolver.reportError(StaticTypeWarningCode.UNDEFINED_GETTER, propertyName, [propertyName.name, staticType.displayName]);
- }
+ bool isStaticProperty = isStatic(selectedElement);
+ if (propertyName.inSetterContext()) {
+ if (isStaticProperty) {
+ _resolver.reportError(StaticWarningCode.UNDEFINED_SETTER, propertyName, [propertyName.name, staticType.displayName]);
+ } else {
+ _resolver.reportError(StaticTypeWarningCode.UNDEFINED_SETTER, propertyName, [propertyName.name, staticType.displayName]);
+ }
+ } else if (propertyName.inGetterContext()) {
+ if (isStaticProperty) {
+ _resolver.reportError(StaticWarningCode.UNDEFINED_GETTER, propertyName, [propertyName.name, staticType.displayName]);
} else {
- _resolver.reportError(StaticWarningCode.UNDEFINED_IDENTIFIER, propertyName, [propertyName.name]);
+ _resolver.reportError(StaticTypeWarningCode.UNDEFINED_GETTER, propertyName, [propertyName.name, staticType.displayName]);
}
+ } else {
+ _resolver.reportError(StaticWarningCode.UNDEFINED_IDENTIFIER, propertyName, [propertyName.name]);
}
}
}
@@ -3607,9 +4212,6 @@ class ElementResolver extends SimpleASTVisitor<Object> {
if (member != null || type == null || type.isDynamic) {
return false;
}
- if (type is InterfaceType) {
- return !classDeclaresNoSuchMethod(((type as InterfaceType)).element);
- }
return true;
}
}
@@ -3926,8 +4528,9 @@ class InheritanceManager {
}
InterfaceType supertype = classElt.supertype;
ClassElement superclassElement = supertype != null ? supertype.element : null;
+ List<InterfaceType> mixins = classElt.mixins;
List<InterfaceType> interfaces = classElt.interfaces;
- if ((superclassElement == null || supertype.isObject) && interfaces.length == 0) {
+ if ((superclassElement == null || supertype.isObject) && mixins.length == 0 && interfaces.length == 0) {
_interfaceLookup[classElt] = resultMap;
return resultMap;
}
@@ -3950,6 +4553,15 @@ class InheritanceManager {
}
}
}
+ for (InterfaceType mixinType in mixins) {
+ ClassElement mixinElement = mixinType.element;
+ if (mixinElement == null) {
+ continue;
+ }
+ Map<String, ExecutableElement> mapWithMixinMembers = new Map<String, ExecutableElement>();
+ recordMapWithClassMembers(mapWithMixinMembers, mixinElement);
+ lookupMaps.add(mapWithMixinMembers);
+ }
for (InterfaceType interfaceType in interfaces) {
ClassElement interfaceElement = interfaceType.element;
if (interfaceElement != null) {
@@ -4141,7 +4753,8 @@ class InheritanceManager {
* Record the passed map with the set of all members (methods, getters and setters) in the class
* into the passed map.
*
- * @param map some non-`null`
+ * @param map some non-`null` map to put the methods and accessors from the passed
+ * [ClassElement] into
* @param classElt the class element that will be recorded into the passed map
*/
void recordMapWithClassMembers(Map<String, ExecutableElement> map, ClassElement classElt) {
@@ -4280,6 +4893,24 @@ class Library {
}
/**
+ * Return an array of the [CompilationUnit]s that make up the library. The first unit is
+ * always the defining unit.
+ *
+ * @return an array of the [CompilationUnit]s that make up the library. The first unit is
+ * always the defining unit
+ */
+ List<CompilationUnit> get compilationUnits {
+ List<CompilationUnit> unitArrayList = new List<CompilationUnit>();
+ unitArrayList.add(definingCompilationUnit);
+ for (Source source in _astMap.keys.toSet()) {
+ if (_librarySource != source) {
+ unitArrayList.add(getAST(source));
+ }
+ }
+ return new List.from(unitArrayList);
+ }
+
+ /**
* Return a collection containing the sources for the compilation units in this library, including
* the defining compilation unit.
*
@@ -4396,6 +5027,7 @@ class Library {
}
String uriContent = uriLiteral.stringValue.trim();
_directiveUris[directive] = uriContent;
+ uriContent = Uri.encodeFull(uriContent);
try {
parseUriWithException(uriContent);
Source source = getSource2(uriContent);
@@ -4969,6 +5601,7 @@ class LibraryResolver {
nameToPrefixMap[prefixName] = prefix;
}
importElement.prefix = prefix;
+ prefixNode.staticElement = prefix;
}
directive.element = importElement;
imports.add(importElement);
@@ -5313,6 +5946,7 @@ class LibraryResolver {
if (uriContent == null) {
return null;
}
+ uriContent = Uri.encodeFull(uriContent);
try {
parseUriWithException(uriContent);
return _analysisContext.sourceFactory.resolveUri(librarySource, uriContent);
@@ -5350,9 +5984,10 @@ class LibraryResolver {
unit.accept(constantVerifier);
ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter, library.libraryElement, _typeProvider, library.inheritanceManager);
unit.accept(errorVerifier);
- if (_enableHints) {
- new HintVerifier(_analysisContext, errorReporter).visitCompilationUnit(unit);
- }
+ }
+ if (_enableHints) {
+ HintGenerator hintGenerator = new HintGenerator(library.compilationUnits, _analysisContext, _errorListener);
+ hintGenerator.generateForLibrary();
}
}
}
@@ -5674,7 +6309,7 @@ class ResolverVisitor extends ScopedVisitor {
try {
_overrideManager.enterScope();
propagateTrueState(condition);
- thenStatement.accept(this);
+ visitStatementInScope(thenStatement);
} finally {
thenOverrides = _overrideManager.captureLocalOverrides();
_overrideManager.exitScope();
@@ -5686,7 +6321,7 @@ class ResolverVisitor extends ScopedVisitor {
try {
_overrideManager.enterScope();
propagateFalseState(condition);
- elseStatement.accept(this);
+ visitStatementInScope(elseStatement);
} finally {
elseOverrides = _overrideManager.captureLocalOverrides();
_overrideManager.exitScope();
@@ -5798,7 +6433,7 @@ class ResolverVisitor extends ScopedVisitor {
try {
_overrideManager.enterScope();
propagateTrueState(condition);
- body.accept(this);
+ visitStatementInScope(body);
} finally {
_overrideManager.exitScope();
}
@@ -5886,7 +6521,7 @@ class ResolverVisitor extends ScopedVisitor {
recordPropagatedType(loopVariable.identifier, iteratorElementType);
}
}
- body.accept(this);
+ visitStatementInScope(body);
} finally {
_overrideManager.exitScope();
}
@@ -5901,7 +6536,7 @@ class ResolverVisitor extends ScopedVisitor {
_overrideManager.enterScope();
try {
propagateTrueState(node.condition);
- safelyVisit(node.body);
+ visitStatementInScope(node.body);
node.updaters.accept(this);
} finally {
_overrideManager.exitScope();
@@ -5988,7 +6623,7 @@ class ResolverVisitor extends ScopedVisitor {
*/
void inferFunctionExpressionsParametersTypes(ArgumentList argumentList) {
for (Expression argument in argumentList.arguments) {
- ParameterElement parameter = argument.parameterElement;
+ ParameterElement parameter = argument.propagatedParameterElement;
if (parameter == null) {
parameter = argument.staticParameterElement;
}
@@ -6216,8 +6851,8 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
TypeProvider get typeProvider => _typeProvider;
Object visitBlock(Block node) {
Scope outerScope = _nameScope;
- _nameScope = new EnclosedScope(_nameScope);
try {
+ _nameScope = new EnclosedScope(_nameScope);
super.visitBlock(node);
} finally {
_nameScope = outerScope;
@@ -6228,8 +6863,8 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
SimpleIdentifier exception = node.exceptionParameter;
if (exception != null) {
Scope outerScope = _nameScope;
- _nameScope = new EnclosedScope(_nameScope);
try {
+ _nameScope = new EnclosedScope(_nameScope);
_nameScope.define(exception.element);
SimpleIdentifier stackTrace = node.stackTraceParameter;
if (stackTrace != null) {
@@ -6281,38 +6916,39 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
return null;
}
Object visitDoStatement(DoStatement node) {
- LabelScope outerScope = _labelScope;
- _labelScope = new LabelScope.con1(outerScope, false, false);
+ LabelScope outerLabelScope = _labelScope;
try {
- super.visitDoStatement(node);
+ _labelScope = new LabelScope.con1(_labelScope, false, false);
+ visitStatementInScope(node.body);
+ safelyVisit(node.condition);
} finally {
- _labelScope = outerScope;
+ _labelScope = outerLabelScope;
}
return null;
}
Object visitForEachStatement(ForEachStatement node) {
- LabelScope outerLabelScope = _labelScope;
- _labelScope = new LabelScope.con1(outerLabelScope, false, false);
Scope outerNameScope = _nameScope;
- _nameScope = new EnclosedScope(_nameScope);
+ LabelScope outerLabelScope = _labelScope;
try {
+ _nameScope = new EnclosedScope(_nameScope);
+ _labelScope = new LabelScope.con1(outerLabelScope, false, false);
visitForEachStatementInScope(node);
} finally {
- _nameScope = outerNameScope;
_labelScope = outerLabelScope;
+ _nameScope = outerNameScope;
}
return null;
}
Object visitForStatement(ForStatement node) {
- LabelScope outerLabelScope = _labelScope;
- _labelScope = new LabelScope.con1(outerLabelScope, false, false);
Scope outerNameScope = _nameScope;
- _nameScope = new EnclosedScope(_nameScope);
+ LabelScope outerLabelScope = _labelScope;
try {
+ _nameScope = new EnclosedScope(_nameScope);
+ _labelScope = new LabelScope.con1(outerLabelScope, false, false);
visitForStatementInScope(node);
} finally {
- _nameScope = outerNameScope;
_labelScope = outerLabelScope;
+ _nameScope = outerNameScope;
}
return null;
}
@@ -6358,6 +6994,12 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
}
return null;
}
+ Object visitIfStatement(IfStatement node) {
+ safelyVisit(node.condition);
+ visitStatementInScope(node.thenStatement);
+ visitStatementInScope(node.elseStatement);
+ return null;
+ }
Object visitLabeledStatement(LabeledStatement node) {
LabelScope outerScope = addScopesFor(node.labels);
try {
@@ -6380,8 +7022,8 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
Object visitSwitchCase(SwitchCase node) {
node.expression.accept(this);
Scope outerNameScope = _nameScope;
- _nameScope = new EnclosedScope(_nameScope);
try {
+ _nameScope = new EnclosedScope(_nameScope);
node.statements.accept(this);
} finally {
_nameScope = outerNameScope;
@@ -6390,8 +7032,8 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
}
Object visitSwitchDefault(SwitchDefault node) {
Scope outerNameScope = _nameScope;
- _nameScope = new EnclosedScope(_nameScope);
try {
+ _nameScope = new EnclosedScope(_nameScope);
node.statements.accept(this);
} finally {
_nameScope = outerNameScope;
@@ -6400,15 +7042,15 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
}
Object visitSwitchStatement(SwitchStatement node) {
LabelScope outerScope = _labelScope;
- _labelScope = new LabelScope.con1(outerScope, true, false);
- for (SwitchMember member in node.members) {
- for (Label label in member.labels) {
- SimpleIdentifier labelName = label.label;
- LabelElement labelElement = labelName.element as LabelElement;
- _labelScope = new LabelScope.con2(_labelScope, labelName.name, labelElement);
- }
- }
try {
+ _labelScope = new LabelScope.con1(outerScope, true, false);
+ for (SwitchMember member in node.members) {
+ for (Label label in member.labels) {
+ SimpleIdentifier labelName = label.label;
+ LabelElement labelElement = labelName.element as LabelElement;
+ _labelScope = new LabelScope.con2(_labelScope, labelName.name, labelElement);
+ }
+ }
super.visitSwitchStatement(node);
} finally {
_labelScope = outerScope;
@@ -6427,9 +7069,10 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
}
Object visitWhileStatement(WhileStatement node) {
LabelScope outerScope = _labelScope;
- _labelScope = new LabelScope.con1(outerScope, false, false);
try {
- super.visitWhileStatement(node);
+ _labelScope = new LabelScope.con1(outerScope, false, false);
+ safelyVisit(node.condition);
+ visitStatementInScope(node.body);
} finally {
_labelScope = outerScope;
}
@@ -6505,7 +7148,7 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
void visitForEachStatementInScope(ForEachStatement node) {
safelyVisit(node.iterator);
safelyVisit(node.loopVariable);
- safelyVisit(node.body);
+ visitStatementInScope(node.body);
}
/**
@@ -6516,7 +7159,31 @@ abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> {
* @param node the statement to be visited
*/
void visitForStatementInScope(ForStatement node) {
- super.visitForStatement(node);
+ safelyVisit(node.variables);
+ safelyVisit(node.initialization);
+ safelyVisit(node.condition);
+ node.updaters.accept(this);
+ visitStatementInScope(node.body);
+ }
+
+ /**
+ * Visit the given statement after it's scope has been created. This is used by ResolverVisitor to
+ * correctly visit the 'then' and 'else' statements of an 'if' statement.
+ *
+ * @param node the statement to be visited
+ */
+ void visitStatementInScope(Statement node) {
+ if (node is Block) {
+ visitBlock((node as Block));
+ } else if (node != null) {
+ Scope outerNameScope = _nameScope;
+ try {
+ _nameScope = new EnclosedScope(_nameScope);
+ node.accept(this);
+ } finally {
+ _nameScope = outerNameScope;
+ }
+ }
}
/**
@@ -6753,7 +7420,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
Type2 staticType = getStaticType(rightHandSide);
recordStaticType(node, staticType);
Type2 overrideType = staticType;
- Type2 propagatedType = getPropagatedType(rightHandSide);
+ Type2 propagatedType = rightHandSide.propagatedType;
if (propagatedType != null) {
if (propagatedType.isMoreSpecificThan(staticType)) {
recordPropagatedType2(node, propagatedType);
@@ -6768,7 +7435,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
ExecutableElement staticMethodElement = node.staticElement;
Type2 staticType = computeStaticReturnType(staticMethodElement);
recordStaticType(node, staticType);
- MethodElement propagatedMethodElement = node.element;
+ MethodElement propagatedMethodElement = node.propagatedElement;
if (propagatedMethodElement != staticMethodElement) {
Type2 propagatedType = computeStaticReturnType(propagatedMethodElement);
if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
@@ -6821,7 +7488,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
Type2 staticType = computeStaticReturnType(staticMethodElement);
staticType = refineBinaryExpressionType(node, staticType);
recordStaticType(node, staticType);
- MethodElement propagatedMethodElement = node.element;
+ MethodElement propagatedMethodElement = node.propagatedElement;
if (propagatedMethodElement != staticMethodElement) {
Type2 propagatedType = computeStaticReturnType(propagatedMethodElement);
if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
@@ -6847,7 +7514,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
*/
Object visitCascadeExpression(CascadeExpression node) {
recordStaticType(node, getStaticType(node.target));
- recordPropagatedType2(node, getPropagatedType(node.target));
+ recordPropagatedType2(node, node.target.propagatedType);
return null;
}
@@ -6874,8 +7541,8 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
staticType = _dynamicType;
}
recordStaticType(node, staticType);
- Type2 propagatedThenType = getPropagatedType(node.thenExpression);
- Type2 propagatedElseType = getPropagatedType(node.elseExpression);
+ Type2 propagatedThenType = node.thenExpression.propagatedType;
+ Type2 propagatedElseType = node.elseExpression.propagatedType;
if (propagatedThenType != null || propagatedElseType != null) {
if (propagatedThenType == null) {
propagatedThenType = staticThenType;
@@ -6969,7 +7636,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
if (staticPropagatedType != null && (staticStaticType == null || staticPropagatedType.isMoreSpecificThan(staticStaticType))) {
recordPropagatedType2(node, staticPropagatedType);
}
- ExecutableElement propagatedMethodElement = node.element;
+ ExecutableElement propagatedMethodElement = node.propagatedElement;
if (propagatedMethodElement != staticMethodElement) {
Type2 propagatedStaticType = computeStaticReturnType(propagatedMethodElement);
if (propagatedStaticType != null && (staticStaticType == null || propagatedStaticType.isMoreSpecificThan(staticStaticType)) && (staticPropagatedType == null || propagatedStaticType.isMoreSpecificThan(staticPropagatedType))) {
@@ -6993,7 +7660,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
ExecutableElement staticMethodElement = node.staticElement;
Type2 staticType = computeArgumentType(staticMethodElement);
recordStaticType(node, staticType);
- MethodElement propagatedMethodElement = node.element;
+ MethodElement propagatedMethodElement = node.propagatedElement;
if (propagatedMethodElement != staticMethodElement) {
Type2 propagatedType = computeArgumentType(propagatedMethodElement);
if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
@@ -7004,7 +7671,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
ExecutableElement staticMethodElement = node.staticElement;
Type2 staticType = computeStaticReturnType(staticMethodElement);
recordStaticType(node, staticType);
- MethodElement propagatedMethodElement = node.element;
+ MethodElement propagatedMethodElement = node.propagatedElement;
if (propagatedMethodElement != staticMethodElement) {
Type2 propagatedType = computeStaticReturnType(propagatedMethodElement);
if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
@@ -7095,9 +7762,9 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
NodeList<Expression> elements = node.elements;
int count = elements.length;
if (count > 0) {
- Type2 propagatedType = getBestType(elements[0]);
+ Type2 propagatedType = elements[0].bestType;
for (int i = 1; i < count; i++) {
- Type2 elementType = getBestType(elements[i]);
+ Type2 elementType = elements[i].bestType;
if (propagatedType != elementType) {
propagatedType = _dynamicType;
} else {
@@ -7150,11 +7817,11 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
int count = entries.length;
if (count > 0) {
MapLiteralEntry entry = entries[0];
- Type2 propagatedKeyType = getBestType(entry.key);
- Type2 propagatedValueType = getBestType(entry.value);
+ Type2 propagatedKeyType = entry.key.bestType;
+ Type2 propagatedValueType = entry.value.bestType;
for (int i = 1; i < count; i++) {
entry = entries[i];
- Type2 elementKeyType = getBestType(entry.key);
+ Type2 elementKeyType = entry.key.bestType;
if (propagatedKeyType != elementKeyType) {
propagatedKeyType = _dynamicType;
} else {
@@ -7163,7 +7830,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
propagatedKeyType = _dynamicType;
}
}
- Type2 elementValueType = getBestType(entry.value);
+ Type2 elementValueType = entry.value.bestType;
if (propagatedValueType != elementValueType) {
propagatedValueType = _dynamicType;
} else {
@@ -7239,7 +7906,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
String methodName = methodNameNode.name;
if (methodName == "then") {
Expression target = node.realTarget;
- Type2 targetType = target == null ? null : getBestType(target);
+ Type2 targetType = target == null ? null : target.bestType;
if (isAsyncFutureType(targetType)) {
NodeList<Expression> arguments = node.argumentList.arguments;
if (arguments.length == 1) {
@@ -7266,7 +7933,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
if (methodName == "\$dom_createEvent") {
Expression target = node.realTarget;
if (target != null) {
- Type2 targetType = getBestType(target);
+ Type2 targetType = target.bestType;
if (targetType is InterfaceType && (targetType.name == "HtmlDocument" || targetType.name == "Document")) {
LibraryElement library = targetType.element.library;
if (isHtmlLibrary(library)) {
@@ -7291,7 +7958,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
}
}
} else {
- Type2 targetType = getBestType(target);
+ Type2 targetType = target.bestType;
if (targetType is InterfaceType && (targetType.name == "HtmlDocument" || targetType.name == "Document")) {
LibraryElement library = targetType.element.library;
if (isHtmlLibrary(library)) {
@@ -7304,7 +7971,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
}
} else if (methodName == "\$dom_createElement") {
Expression target = node.realTarget;
- Type2 targetType = getBestType(target);
+ Type2 targetType = target.bestType;
if (targetType is InterfaceType && (targetType.name == "HtmlDocument" || targetType.name == "Document")) {
LibraryElement library = targetType.element.library;
if (isHtmlLibrary(library)) {
@@ -7337,7 +8004,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
Object visitNamedExpression(NamedExpression node) {
Expression expression = node.expression;
recordStaticType(node, getStaticType(expression));
- recordPropagatedType2(node, getPropagatedType(expression));
+ recordPropagatedType2(node, expression.propagatedType);
return null;
}
@@ -7352,7 +8019,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
Object visitParenthesizedExpression(ParenthesizedExpression node) {
Expression expression = node.expression;
recordStaticType(node, getStaticType(expression));
- recordPropagatedType2(node, getPropagatedType(expression));
+ recordPropagatedType2(node, expression.propagatedType);
return null;
}
@@ -7393,7 +8060,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
}
}
recordStaticType(node, staticType);
- recordPropagatedType2(node, getPropagatedType(operand));
+ recordPropagatedType2(node, operand.propagatedType);
return null;
}
@@ -7452,7 +8119,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
}
}
recordStaticType(node, staticType);
- MethodElement propagatedMethodElement = node.element;
+ MethodElement propagatedMethodElement = node.propagatedElement;
if (propagatedMethodElement != staticMethodElement) {
Type2 propagatedType = computeStaticReturnType(propagatedMethodElement);
if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
@@ -7635,6 +8302,10 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
}
return null;
}
+ Object visitSymbolLiteral(SymbolLiteral node) {
+ recordStaticType(node, _typeProvider.symbolType);
+ return null;
+ }
/**
* The Dart Language Specification, 12.10: <blockquote>The static type of `this` is the
@@ -7660,7 +8331,7 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
Object visitVariableDeclaration(VariableDeclaration node) {
Expression initializer = node.initializer;
if (initializer != null) {
- Type2 rightType = getBestType(initializer);
+ Type2 rightType = initializer.bestType;
SimpleIdentifier name = node.name;
recordPropagatedType2(name, rightType);
VariableElement element = name.element as VariableElement;
@@ -7711,11 +8382,11 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
Type2 computePropagatedReturnType2(FunctionBody body) {
if (body is ExpressionFunctionBody) {
ExpressionFunctionBody expressionBody = body as ExpressionFunctionBody;
- return getBestType(expressionBody.expression);
+ return expressionBody.expression.bestType;
}
if (body is BlockFunctionBody) {
List<Type2> result = [null];
- body.accept(new GeneralizingASTVisitor_8(this, result));
+ body.accept(new GeneralizingASTVisitor_8(result));
return result[0];
}
return null;
@@ -7799,24 +8470,6 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
}
/**
- * Return the propagated type of the given expression if it is available, or the static type if
- * there is no propagated type.
- *
- * @param expression the expression whose type is to be returned
- * @return the propagated or static type of the given expression
- */
- Type2 getBestType(Expression expression) {
- Type2 type = expression.propagatedType;
- if (type == null) {
- type = expression.staticType;
- if (type == null) {
- return _dynamicType;
- }
- }
- return type;
- }
-
- /**
* If the given element name can be mapped to the name of a class defined within the given
* library, return the type specified by the argument.
*
@@ -7904,20 +8557,9 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
* @param library the library in which the specified type would be defined
* @param argumentList the list of arguments from which a type is to be extracted
* @param nameMap an optional map used to map the element name to a type name
- * @return the type specified by the first argument in the argument list
- */
- Type2 getFirstArgumentAsType2(LibraryElement library, ArgumentList argumentList, Map<String, String> nameMap) => getElementNameAsType(library, getFirstArgumentAsString(argumentList), nameMap);
-
- /**
- * Return the propagated type of the given expression.
- *
- * @param expression the expression whose type is to be returned
- * @return the propagated type of the given expression
+ * @return the type specified by the first argument in the argument list
*/
- Type2 getPropagatedType(Expression expression) {
- Type2 type = expression.propagatedType;
- return type;
- }
+ Type2 getFirstArgumentAsType2(LibraryElement library, ArgumentList argumentList, Map<String, String> nameMap) => getElementNameAsType(library, getFirstArgumentAsString(argumentList), nameMap);
/**
* Return the static type of the given expression.
@@ -8105,15 +8747,14 @@ class StaticTypeAnalyzer extends SimpleASTVisitor<Object> {
set thisType_J2DAccessor(__v) => _thisType = __v;
}
class GeneralizingASTVisitor_8 extends GeneralizingASTVisitor<Object> {
- final StaticTypeAnalyzer StaticTypeAnalyzer_this;
List<Type2> result;
- GeneralizingASTVisitor_8(this.StaticTypeAnalyzer_this, this.result) : super();
+ GeneralizingASTVisitor_8(this.result) : super();
Object visitExpression(Expression node) => null;
Object visitReturnStatement(ReturnStatement node) {
Type2 type;
Expression expression = node.expression;
if (expression != null) {
- type = StaticTypeAnalyzer_this.getBestType(expression);
+ type = expression.bestType;
} else {
type = BottomTypeImpl.instance;
}
@@ -8638,7 +9279,7 @@ class TypeResolverVisitor extends ScopedVisitor {
InterfaceType superclassType = null;
ExtendsClause extendsClause = node.extendsClause;
if (extendsClause != null) {
- ErrorCode errorCode = node.withClause == null ? CompileTimeErrorCode.EXTENDS_NON_CLASS : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS;
+ ErrorCode errorCode = (node.withClause == null ? CompileTimeErrorCode.EXTENDS_NON_CLASS : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS) as ErrorCode;
superclassType = resolveType(extendsClause.superclass, errorCode, errorCode);
if (superclassType != typeProvider.objectType) {
classElement.validMixin = false;
@@ -8826,6 +9467,7 @@ class TypeResolverVisitor extends ScopedVisitor {
} else {
reportError(StaticWarningCode.NEW_WITH_NON_TYPE, prefixedIdentifier.identifier, [prefixedIdentifier.identifier.name]);
}
+ setElement(prefix, element);
return null;
} else if (element != null) {
name.name = prefixedIdentifier.identifier;
@@ -8874,7 +9516,11 @@ class TypeResolverVisitor extends ScopedVisitor {
elementValid = false;
}
if (!elementValid) {
- setElement(typeName, _dynamicType.element);
+ if (element is MultiplyDefinedElement) {
+ setElement(typeName, element);
+ } else {
+ setElement(typeName, _dynamicType.element);
+ }
typeName.staticType = _dynamicType;
node.type = _dynamicType;
return null;
@@ -9369,12 +10015,12 @@ class TypeResolverVisitor extends ScopedVisitor {
List<ParameterElement> parameters = getElements(parameterList);
FunctionTypeAliasElementImpl aliasElement = new FunctionTypeAliasElementImpl(null);
aliasElement.synthetic = true;
- aliasElement.parameters = parameters;
+ aliasElement.shareParameters(parameters);
aliasElement.returnType = computeReturnType(returnType2);
FunctionTypeImpl type = new FunctionTypeImpl.con2(aliasElement);
ClassElement definingClass = element.getAncestor(ClassElement);
if (definingClass != null) {
- aliasElement.typeVariables = definingClass.typeVariables;
+ aliasElement.shareTypeVariables(definingClass.typeVariables);
type.typeArguments = definingClass.type.typeArguments;
} else {
FunctionTypeAliasElement alias = element.getAncestor(FunctionTypeAliasElement);
@@ -9654,51 +10300,6 @@ class LabelScope {
class LibraryImportScope extends Scope {
/**
- * @return `true` if the given [Identifier] is the part of type annotation.
- */
- static bool isTypeAnnotation(Identifier identifier) {
- ASTNode parent = identifier.parent;
- if (parent is TypeName) {
- ASTNode parent2 = parent.parent;
- if (parent2 is FunctionDeclaration) {
- FunctionDeclaration decl = parent2 as FunctionDeclaration;
- return identical(decl.returnType, parent);
- }
- if (parent2 is FunctionTypeAlias) {
- FunctionTypeAlias decl = parent2 as FunctionTypeAlias;
- return identical(decl.returnType, parent);
- }
- if (parent2 is MethodDeclaration) {
- MethodDeclaration decl = parent2 as MethodDeclaration;
- return identical(decl.returnType, parent);
- }
- if (parent2 is VariableDeclarationList) {
- VariableDeclarationList decl = parent2 as VariableDeclarationList;
- return identical(decl.type, parent);
- }
- if (parent2 is SimpleFormalParameter) {
- SimpleFormalParameter decl = parent2 as SimpleFormalParameter;
- return identical(decl.type, parent);
- }
- if (parent2 is TypeParameter) {
- TypeParameter decl = parent2 as TypeParameter;
- return identical(decl.bound, parent);
- }
- if (parent2 is TypeArgumentList) {
- ASTNode parent3 = parent2.parent;
- if (parent3 is TypeName) {
- TypeName typeName = parent3 as TypeName;
- if (identical((typeName).typeArguments, parent2)) {
- return isTypeAnnotation(typeName.name);
- }
- }
- }
- return false;
- }
- return false;
- }
-
- /**
* The element representing the library in which this scope is enclosed.
*/
LibraryElement _definingLibrary;
@@ -9760,8 +10361,7 @@ class LibraryImportScope extends Scope {
if (enclosingLibrary != null) {
libName2 = enclosingLibrary.definingCompilationUnit.displayName;
}
- ErrorCode errorCode = isTypeAnnotation(identifier) ? StaticWarningCode.AMBIGUOUS_IMPORT : CompileTimeErrorCode.AMBIGUOUS_IMPORT;
- _errorListener.onError(new AnalysisError.con2(source, identifier.offset, identifier.length, errorCode, [foundEltName, libName1, libName2]));
+ _errorListener.onError(new AnalysisError.con2(source, identifier.offset, identifier.length, StaticWarningCode.AMBIGUOUS_IMPORT, [foundEltName, libName1, libName2]));
return foundElement;
}
if (foundElement != null) {
@@ -10168,474 +10768,137 @@ abstract class Scope {
* in this scope, then an error will be generated and the original element will continue to be
* mapped to the name. If there is an element with the given name in an enclosing scope, then a
* warning will be generated but the given element will hide the inherited element.
- *
- * @param element the element to be added to this scope
- */
- void define(Element element) {
- String name = getName(element);
- if (name != null && !name.isEmpty) {
- if (_definedNames.containsKey(name)) {
- errorListener.onError(getErrorForDuplicate(_definedNames[name], element));
- } else {
- _definedNames[name] = element;
- }
- }
- }
-
- /**
- * Return the element with which the given identifier is associated, or `null` if the name
- * is not defined within this scope.
- *
- * @param identifier the identifier associated with the element to be returned
- * @param referencingLibrary the library that contains the reference to the name, used to
- * implement library-level privacy
- * @return the element with which the given identifier is associated
- */
- Element lookup(Identifier identifier, LibraryElement referencingLibrary) => lookup3(identifier, identifier.name, referencingLibrary);
-
- /**
- * Add the given element to this scope without checking for duplication or hiding.
- *
- * @param element the element to be added to this scope
- */
- void defineWithoutChecking(Element element) {
- _definedNames[getName(element)] = element;
- }
-
- /**
- * Add the given element to this scope without checking for duplication or hiding.
- *
- * @param name the name of the element to be added
- * @param element the element to be added to this scope
- */
- void defineWithoutChecking2(String name, Element element) {
- _definedNames[name] = element;
- }
-
- /**
- * Return the element representing the library in which this scope is enclosed.
- *
- * @return the element representing the library in which this scope is enclosed
- */
- LibraryElement get definingLibrary;
-
- /**
- * Return the error code to be used when reporting that a name being defined locally conflicts
- * with another element of the same name in the local scope.
- *
- * @param existing the first element to be declared with the conflicting name
- * @param duplicate another element declared with the conflicting name
- * @return the error code used to report duplicate names within a scope
- */
- AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
- Source source = duplicate.source;
- if (source == null) {
- source = source;
- }
- return new AnalysisError.con2(source, duplicate.nameOffset, duplicate.displayName.length, CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]);
- }
-
- /**
- * Return the listener that is to be informed when an error is encountered.
- *
- * @return the listener that is to be informed when an error is encountered
- */
- AnalysisErrorListener get errorListener;
-
- /**
- * Return the source object representing the compilation unit with which errors related to this
- * scope should be associated.
- *
- * @return the source object with which errors should be associated
- */
- Source get source => definingLibrary.definingCompilationUnit.source;
-
- /**
- * Return the element with which the given name is associated, or `null` if the name is not
- * defined within this scope. This method only returns elements that are directly defined within
- * this scope, not elements that are defined in an enclosing scope.
- *
- * @param name the name associated with the element to be returned
- * @param referencingLibrary the library that contains the reference to the name, used to
- * implement library-level privacy
- * @return the element with which the given name is associated
- */
- Element localLookup(String name, LibraryElement referencingLibrary) => _definedNames[name];
-
- /**
- * Return the element with which the given name is associated, or `null` if the name is not
- * defined within this scope.
- *
- * @param identifier the identifier node to lookup element for, used to report correct kind of a
- * problem and associate problem with
- * @param name the name associated with the element to be returned
- * @param referencingLibrary the library that contains the reference to the name, used to
- * implement library-level privacy
- * @return the element with which the given name is associated
- */
- Element lookup3(Identifier identifier, String name, LibraryElement referencingLibrary);
-
- /**
- * Return the name that will be used to look up the given element.
- *
- * @param element the element whose look-up name is to be returned
- * @return the name that will be used to look up the given element
- */
- String getName(Element element) {
- if (element is MethodElement) {
- MethodElement method = element as MethodElement;
- if (method.name == "-" && method.parameters.length == 0) {
- return UNARY_MINUS;
- }
- }
- return element.name;
- }
-}
-/**
- * Instances of the class `ConstantVerifier` traverse an AST structure looking for additional
- * errors and warnings not covered by the parser and resolver. In particular, it looks for errors
- * and warnings related to constant expressions.
- *
- * @coverage dart.engine.resolver
- */
-class ConstantVerifier extends RecursiveASTVisitor<Object> {
-
- /**
- * The error reporter by which errors will be reported.
- */
- ErrorReporter _errorReporter;
-
- /**
- * The type representing the type 'bool'.
- */
- InterfaceType _boolType;
-
- /**
- * The type representing the type 'int'.
- */
- InterfaceType _intType;
-
- /**
- * The type representing the type 'num'.
- */
- InterfaceType _numType;
-
- /**
- * The type representing the type 'string'.
- */
- InterfaceType _stringType;
-
- /**
- * Initialize a newly created constant verifier.
- *
- * @param errorReporter the error reporter by which errors will be reported
- */
- ConstantVerifier(ErrorReporter errorReporter, TypeProvider typeProvider) {
- this._errorReporter = errorReporter;
- this._boolType = typeProvider.boolType;
- this._intType = typeProvider.intType;
- this._numType = typeProvider.numType;
- this._stringType = typeProvider.stringType;
- }
- Object visitAnnotation(Annotation node) {
- super.visitAnnotation(node);
- Element element = node.element;
- if (element is ConstructorElement) {
- ConstructorElement constructorElement = element as ConstructorElement;
- if (!constructorElement.isConst) {
- _errorReporter.reportError2(CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, node, []);
- return null;
- }
- ArgumentList argumentList = node.arguments;
- if (argumentList == null) {
- _errorReporter.reportError2(CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS, node, []);
- return null;
- }
- validateConstantArguments(argumentList);
- }
- return null;
- }
- Object visitConstructorDeclaration(ConstructorDeclaration node) {
- if (node.constKeyword != null) {
- validateInitializers(node);
- }
- validateDefaultValues(node.parameters);
- return super.visitConstructorDeclaration(node);
- }
- Object visitFunctionExpression(FunctionExpression node) {
- super.visitFunctionExpression(node);
- validateDefaultValues(node.parameters);
- return null;
- }
- Object visitInstanceCreationExpression(InstanceCreationExpression node) {
- validateConstantArguments2(node);
- return super.visitInstanceCreationExpression(node);
- }
- Object visitListLiteral(ListLiteral node) {
- super.visitListLiteral(node);
- if (node.modifier != null) {
- for (Expression element in node.elements) {
- validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT);
- }
- }
- return null;
- }
- Object visitMapLiteral(MapLiteral node) {
- super.visitMapLiteral(node);
- bool isConst = node.modifier != null;
- bool reportEqualKeys = true;
- Set<Object> keys = new Set<Object>();
- List<Expression> invalidKeys = new List<Expression>();
- for (MapLiteralEntry entry in node.entries) {
- Expression key = entry.key;
- if (isConst) {
- EvaluationResultImpl result = validate(key, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY);
- validate(entry.value, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE);
- if (result is ValidResult) {
- Object value = ((result as ValidResult)).value;
- if (keys.contains(value)) {
- invalidKeys.add(key);
- } else {
- javaSetAdd(keys, value);
- }
- }
+ *
+ * @param element the element to be added to this scope
+ */
+ void define(Element element) {
+ String name = getName(element);
+ if (name != null && !name.isEmpty) {
+ if (_definedNames.containsKey(name)) {
+ errorListener.onError(getErrorForDuplicate(_definedNames[name], element));
} else {
- EvaluationResultImpl result = key.accept(new ConstantVisitor());
- if (result is ValidResult) {
- Object value = ((result as ValidResult)).value;
- if (keys.contains(value)) {
- invalidKeys.add(key);
- } else {
- javaSetAdd(keys, value);
- }
- } else {
- reportEqualKeys = false;
- }
- }
- }
- if (reportEqualKeys) {
- for (Expression key in invalidKeys) {
- _errorReporter.reportError2(StaticWarningCode.EQUAL_KEYS_IN_MAP, key, []);
- }
- }
- return null;
- }
- Object visitMethodDeclaration(MethodDeclaration node) {
- super.visitMethodDeclaration(node);
- validateDefaultValues(node.parameters);
- return null;
- }
- Object visitSwitchCase(SwitchCase node) {
- super.visitSwitchCase(node);
- validate(node.expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION);
- return null;
- }
- Object visitVariableDeclaration(VariableDeclaration node) {
- super.visitVariableDeclaration(node);
- Expression initializer = node.initializer;
- if (initializer != null && node.isConst) {
- VariableElementImpl element = node.element as VariableElementImpl;
- EvaluationResultImpl result = element.evaluationResult;
- if (result == null) {
- result = validate(initializer, CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE);
- element.evaluationResult = result;
- } else if (result is ErrorResult) {
- reportErrors(result, CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE);
+ _definedNames[name] = element;
}
}
- return null;
}
/**
- * Return `true` if the given value is the result of evaluating an expression whose value is
- * a valid key in a const map literal. Keys in const map literals must be either a string, number,
- * boolean, list, map, or null.
+ * Return the element with which the given identifier is associated, or `null` if the name
+ * is not defined within this scope.
*
- * @param value
- * @return `true` if the given value is a valid key in a const map literal
+ * @param identifier the identifier associated with the element to be returned
+ * @param referencingLibrary the library that contains the reference to the name, used to
+ * implement library-level privacy
+ * @return the element with which the given identifier is associated
*/
- bool isValidConstMapKey(Object value) => true;
+ Element lookup(Identifier identifier, LibraryElement referencingLibrary) => lookup3(identifier, identifier.name, referencingLibrary);
/**
- * If the given result represents one or more errors, report those errors. Except for special
- * cases, use the given error code rather than the one reported in the error.
+ * Add the given element to this scope without checking for duplication or hiding.
*
- * @param result the result containing any errors that need to be reported
- * @param errorCode the error code to be used if the result represents an error
+ * @param element the element to be added to this scope
*/
- void reportErrors(EvaluationResultImpl result, ErrorCode errorCode2) {
- if (result is ErrorResult) {
- for (ErrorResult_ErrorData data in ((result as ErrorResult)).errorData) {
- ErrorCode dataErrorCode = data.errorCode;
- if (identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM)) {
- _errorReporter.reportError2(dataErrorCode, data.node, []);
- } else {
- _errorReporter.reportError2(errorCode2, data.node, []);
- }
- }
- }
+ void defineWithoutChecking(Element element) {
+ _definedNames[getName(element)] = element;
}
/**
- * Validate that the given expression is a compile time constant. Return the value of the compile
- * time constant, or `null` if the expression is not a compile time constant.
+ * Add the given element to this scope without checking for duplication or hiding.
*
- * @param expression the expression to be validated
- * @param errorCode the error code to be used if the expression is not a compile time constant
- * @return the value of the compile time constant
+ * @param name the name of the element to be added
+ * @param element the element to be added to this scope
*/
- EvaluationResultImpl validate(Expression expression, ErrorCode errorCode) {
- EvaluationResultImpl result = expression.accept(new ConstantVisitor());
- reportErrors(result, errorCode);
- return result;
+ void defineWithoutChecking2(String name, Element element) {
+ _definedNames[name] = element;
}
/**
- * Validate that if the passed arguments are constant expressions.
+ * Return the element representing the library in which this scope is enclosed.
*
- * @param argumentList the argument list to evaluate
+ * @return the element representing the library in which this scope is enclosed
*/
- void validateConstantArguments(ArgumentList argumentList) {
- for (Expression argument in argumentList.arguments) {
- if (argument is NamedExpression) {
- argument = ((argument as NamedExpression)).expression;
- }
- validate(argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT);
- }
- }
+ LibraryElement get definingLibrary;
/**
- * Validate that if the passed instance creation is 'const' then all its arguments are constant
- * expressions.
+ * Return the error code to be used when reporting that a name being defined locally conflicts
+ * with another element of the same name in the local scope.
*
- * @param node the instance creation evaluate
+ * @param existing the first element to be declared with the conflicting name
+ * @param duplicate another element declared with the conflicting name
+ * @return the error code used to report duplicate names within a scope
*/
- void validateConstantArguments2(InstanceCreationExpression node) {
- if (!node.isConst) {
- return;
- }
- ArgumentList argumentList = node.argumentList;
- if (argumentList == null) {
- return;
+ AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
+ Source source = duplicate.source;
+ if (source == null) {
+ source = source;
}
- validateConstantArguments(argumentList);
+ return new AnalysisError.con2(source, duplicate.nameOffset, duplicate.displayName.length, CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]);
}
/**
- * Validate that the default value associated with each of the parameters in the given list is a
- * compile time constant.
+ * Return the listener that is to be informed when an error is encountered.
*
- * @param parameters the list of parameters to be validated
+ * @return the listener that is to be informed when an error is encountered
*/
- void validateDefaultValues(FormalParameterList parameters2) {
- if (parameters2 == null) {
- return;
- }
- for (FormalParameter parameter in parameters2.parameters) {
- if (parameter is DefaultFormalParameter) {
- DefaultFormalParameter defaultParameter = parameter as DefaultFormalParameter;
- Expression defaultValue = defaultParameter.defaultValue;
- if (defaultValue != null) {
- EvaluationResultImpl result = validate(defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE);
- VariableElementImpl element = parameter.element as VariableElementImpl;
- element.evaluationResult = result;
- }
- }
- }
- }
+ AnalysisErrorListener get errorListener;
/**
- * Validates that the given expression is a compile time constant.
+ * Return the source object representing the compilation unit with which errors related to this
+ * scope should be associated.
*
- * @param parameterElements the elements of parameters of constant constructor, they are
- * considered as a valid potentially constant expressions
- * @param expression the expression to validate
+ * @return the source object with which errors should be associated
*/
- void validateInitializerExpression(List<ParameterElement> parameterElements, Expression expression) {
- EvaluationResultImpl result = expression.accept(new ConstantVisitor_10(this, parameterElements));
- reportErrors(result, CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER);
- }
+ Source get source => definingLibrary.definingCompilationUnit.source;
/**
- * Validates that all of the arguments of a constructor initializer are compile time constants.
+ * Return the element with which the given name is associated, or `null` if the name is not
+ * defined within this scope. This method only returns elements that are directly defined within
+ * this scope, not elements that are defined in an enclosing scope.
*
- * @param parameterElements the elements of parameters of constant constructor, they are
- * considered as a valid potentially constant expressions
- * @param argumentList the argument list to validate
+ * @param name the name associated with the element to be returned
+ * @param referencingLibrary the library that contains the reference to the name, used to
+ * implement library-level privacy
+ * @return the element with which the given name is associated
*/
- void validateInitializerInvocationArguments(List<ParameterElement> parameterElements, ArgumentList argumentList) {
- if (argumentList == null) {
- return;
- }
- for (Expression argument in argumentList.arguments) {
- validateInitializerExpression(parameterElements, argument);
- }
- }
+ Element localLookup(String name, LibraryElement referencingLibrary) => _definedNames[name];
/**
- * Validates that the expressions of the given initializers (of a constant constructor) are all
- * compile time constants.
+ * Return the element with which the given name is associated, or `null` if the name is not
+ * defined within this scope.
*
- * @param constructor the constant constructor declaration to validate
+ * @param identifier the identifier node to lookup element for, used to report correct kind of a
+ * problem and associate problem with
+ * @param name the name associated with the element to be returned
+ * @param referencingLibrary the library that contains the reference to the name, used to
+ * implement library-level privacy
+ * @return the element with which the given name is associated
*/
- void validateInitializers(ConstructorDeclaration constructor) {
- List<ParameterElement> parameterElements = constructor.parameters.elements;
- NodeList<ConstructorInitializer> initializers = constructor.initializers;
- for (ConstructorInitializer initializer in initializers) {
- if (initializer is ConstructorFieldInitializer) {
- ConstructorFieldInitializer fieldInitializer = initializer as ConstructorFieldInitializer;
- validateInitializerExpression(parameterElements, fieldInitializer.expression);
- }
- if (initializer is RedirectingConstructorInvocation) {
- RedirectingConstructorInvocation invocation = initializer as RedirectingConstructorInvocation;
- validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
- }
- if (initializer is SuperConstructorInvocation) {
- SuperConstructorInvocation invocation = initializer as SuperConstructorInvocation;
- validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
- }
- }
- }
-}
-class ConstantVisitor_10 extends ConstantVisitor {
- final ConstantVerifier ConstantVerifier_this;
- List<ParameterElement> parameterElements;
- ConstantVisitor_10(this.ConstantVerifier_this, this.parameterElements) : super();
- EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) {
- Element element = node.element;
- for (ParameterElement parameterElement in parameterElements) {
- if (identical(parameterElement, element) && parameterElement != null) {
- Type2 type = parameterElement.type;
- if (type != null) {
- if (type.isDynamic) {
- return ValidResult.RESULT_DYNAMIC;
- }
- if (type.isSubtypeOf(ConstantVerifier_this._boolType)) {
- return ValidResult.RESULT_BOOL;
- }
- if (type.isSubtypeOf(ConstantVerifier_this._intType)) {
- return ValidResult.RESULT_INT;
- }
- if (type.isSubtypeOf(ConstantVerifier_this._numType)) {
- return ValidResult.RESULT_NUM;
- }
- if (type.isSubtypeOf(ConstantVerifier_this._stringType)) {
- return ValidResult.RESULT_STRING;
- }
- }
- return ValidResult.RESULT_OBJECT;
+ Element lookup3(Identifier identifier, String name, LibraryElement referencingLibrary);
+
+ /**
+ * Return the name that will be used to look up the given element.
+ *
+ * @param element the element whose look-up name is to be returned
+ * @return the name that will be used to look up the given element
+ */
+ String getName(Element element) {
+ if (element is MethodElement) {
+ MethodElement method = element as MethodElement;
+ if (method.name == "-" && method.parameters.length == 0) {
+ return UNARY_MINUS;
}
}
- return super.visitSimpleIdentifier(node);
+ return element.name;
}
}
/**
- * Instances of the class `DeadCodeVerifier` traverse an AST structure looking for cases of
- * [HintCode#DEAD_CODE].
+ * Instances of the class `ConstantVerifier` traverse an AST structure looking for additional
+ * errors and warnings not covered by the parser and resolver. In particular, it looks for errors
+ * and warnings related to constant expressions.
*
* @coverage dart.engine.resolver
*/
-class DeadCodeVerifier extends RecursiveASTVisitor<Object> {
+class ConstantVerifier extends RecursiveASTVisitor<Object> {
/**
* The error reporter by which errors will be reported.
@@ -10643,194 +10906,328 @@ class DeadCodeVerifier extends RecursiveASTVisitor<Object> {
ErrorReporter _errorReporter;
/**
- * Create a new instance of the [DeadCodeVerifier].
- *
- * @param errorReporter the error reporter
+ * The type representing the type 'bool'.
*/
- DeadCodeVerifier(ErrorReporter errorReporter) {
- this._errorReporter = errorReporter;
- }
- Object visitBinaryExpression(BinaryExpression node) {
- sc.Token operator = node.operator;
- bool isAmpAmp = identical(operator.type, sc.TokenType.AMPERSAND_AMPERSAND);
- bool isBarBar = identical(operator.type, sc.TokenType.BAR_BAR);
- if (isAmpAmp || isBarBar) {
- Expression lhsCondition = node.leftOperand;
- ValidResult lhsResult = getConstantBooleanValue(lhsCondition);
- if (lhsResult != null) {
- if (identical(lhsResult, ValidResult.RESULT_TRUE) && isBarBar) {
- _errorReporter.reportError2(HintCode.DEAD_CODE, node.rightOperand, []);
- safelyVisit(lhsCondition);
- return null;
- } else if (identical(lhsResult, ValidResult.RESULT_FALSE) && isAmpAmp) {
- _errorReporter.reportError2(HintCode.DEAD_CODE, node.rightOperand, []);
- safelyVisit(lhsCondition);
- return null;
- }
- }
- }
- return super.visitBinaryExpression(node);
- }
+ InterfaceType _boolType;
/**
- * For each [Block], this method reports and error on all statements between the end of the
- * block and the first return statement (assuming there it is not at the end of the block.)
+ * The type representing the type 'int'.
+ */
+ InterfaceType _intType;
+
+ /**
+ * The type representing the type 'num'.
+ */
+ InterfaceType _numType;
+
+ /**
+ * The type representing the type 'string'.
+ */
+ InterfaceType _stringType;
+
+ /**
+ * Initialize a newly created constant verifier.
*
- * @param node the block to evaluate
+ * @param errorReporter the error reporter by which errors will be reported
*/
- Object visitBlock(Block node) {
- NodeList<Statement> statements = node.statements;
- int size = statements.length;
- for (int i = 0; i < size; i++) {
- Statement currentStatement = statements[i];
- safelyVisit(currentStatement);
- if (currentStatement is ReturnStatement && i != size - 1) {
- Statement nextStatement = statements[i + 1];
- Statement lastStatement = statements[size - 1];
- int offset = nextStatement.offset;
- int length = lastStatement.end - offset;
- _errorReporter.reportError3(HintCode.DEAD_CODE, offset, length, []);
+ ConstantVerifier(ErrorReporter errorReporter, TypeProvider typeProvider) {
+ this._errorReporter = errorReporter;
+ this._boolType = typeProvider.boolType;
+ this._intType = typeProvider.intType;
+ this._numType = typeProvider.numType;
+ this._stringType = typeProvider.stringType;
+ }
+ Object visitAnnotation(Annotation node) {
+ super.visitAnnotation(node);
+ Element element = node.element;
+ if (element is ConstructorElement) {
+ ConstructorElement constructorElement = element as ConstructorElement;
+ if (!constructorElement.isConst) {
+ _errorReporter.reportError2(CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, node, []);
+ return null;
+ }
+ ArgumentList argumentList = node.arguments;
+ if (argumentList == null) {
+ _errorReporter.reportError2(CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS, node, []);
return null;
}
+ validateConstantArguments(argumentList);
}
return null;
}
- Object visitConditionalExpression(ConditionalExpression node) {
- Expression conditionExpression = node.condition;
- ValidResult result = getConstantBooleanValue(conditionExpression);
- if (result != null) {
- if (identical(result, ValidResult.RESULT_TRUE)) {
- _errorReporter.reportError2(HintCode.DEAD_CODE, node.elseExpression, []);
- safelyVisit(node.thenExpression);
- return null;
- } else {
- _errorReporter.reportError2(HintCode.DEAD_CODE, node.thenExpression, []);
- safelyVisit(node.elseExpression);
- return null;
- }
+ Object visitConstructorDeclaration(ConstructorDeclaration node) {
+ if (node.constKeyword != null) {
+ validateInitializers(node);
}
- return super.visitConditionalExpression(node);
+ validateDefaultValues(node.parameters);
+ return super.visitConstructorDeclaration(node);
}
- Object visitIfStatement(IfStatement node) {
- Expression conditionExpression = node.condition;
- ValidResult result = getConstantBooleanValue(conditionExpression);
- if (result != null) {
- if (identical(result, ValidResult.RESULT_TRUE)) {
- Statement elseStatement = node.elseStatement;
- if (elseStatement != null) {
- _errorReporter.reportError2(HintCode.DEAD_CODE, elseStatement, []);
- safelyVisit(node.thenStatement);
- return null;
- }
- } else {
- _errorReporter.reportError2(HintCode.DEAD_CODE, node.thenStatement, []);
- safelyVisit(node.elseStatement);
- return null;
+ Object visitFunctionExpression(FunctionExpression node) {
+ super.visitFunctionExpression(node);
+ validateDefaultValues(node.parameters);
+ return null;
+ }
+ Object visitInstanceCreationExpression(InstanceCreationExpression node) {
+ validateConstantArguments2(node);
+ return super.visitInstanceCreationExpression(node);
+ }
+ Object visitListLiteral(ListLiteral node) {
+ super.visitListLiteral(node);
+ if (node.modifier != null) {
+ for (Expression element in node.elements) {
+ validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT);
}
}
- return super.visitIfStatement(node);
+ return null;
}
- Object visitTryStatement(TryStatement node) {
- safelyVisit(node.body);
- safelyVisit(node.finallyClause);
- NodeList<CatchClause> catchClauses = node.catchClauses;
- int numOfCatchClauses = catchClauses.length;
- List<Type2> visitedTypes = new List<Type2>();
- for (int i = 0; i < numOfCatchClauses; i++) {
- CatchClause catchClause = catchClauses[i];
- if (catchClause.onKeyword != null) {
- TypeName typeName = catchClause.exceptionType;
- if (typeName != null && typeName.type != null) {
- Type2 currentType = typeName.type;
- if (currentType.isObject) {
- safelyVisit(catchClause);
- if (i + 1 != numOfCatchClauses) {
- CatchClause nextCatchClause = catchClauses[i + 1];
- CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
- int offset = nextCatchClause.offset;
- int length = lastCatchClause.end - offset;
- _errorReporter.reportError3(HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length, []);
- return null;
- }
- }
- for (Type2 type in visitedTypes) {
- if (currentType.isSubtypeOf(type)) {
- CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
- int offset = catchClause.offset;
- int length = lastCatchClause.end - offset;
- _errorReporter.reportError3(HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, offset, length, [currentType.displayName, type.displayName]);
- return null;
- }
+ Object visitMapLiteral(MapLiteral node) {
+ super.visitMapLiteral(node);
+ bool isConst = node.modifier != null;
+ bool reportEqualKeys = true;
+ Set<Object> keys = new Set<Object>();
+ List<Expression> invalidKeys = new List<Expression>();
+ for (MapLiteralEntry entry in node.entries) {
+ Expression key = entry.key;
+ if (isConst) {
+ EvaluationResultImpl result = validate(key, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY);
+ validate(entry.value, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE);
+ if (result is ValidResult) {
+ Object value = ((result as ValidResult)).value;
+ if (keys.contains(value)) {
+ invalidKeys.add(key);
+ } else {
+ javaSetAdd(keys, value);
}
- visitedTypes.add(currentType);
}
- safelyVisit(catchClause);
} else {
- safelyVisit(catchClause);
- if (i + 1 != numOfCatchClauses) {
- CatchClause nextCatchClause = catchClauses[i + 1];
- CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
- int offset = nextCatchClause.offset;
- int length = lastCatchClause.end - offset;
- _errorReporter.reportError3(HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length, []);
- return null;
+ EvaluationResultImpl result = key.accept(new ConstantVisitor());
+ if (result is ValidResult) {
+ Object value = ((result as ValidResult)).value;
+ if (keys.contains(value)) {
+ invalidKeys.add(key);
+ } else {
+ javaSetAdd(keys, value);
+ }
+ } else {
+ reportEqualKeys = false;
+ }
+ }
+ }
+ if (reportEqualKeys) {
+ for (Expression key in invalidKeys) {
+ _errorReporter.reportError2(StaticWarningCode.EQUAL_KEYS_IN_MAP, key, []);
+ }
+ }
+ return null;
+ }
+ Object visitMethodDeclaration(MethodDeclaration node) {
+ super.visitMethodDeclaration(node);
+ validateDefaultValues(node.parameters);
+ return null;
+ }
+ Object visitSwitchCase(SwitchCase node) {
+ super.visitSwitchCase(node);
+ validate(node.expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION);
+ return null;
+ }
+ Object visitVariableDeclaration(VariableDeclaration node) {
+ super.visitVariableDeclaration(node);
+ Expression initializer = node.initializer;
+ if (initializer != null && node.isConst) {
+ VariableElementImpl element = node.element as VariableElementImpl;
+ EvaluationResultImpl result = element.evaluationResult;
+ if (result == null) {
+ result = validate(initializer, CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE);
+ element.evaluationResult = result;
+ } else if (result is ErrorResult) {
+ reportErrors(result, CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return `true` if the given value is the result of evaluating an expression whose value is
+ * a valid key in a const map literal. Keys in const map literals must be either a string, number,
+ * boolean, list, map, or null.
+ *
+ * @param value
+ * @return `true` if the given value is a valid key in a const map literal
+ */
+ bool isValidConstMapKey(Object value) => true;
+
+ /**
+ * If the given result represents one or more errors, report those errors. Except for special
+ * cases, use the given error code rather than the one reported in the error.
+ *
+ * @param result the result containing any errors that need to be reported
+ * @param errorCode the error code to be used if the result represents an error
+ */
+ void reportErrors(EvaluationResultImpl result, ErrorCode errorCode2) {
+ if (result is ErrorResult) {
+ for (ErrorResult_ErrorData data in ((result as ErrorResult)).errorData) {
+ ErrorCode dataErrorCode = data.errorCode;
+ if (identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM)) {
+ _errorReporter.reportError2(dataErrorCode, data.node, []);
+ } else {
+ _errorReporter.reportError2(errorCode2, data.node, []);
}
}
}
- return null;
}
- Object visitWhileStatement(WhileStatement node) {
- Expression conditionExpression = node.condition;
- safelyVisit(conditionExpression);
- ValidResult result = getConstantBooleanValue(conditionExpression);
- if (result != null) {
- if (identical(result, ValidResult.RESULT_FALSE)) {
- _errorReporter.reportError2(HintCode.DEAD_CODE, node.body, []);
- return null;
+
+ /**
+ * Validate that the given expression is a compile time constant. Return the value of the compile
+ * time constant, or `null` if the expression is not a compile time constant.
+ *
+ * @param expression the expression to be validated
+ * @param errorCode the error code to be used if the expression is not a compile time constant
+ * @return the value of the compile time constant
+ */
+ EvaluationResultImpl validate(Expression expression, ErrorCode errorCode) {
+ EvaluationResultImpl result = expression.accept(new ConstantVisitor());
+ reportErrors(result, errorCode);
+ return result;
+ }
+
+ /**
+ * Validate that if the passed arguments are constant expressions.
+ *
+ * @param argumentList the argument list to evaluate
+ */
+ void validateConstantArguments(ArgumentList argumentList) {
+ for (Expression argument in argumentList.arguments) {
+ if (argument is NamedExpression) {
+ argument = ((argument as NamedExpression)).expression;
}
+ validate(argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT);
}
- safelyVisit(node.body);
- return null;
}
/**
- * Given some [Expression], this method returns [ValidResult#RESULT_TRUE] if it is
- * `true`, [ValidResult#RESULT_FALSE] if it is `false`, or `null` if the
- * expression is not a constant boolean value.
+ * Validate that if the passed instance creation is 'const' then all its arguments are constant
+ * expressions.
*
- * @param expression the expression to evaluate
- * @return [ValidResult#RESULT_TRUE] if it is `true`, [ValidResult#RESULT_FALSE]
- * if it is `false`, or `null` if the expression is not a constant boolean
- * value
+ * @param node the instance creation evaluate
*/
- ValidResult getConstantBooleanValue(Expression expression) {
- if (expression is BooleanLiteral) {
- if (((expression as BooleanLiteral)).value) {
- return ValidResult.RESULT_TRUE;
- } else {
- return ValidResult.RESULT_FALSE;
- }
- } else {
- EvaluationResultImpl result = expression.accept(new ConstantVisitor());
- if (identical(result, ValidResult.RESULT_TRUE)) {
- return ValidResult.RESULT_TRUE;
- } else if (identical(result, ValidResult.RESULT_FALSE)) {
- return ValidResult.RESULT_FALSE;
+ void validateConstantArguments2(InstanceCreationExpression node) {
+ if (!node.isConst) {
+ return;
+ }
+ ArgumentList argumentList = node.argumentList;
+ if (argumentList == null) {
+ return;
+ }
+ validateConstantArguments(argumentList);
+ }
+
+ /**
+ * Validate that the default value associated with each of the parameters in the given list is a
+ * compile time constant.
+ *
+ * @param parameters the list of parameters to be validated
+ */
+ void validateDefaultValues(FormalParameterList parameters2) {
+ if (parameters2 == null) {
+ return;
+ }
+ for (FormalParameter parameter in parameters2.parameters) {
+ if (parameter is DefaultFormalParameter) {
+ DefaultFormalParameter defaultParameter = parameter as DefaultFormalParameter;
+ Expression defaultValue = defaultParameter.defaultValue;
+ if (defaultValue != null) {
+ EvaluationResultImpl result = validate(defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE);
+ VariableElementImpl element = parameter.element as VariableElementImpl;
+ element.evaluationResult = result;
+ }
}
- return null;
}
}
/**
- * If the given node is not `null`, visit this instance of the dead code verifier.
+ * Validates that the given expression is a compile time constant.
*
- * @param node the node to be visited
+ * @param parameterElements the elements of parameters of constant constructor, they are
+ * considered as a valid potentially constant expressions
+ * @param expression the expression to validate
*/
- void safelyVisit(ASTNode node) {
- if (node != null) {
- node.accept(this);
+ void validateInitializerExpression(List<ParameterElement> parameterElements, Expression expression) {
+ EvaluationResultImpl result = expression.accept(new ConstantVisitor_10(this, parameterElements));
+ reportErrors(result, CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER);
+ }
+
+ /**
+ * Validates that all of the arguments of a constructor initializer are compile time constants.
+ *
+ * @param parameterElements the elements of parameters of constant constructor, they are
+ * considered as a valid potentially constant expressions
+ * @param argumentList the argument list to validate
+ */
+ void validateInitializerInvocationArguments(List<ParameterElement> parameterElements, ArgumentList argumentList) {
+ if (argumentList == null) {
+ return;
+ }
+ for (Expression argument in argumentList.arguments) {
+ validateInitializerExpression(parameterElements, argument);
}
}
+
+ /**
+ * Validates that the expressions of the given initializers (of a constant constructor) are all
+ * compile time constants.
+ *
+ * @param constructor the constant constructor declaration to validate
+ */
+ void validateInitializers(ConstructorDeclaration constructor) {
+ List<ParameterElement> parameterElements = constructor.parameters.parameterElements;
+ NodeList<ConstructorInitializer> initializers = constructor.initializers;
+ for (ConstructorInitializer initializer in initializers) {
+ if (initializer is ConstructorFieldInitializer) {
+ ConstructorFieldInitializer fieldInitializer = initializer as ConstructorFieldInitializer;
+ validateInitializerExpression(parameterElements, fieldInitializer.expression);
+ }
+ if (initializer is RedirectingConstructorInvocation) {
+ RedirectingConstructorInvocation invocation = initializer as RedirectingConstructorInvocation;
+ validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
+ }
+ if (initializer is SuperConstructorInvocation) {
+ SuperConstructorInvocation invocation = initializer as SuperConstructorInvocation;
+ validateInitializerInvocationArguments(parameterElements, invocation.argumentList);
+ }
+ }
+ }
+}
+class ConstantVisitor_10 extends ConstantVisitor {
+ final ConstantVerifier ConstantVerifier_this;
+ List<ParameterElement> parameterElements;
+ ConstantVisitor_10(this.ConstantVerifier_this, this.parameterElements) : super();
+ EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) {
+ Element element = node.element;
+ for (ParameterElement parameterElement in parameterElements) {
+ if (identical(parameterElement, element) && parameterElement != null) {
+ Type2 type = parameterElement.type;
+ if (type != null) {
+ if (type.isDynamic) {
+ return ValidResult.RESULT_DYNAMIC;
+ }
+ if (type.isSubtypeOf(ConstantVerifier_this._boolType)) {
+ return ValidResult.RESULT_BOOL;
+ }
+ if (type.isSubtypeOf(ConstantVerifier_this._intType)) {
+ return ValidResult.RESULT_INT;
+ }
+ if (type.isSubtypeOf(ConstantVerifier_this._numType)) {
+ return ValidResult.RESULT_NUM;
+ }
+ if (type.isSubtypeOf(ConstantVerifier_this._stringType)) {
+ return ValidResult.RESULT_STRING;
+ }
+ }
+ return ValidResult.RESULT_OBJECT;
+ }
+ }
+ return super.visitSimpleIdentifier(node);
+ }
}
/**
* Instances of the class `ErrorVerifier` traverse an AST structure looking for additional
@@ -11045,6 +11442,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
checkForInvalidAssignment(node);
}
checkForAssignmentToFinal(node);
+ checkForArgumentTypeNotAssignable2(node.rightHandSide);
return super.visitAssignmentExpression(node);
}
Object visitBinaryExpression(BinaryExpression node) {
@@ -11331,12 +11729,19 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
checkForStaticAccessToInstanceMember(node.target, node.methodName);
return super.visitMethodInvocation(node);
}
+ Object visitNativeClause(NativeClause node) {
+ if (!_isInSystemLibrary) {
+ _errorReporter.reportError2(ParserErrorCode.NATIVE_CLAUSE_IN_NON_SDK_CODE, node, []);
+ }
+ return super.visitNativeClause(node);
+ }
Object visitNativeFunctionBody(NativeFunctionBody node) {
checkForNativeFunctionBodyInNonSDKCode(node);
return super.visitNativeFunctionBody(node);
}
Object visitPostfixExpression(PostfixExpression node) {
checkForAssignmentToFinal2(node.operand);
+ checkForIntNotAssignable(node.operand);
return super.visitPostfixExpression(node);
}
Object visitPrefixedIdentifier(PrefixedIdentifier node) {
@@ -11349,6 +11754,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
if (node.operator.type.isIncrementOperator) {
checkForAssignmentToFinal2(node.operand);
}
+ checkForIntNotAssignable(node.operand);
return super.visitPrefixExpression(node);
}
Object visitPropertyAccess(PropertyAccess node) {
@@ -11857,7 +12263,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
if (redirectedElement == null) {
TypeName constructorTypeName = redirectedNode.type;
Type2 redirectedType = constructorTypeName.type;
- if (redirectedType != null && redirectedType.element != null && redirectedType.element != DynamicElementImpl.instance) {
+ if (redirectedType != null && redirectedType.element != null && !redirectedType.isDynamic) {
String constructorStrName = constructorTypeName.name.name;
if (redirectedNode.name != null) {
constructorStrName += ".${redirectedNode.name.name}";
@@ -12010,7 +12416,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
ParameterElement staticParameterElement = argument.staticParameterElement;
Type2 staticParameterType = staticParameterElement == null ? null : staticParameterElement.type;
- ParameterElement propagatedParameterElement = argument.parameterElement;
+ ParameterElement propagatedParameterElement = argument.propagatedParameterElement;
Type2 propagatedParameterType = propagatedParameterElement == null ? null : propagatedParameterElement.type;
return checkForArgumentTypeNotAssignable3(argument, staticParameterType, propagatedParameterType, errorCode);
}
@@ -12025,35 +12431,48 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
* @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE
* @see CompileTimeErrorCode#ARGUMENT_TYPE_NOT_ASSIGNABLE
*/
- bool checkForArgumentTypeNotAssignable3(Expression expression, Type2 expectedStaticType, Type2 expectedPropagatedType, ErrorCode errorCode) {
- Type2 staticArgumentType = getStaticType(expression);
- if (staticArgumentType == null || expectedStaticType == null) {
+ bool checkForArgumentTypeNotAssignable3(Expression expression, Type2 expectedStaticType, Type2 expectedPropagatedType, ErrorCode errorCode) => checkForArgumentTypeNotAssignable4(expression, expectedStaticType, getStaticType(expression), expectedPropagatedType, expression.propagatedType, errorCode);
+
+ /**
+ * This verifies that the passed expression can be assigned to its corresponding parameters.
+ *
+ * @param expression the expression to evaluate
+ * @param expectedStaticType the expected static type of the parameter
+ * @param actualStaticType the actual static type of the argument
+ * @param expectedPropagatedType the expected propagated type of the parameter, may be
+ * `null`
+ * @param actualPropagatedType the expected propagated type of the parameter, may be `null`
+ * @return `true` if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE
+ * @see CompileTimeErrorCode#ARGUMENT_TYPE_NOT_ASSIGNABLE
+ */
+ bool checkForArgumentTypeNotAssignable4(Expression expression, Type2 expectedStaticType, Type2 actualStaticType, Type2 expectedPropagatedType, Type2 actualPropagatedType, ErrorCode errorCode) {
+ if (actualStaticType == null || expectedStaticType == null) {
return false;
}
if (_strictMode) {
- if (staticArgumentType.isAssignableTo(expectedStaticType)) {
+ if (actualStaticType.isAssignableTo(expectedStaticType)) {
return false;
}
_errorReporter.reportError2(errorCode, expression, [
- staticArgumentType.displayName,
+ actualStaticType.displayName,
expectedStaticType.displayName]);
return true;
}
- Type2 propagatedArgumentType = getPropagatedType(expression);
- if (propagatedArgumentType == null || expectedPropagatedType == null) {
- if (staticArgumentType.isAssignableTo(expectedStaticType)) {
+ if (actualPropagatedType == null || expectedPropagatedType == null) {
+ if (actualStaticType.isAssignableTo(expectedStaticType)) {
return false;
}
_errorReporter.reportError2(errorCode, expression, [
- staticArgumentType.displayName,
+ actualStaticType.displayName,
expectedStaticType.displayName]);
return true;
}
- if (staticArgumentType.isAssignableTo(expectedStaticType) || staticArgumentType.isAssignableTo(expectedPropagatedType) || propagatedArgumentType.isAssignableTo(expectedStaticType) || propagatedArgumentType.isAssignableTo(expectedPropagatedType)) {
+ if (actualStaticType.isAssignableTo(expectedStaticType) || actualStaticType.isAssignableTo(expectedPropagatedType) || actualPropagatedType.isAssignableTo(expectedStaticType) || actualPropagatedType.isAssignableTo(expectedPropagatedType)) {
return false;
}
_errorReporter.reportError2(errorCode, expression, [
- (propagatedArgumentType == null ? staticArgumentType : propagatedArgumentType).displayName,
+ (actualPropagatedType == null ? actualStaticType : actualPropagatedType).displayName,
(expectedPropagatedType == null ? expectedStaticType : expectedPropagatedType).displayName]);
return true;
}
@@ -12075,6 +12494,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
*
* @param node the expression to evaluate
* @return `true` if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#ASSIGNMENT_TO_CONST
* @see StaticWarningCode#ASSIGNMENT_TO_FINAL
* @see StaticWarningCode#ASSIGNMENT_TO_METHOD
*/
@@ -12086,17 +12506,17 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
if (expression is PropertyAccess) {
element = ((expression as PropertyAccess)).propertyName.element;
}
+ if (element is PropertyAccessorElement) {
+ PropertyAccessorElement accessor = element as PropertyAccessorElement;
+ element = accessor.variable;
+ }
if (element is VariableElement) {
- VariableElement leftVar = element as VariableElement;
- if (leftVar.isFinal) {
- _errorReporter.reportError2(StaticWarningCode.ASSIGNMENT_TO_FINAL, expression, []);
+ VariableElement variable = element as VariableElement;
+ if (variable.isConst) {
+ _errorReporter.reportError2(StaticWarningCode.ASSIGNMENT_TO_CONST, expression, []);
return true;
}
- return false;
- }
- if (element is PropertyAccessorElement) {
- PropertyAccessorElement leftAccessor = element as PropertyAccessorElement;
- if (!leftAccessor.isSetter) {
+ if (variable.isFinal) {
_errorReporter.reportError2(StaticWarningCode.ASSIGNMENT_TO_FINAL, expression, []);
return true;
}
@@ -12864,7 +13284,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
return true;
}
- Type2 propagatedType = getPropagatedType(expression);
+ Type2 propagatedType = expression.propagatedType;
if (propagatedType != null && propagatedType.isAssignableTo(fieldType)) {
return false;
}
@@ -13113,9 +13533,9 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
SwitchCase switchCase = switchMember as SwitchCase;
Expression expression = switchCase.expression;
if (firstType == null) {
- firstType = getBestType(expression);
+ firstType = expression.bestType;
} else {
- Type2 nType = getBestType(expression);
+ Type2 nType = expression.bestType;
if (firstType != nType) {
_errorReporter.reportError2(CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, expression, [expression.toSource(), firstType.displayName]);
foundError = true;
@@ -13149,6 +13569,33 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
/**
+ * This verifies that an 'int' can be assigned to the parameter corresponding to the given
+ * expression. This is used for prefix and postfix expressions where the argument value is
+ * implicit.
+ *
+ * @param argument the expression to which the operator is being applied
+ * @return `true` if and only if an error code is generated on the passed node
+ * @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE
+ * @see CompileTimeErrorCode#ARGUMENT_TYPE_NOT_ASSIGNABLE
+ */
+ bool checkForIntNotAssignable(Expression argument) {
+ if (argument == null) {
+ return false;
+ }
+ ErrorCode errorCode;
+ if (_isInConstInstanceCreation || _isEnclosingConstructorConst) {
+ errorCode = CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE;
+ } else {
+ errorCode = StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE;
+ }
+ ParameterElement staticParameterElement = argument.staticParameterElement;
+ Type2 staticParameterType = staticParameterElement == null ? null : staticParameterElement.type;
+ ParameterElement propagatedParameterElement = argument.propagatedParameterElement;
+ Type2 propagatedParameterType = propagatedParameterElement == null ? null : propagatedParameterElement.type;
+ return checkForArgumentTypeNotAssignable4(argument, staticParameterType, _typeProvider.intType, propagatedParameterType, _typeProvider.intType, errorCode);
+ }
+
+ /**
* Given an assignment using a compound assignment operator, this verifies that the given
* assignment is valid.
*
@@ -13163,7 +13610,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
VariableElement leftElement = getVariableElement(lhs);
Type2 leftType = (leftElement == null) ? getStaticType(lhs) : leftElement.type;
- MethodElement invokedMethod = node.element;
+ MethodElement invokedMethod = node.staticElement;
if (invokedMethod == null) {
return false;
}
@@ -13194,7 +13641,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
Type2 leftType = (leftElement == null) ? getStaticType(lhs) : leftElement.type;
Type2 staticRightType = getStaticType(rhs);
bool isStaticAssignable = staticRightType.isAssignableTo(leftType);
- Type2 propagatedRightType = getPropagatedType(rhs);
+ Type2 propagatedRightType = rhs.propagatedType;
if (_strictMode || propagatedRightType == null) {
if (!isStaticAssignable) {
_errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
@@ -13574,39 +14021,22 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
if (_enclosingClass.isAbstract) {
return false;
}
- Set<ExecutableElement> missingOverrides = new Set<ExecutableElement>();
+ List<MethodElement> methods = _enclosingClass.methods;
+ List<PropertyAccessorElement> accessors = _enclosingClass.accessors;
Set<String> methodsInEnclosingClass = new Set<String>();
Set<String> accessorsInEnclosingClass = new Set<String>();
- List<MethodElement> methods = _enclosingClass.methods;
for (MethodElement method in methods) {
javaSetAdd(methodsInEnclosingClass, method.name);
}
- List<PropertyAccessorElement> accessors = _enclosingClass.accessors;
for (PropertyAccessorElement accessor in accessors) {
javaSetAdd(accessorsInEnclosingClass, accessor.name);
}
- Map<String, ExecutableElement> membersInheritedFromSuperclasses = _inheritanceManager.getMapOfMembersInheritedFromClasses(_enclosingClass);
- for (MapEntry<String, ExecutableElement> entry in getMapEntrySet(membersInheritedFromSuperclasses)) {
- ExecutableElement executableElt = entry.getValue();
- if (executableElt is MethodElement) {
- MethodElement methodElt = executableElt as MethodElement;
- if (methodElt.isAbstract) {
- String methodName = entry.getKey();
- if (!methodsInEnclosingClass.contains(methodName)) {
- javaSetAdd(missingOverrides, executableElt);
- }
- }
- } else if (executableElt is PropertyAccessorElement) {
- PropertyAccessorElement propertyAccessorElt = executableElt as PropertyAccessorElement;
- if (propertyAccessorElt.isAbstract) {
- String accessorName = entry.getKey();
- if (!accessorsInEnclosingClass.contains(accessorName)) {
- javaSetAdd(missingOverrides, executableElt);
- }
- }
- }
+ if (methodsInEnclosingClass.contains(ElementResolver.NO_SUCH_METHOD_METHOD_NAME)) {
+ return false;
}
+ Set<ExecutableElement> missingOverrides = new Set<ExecutableElement>();
Map<String, ExecutableElement> membersInheritedFromInterfaces = _inheritanceManager.getMapOfMembersInheritedFromInterfaces(_enclosingClass);
+ Map<String, ExecutableElement> membersInheritedFromSuperclasses = _inheritanceManager.getMapOfMembersInheritedFromClasses(_enclosingClass);
for (MapEntry<String, ExecutableElement> entry in getMapEntrySet(membersInheritedFromInterfaces)) {
ExecutableElement executableElt = entry.getValue();
ExecutableElement elt = membersInheritedFromSuperclasses[executableElt.name];
@@ -13619,12 +14049,12 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
if (executableElt is MethodElement) {
String methodName = entry.getKey();
- if (!methodsInEnclosingClass.contains(methodName)) {
+ if (!methodsInEnclosingClass.contains(methodName) && !memberHasConcreteMethodImplementationInSuperclassChain(_enclosingClass, methodName, new List<ClassElement>())) {
javaSetAdd(missingOverrides, executableElt);
}
} else if (executableElt is PropertyAccessorElement) {
String accessorName = entry.getKey();
- if (!accessorsInEnclosingClass.contains(accessorName)) {
+ if (!accessorsInEnclosingClass.contains(accessorName) && !memberHasConcreteAccessorImplementationInSuperclassChain(_enclosingClass, accessorName, new List<ClassElement>())) {
javaSetAdd(missingOverrides, executableElt);
}
}
@@ -13905,7 +14335,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
_errorReporter.reportError3(CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE, _enclosingClass.nameOffset, enclosingClassName.length, [enclosingClassName, builder.toString()]);
return true;
} else if (list.length == 2) {
- ErrorCode errorCode = supertype != null && _enclosingClass == supertype.element ? CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS : CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS;
+ ErrorCode errorCode = (supertype != null && _enclosingClass == supertype.element ? CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS : CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS) as ErrorCode;
_errorReporter.reportError3(errorCode, _enclosingClass.nameOffset, enclosingClassName.length, [enclosingClassName]);
return true;
}
@@ -14115,7 +14545,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
return true;
}
bool isStaticAssignable = staticReturnType.isAssignableTo(expectedReturnType);
- Type2 propagatedReturnType = getPropagatedType(returnExpression);
+ Type2 propagatedReturnType = returnExpression.propagatedType;
if (_strictMode || propagatedReturnType == null) {
if (isStaticAssignable) {
return false;
@@ -14203,7 +14633,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
*/
bool checkForTypeAliasCannotReferenceItself_function(FunctionTypeAlias node) {
FunctionTypeAliasElement element = node.element;
- if (!hasFunctionTypeAliasSelfReference(element)) {
+ if (!hasTypedefSelfReference(element)) {
return false;
}
_errorReporter.reportError2(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, node, []);
@@ -14218,7 +14648,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
*/
bool checkForTypeAliasCannotReferenceItself_mixin(ClassTypeAlias node) {
ClassElement element = node.element;
- if (!hasClassTypeAliasSelfReference(element, new Set<ClassElement>())) {
+ if (!hasTypedefSelfReference(element)) {
return false;
}
_errorReporter.reportError2(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, node, []);
@@ -14432,21 +14862,6 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
/**
- * Return the propagated type of the given expression, or the static type if there is no
- * propagated type information.
- *
- * @param expression the expression whose type is to be returned
- * @return the propagated or static type of the given expression, whichever is best
- */
- Type2 getBestType(Expression expression) {
- Type2 type = getPropagatedType(expression);
- if (type == null) {
- type = getStaticType(expression);
- }
- return type;
- }
-
- /**
* Returns the Type (return type) for a given getter.
*
* @param propertyAccessorElement
@@ -14459,15 +14874,7 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
} else {
return null;
}
- }
-
- /**
- * Return the propagated type of the given expression that is to be used for type analysis.
- *
- * @param expression the expression whose type is to be returned
- * @return the propagated type of the given expression
- */
- Type2 getPropagatedType(Expression expression) => expression.propagatedType;
+ }
/**
* Returns the Type (first and only parameter) for a given setter.
@@ -14515,78 +14922,6 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
/**
- * @return <code>true</code> if given [ClassElement] has direct or indirect reference to
- * itself using only other typedef [ClassElement]s.
- */
- bool hasClassTypeAliasSelfReference(ClassElement element2, Set<ClassElement> seenMixins) {
- if (seenMixins.contains(element2)) {
- return true;
- }
- javaSetAdd(seenMixins, element2);
- for (InterfaceType mixin in element2.mixins) {
- ClassElement mixinElement = mixin.element;
- if (!mixinElement.isTypedef) {
- continue;
- }
- if (hasClassTypeAliasSelfReference(mixinElement, seenMixins)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks if "target" is referenced by "current".
- */
- bool hasFunctionTypeAliasReference(Set<FunctionTypeAliasElement> visited, FunctionTypeAliasElement target, Element currentElement) {
- if (currentElement is! FunctionTypeAliasElement) {
- return false;
- }
- FunctionTypeAliasElement current = currentElement as FunctionTypeAliasElement;
- if (target == current) {
- return true;
- }
- if (visited.contains(current)) {
- return false;
- }
- javaSetAdd(visited, current);
- return hasFunctionTypeAliasReference2(visited, target, current);
- }
-
- /**
- * Checks if "target" is referenced by "current".
- */
- bool hasFunctionTypeAliasReference2(Set<FunctionTypeAliasElement> visited, FunctionTypeAliasElement target, FunctionTypeAliasElement current) {
- FunctionType type = current.type;
- Set<Type2> referencedTypes = new Set();
- if (type != null) {
- for (TypeVariableElement typeVariable in current.typeVariables) {
- Type2 bound = typeVariable.bound;
- javaSetAdd(referencedTypes, bound);
- }
- javaSetAdd(referencedTypes, type.returnType);
- for (ParameterElement parameter in type.parameters) {
- javaSetAdd(referencedTypes, parameter.type);
- }
- }
- for (Type2 referencedType in referencedTypes) {
- if (referencedType != null && hasFunctionTypeAliasReference(visited, target, referencedType.element)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * @return <code>true</code> if given [FunctionTypeAliasElement] has direct or indirect
- * reference to itself using other [FunctionTypeAliasElement]s.
- */
- bool hasFunctionTypeAliasSelfReference(FunctionTypeAliasElement target) {
- Set<FunctionTypeAliasElement> visited = new Set();
- return hasFunctionTypeAliasReference2(visited, target, target);
- }
-
- /**
* @return `true` if the given constructor redirects to itself, directly or indirectly
*/
bool hasRedirectingFactoryConstructorCycle(ConstructorElement element) {
@@ -14606,6 +14941,39 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
/**
+ * @return <code>true</code> if given [Element] has direct or indirect reference to itself
+ * form anywhere except [ClassElement] or type variable bounds.
+ */
+ bool hasTypedefSelfReference(Element target) {
+ Set<Element> checked = new Set<Element>();
+ List<Element> toCheck = new List<Element>();
+ toCheck.add(target);
+ bool firstIteration = true;
+ while (true) {
+ Element current;
+ while (true) {
+ if (toCheck.isEmpty) {
+ return false;
+ }
+ current = toCheck.removeAt(toCheck.length - 1);
+ if (target == current) {
+ if (firstIteration) {
+ firstIteration = false;
+ break;
+ } else {
+ return true;
+ }
+ }
+ if (current != null && !checked.contains(current)) {
+ break;
+ }
+ }
+ current.accept(new GeneralizingElementVisitor_11(target, toCheck));
+ javaSetAdd(checked, current);
+ }
+ }
+
+ /**
* @return `true` if the given [ASTNode] is the part of constant constructor
* invocation.
*/
@@ -14640,13 +15008,95 @@ class ErrorVerifier extends RecursiveASTVisitor<Object> {
}
return false;
}
+
+ /**
+ * Return `true` iff the passed [ClassElement] has a concrete implementation of the
+ * passed accessor name in the superclass chain.
+ */
+ bool memberHasConcreteAccessorImplementationInSuperclassChain(ClassElement classElement, String accessorName, List<ClassElement> superclassChain) {
+ if (superclassChain.contains(classElement)) {
+ return false;
+ } else {
+ superclassChain.add(classElement);
+ }
+ for (PropertyAccessorElement accessor in classElement.accessors) {
+ if (accessor.name == accessorName) {
+ if (!accessor.isAbstract) {
+ return true;
+ }
+ }
+ }
+ for (InterfaceType mixinType in classElement.mixins) {
+ if (mixinType != null) {
+ ClassElement mixinElement = mixinType.element;
+ if (mixinElement != null) {
+ for (PropertyAccessorElement accessor in mixinElement.accessors) {
+ if (accessor.name == accessorName) {
+ if (!accessor.isAbstract) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ InterfaceType superType = classElement.supertype;
+ if (superType != null) {
+ ClassElement superClassElt = superType.element;
+ if (superClassElt != null) {
+ return memberHasConcreteAccessorImplementationInSuperclassChain(superClassElt, accessorName, superclassChain);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return `true` iff the passed [ClassElement] has a concrete implementation of the
+ * passed method name in the superclass chain.
+ */
+ bool memberHasConcreteMethodImplementationInSuperclassChain(ClassElement classElement, String methodName, List<ClassElement> superclassChain) {
+ if (superclassChain.contains(classElement)) {
+ return false;
+ } else {
+ superclassChain.add(classElement);
+ }
+ for (MethodElement method in classElement.methods) {
+ if (method.name == methodName) {
+ if (!method.isAbstract) {
+ return true;
+ }
+ }
+ }
+ for (InterfaceType mixinType in classElement.mixins) {
+ if (mixinType != null) {
+ ClassElement mixinElement = mixinType.element;
+ if (mixinElement != null) {
+ for (MethodElement method in mixinElement.methods) {
+ if (method.name == methodName) {
+ if (!method.isAbstract) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ InterfaceType superType = classElement.supertype;
+ if (superType != null) {
+ ClassElement superClassElt = superType.element;
+ if (superClassElt != null) {
+ return memberHasConcreteMethodImplementationInSuperclassChain(superClassElt, methodName, superclassChain);
+ }
+ }
+ return false;
+ }
}
/**
* This enum holds one of four states of a field initialization state through a constructor
* signature, not initialized, initialized in the field declaration, initialized in the field
* formal, and finally, initialized in the initializers list.
*/
-class INIT_STATE implements Comparable<INIT_STATE> {
+class INIT_STATE implements Enum<INIT_STATE> {
static final INIT_STATE NOT_INIT = new INIT_STATE('NOT_INIT', 0);
static final INIT_STATE INIT_IN_DECLARATION = new INIT_STATE('INIT_IN_DECLARATION', 1);
static final INIT_STATE INIT_IN_FIELD_FORMAL = new INIT_STATE('INIT_IN_FIELD_FORMAL', 2);
@@ -14667,171 +15117,58 @@ class INIT_STATE implements Comparable<INIT_STATE> {
int get hashCode => ordinal;
String toString() => name;
}
-/**
- * Instances of the class `HintVerifier` traverse an AST structure looking for additional
- * additional suggestions not mentioned in the Dart Language Specification.
- *
- * @coverage dart.engine.resolver
- */
-class HintVerifier {
- DeadCodeVerifier _deadCodeVerifier;
- HintVerifier(AnalysisContext context, ErrorReporter errorReporter) {
- _deadCodeVerifier = new DeadCodeVerifier(errorReporter);
- }
- void visitCompilationUnit(CompilationUnit node) {
- node.accept(_deadCodeVerifier);
- }
-}
-/**
- * Instances of the class `PubVerifier` traverse an AST structure looking for deviations from
- * pub best practices.
- */
-class PubVerifier extends RecursiveASTVisitor<Object> {
- static String _PUBSPEC_YAML = "pubspec.yaml";
-
- /**
- * The analysis context containing the sources to be analyzed
- */
- AnalysisContext _context;
-
- /**
- * The error reporter by which errors will be reported.
- */
- ErrorReporter _errorReporter;
- PubVerifier(AnalysisContext context, ErrorReporter errorReporter) {
- this._context = context;
- this._errorReporter = errorReporter;
- }
- Object visitImportDirective(ImportDirective directive) {
- return null;
- }
-
- /**
- * This verifies that the passed file import directive is not contained in a source inside a
- * package "lib" directory hierarchy referencing a source outside that package "lib" directory
- * hierarchy.
- *
- * @param uriLiteral the import URL (not `null`)
- * @param path the file path being verified (not `null`)
- * @return `true` if and only if an error code is generated on the passed node
- * @see PubSuggestionCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE
- */
- bool checkForFileImportInsideLibReferencesFileOutside(StringLiteral uriLiteral, String path) {
- Source source = getSource(uriLiteral);
- String fullName = getSourceFullName(source);
- if (fullName != null) {
- int pathIndex = 0;
- int fullNameIndex = fullName.length;
- while (pathIndex < path.length && JavaString.startsWithBefore(path, "../", pathIndex)) {
- fullNameIndex = JavaString.lastIndexOf(fullName, '/', fullNameIndex);
- if (fullNameIndex < 4) {
- return false;
- }
- if (JavaString.startsWithBefore(fullName, "/lib", fullNameIndex - 4)) {
- String relativePubspecPath = path.substring(0, pathIndex + 3) + _PUBSPEC_YAML;
- Source pubspecSource = _context.sourceFactory.resolveUri(source, relativePubspecPath);
- if (pubspecSource.exists()) {
- _errorReporter.reportError2(PubSuggestionCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE, uriLiteral, []);
- }
- return true;
- }
- pathIndex += 3;
- }
+class GeneralizingElementVisitor_11 extends GeneralizingElementVisitor<Object> {
+ Element target;
+ List<Element> toCheck;
+ GeneralizingElementVisitor_11(this.target, this.toCheck) : super();
+ bool _inClass = false;
+ Object visitClassElement(ClassElement element) {
+ addTypeToCheck(element.supertype);
+ for (InterfaceType mixin in element.mixins) {
+ addTypeToCheck(mixin);
+ }
+ _inClass = !element.isTypedef;
+ try {
+ return super.visitClassElement(element);
+ } finally {
+ _inClass = false;
}
- return false;
}
-
- /**
- * This verifies that the passed file import directive is not contained in a source outside a
- * package "lib" directory hierarchy referencing a source inside that package "lib" directory
- * hierarchy.
- *
- * @param uriLiteral the import URL (not `null`)
- * @param path the file path being verified (not `null`)
- * @return `true` if and only if an error code is generated on the passed node
- * @see PubSuggestionCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE
- */
- bool checkForFileImportOutsideLibReferencesFileInside(StringLiteral uriLiteral, String path) {
- if (path.startsWith("lib/")) {
- if (checkForFileImportOutsideLibReferencesFileInside2(uriLiteral, path, 0)) {
- return true;
- }
- }
- int pathIndex = path.indexOf("/lib/");
- while (pathIndex != -1) {
- if (checkForFileImportOutsideLibReferencesFileInside2(uriLiteral, path, pathIndex + 1)) {
- return true;
- }
- pathIndex = JavaString.indexOf(path, "/lib/", pathIndex + 4);
+ Object visitExecutableElement(ExecutableElement element) {
+ if (element.isSynthetic) {
+ return null;
}
- return false;
+ addTypeToCheck(element.returnType);
+ return super.visitExecutableElement(element);
}
- bool checkForFileImportOutsideLibReferencesFileInside2(StringLiteral uriLiteral, String path, int pathIndex) {
- Source source = getSource(uriLiteral);
- String relativePubspecPath = path.substring(0, pathIndex) + _PUBSPEC_YAML;
- Source pubspecSource = _context.sourceFactory.resolveUri(source, relativePubspecPath);
- if (!pubspecSource.exists()) {
- return false;
- }
- String fullName = getSourceFullName(source);
- if (fullName != null) {
- if (!fullName.contains("/lib/")) {
- _errorReporter.reportError2(PubSuggestionCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE, uriLiteral, []);
- return true;
- }
- }
- return false;
+ Object visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
+ addTypeToCheck(element.returnType);
+ return super.visitFunctionTypeAliasElement(element);
}
-
- /**
- * This verifies that the passed package import directive does not contain ".."
- *
- * @param uriLiteral the import URL (not `null`)
- * @param path the path to be validated (not `null`)
- * @return `true` if and only if an error code is generated on the passed node
- * @see PubSuggestionCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT
- */
- bool checkForPackageImportContainsDotDot(StringLiteral uriLiteral, String path) {
- if (path.startsWith("../") || path.contains("/../")) {
- _errorReporter.reportError2(PubSuggestionCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT, uriLiteral, []);
- return true;
- }
- return false;
+ Object visitParameterElement(ParameterElement element) {
+ addTypeToCheck(element.type);
+ return super.visitParameterElement(element);
}
-
- /**
- * Answer the source associated with the compilation unit containing the given AST node.
- *
- * @param node the node (not `null`)
- * @return the source or `null` if it could not be determined
- */
- Source getSource(ASTNode node) {
- Source source = null;
- CompilationUnit unit = node.getAncestor(CompilationUnit);
- if (unit != null) {
- CompilationUnitElement element = unit.element;
- if (element != null) {
- source = element.source;
- }
- }
- return source;
+ Object visitTypeVariableElement(TypeVariableElement element) => null;
+ Object visitVariableElement(VariableElement element) {
+ addTypeToCheck(element.type);
+ return super.visitVariableElement(element);
}
-
- /**
- * Answer the full name of the given source. The returned value will have all
- * [File#separatorChar] replace by '/'.
- *
- * @param source the source
- * @return the full name or `null` if it could not be determined
- */
- String getSourceFullName(Source source) {
- if (source != null) {
- String fullName = source.fullName;
- if (fullName != null) {
- return fullName.replaceAll(r'\', '/');
+ void addTypeToCheck(Type2 type) {
+ if (type == null) {
+ return;
+ }
+ Element element = type.element;
+ if (_inClass && target == element) {
+ return;
+ }
+ toCheck.add(element);
+ if (type is InterfaceType) {
+ InterfaceType interfaceType = type as InterfaceType;
+ for (Type2 typeArgument in interfaceType.typeArguments) {
+ addTypeToCheck(typeArgument);
}
}
- return null;
}
}
/**
@@ -14842,7 +15179,7 @@ class PubVerifier extends RecursiveASTVisitor<Object> {
*
* @coverage dart.engine.resolver
*/
-class ResolverErrorCode implements Comparable<ResolverErrorCode>, ErrorCode {
+class ResolverErrorCode implements Enum<ResolverErrorCode>, ErrorCode {
static final ResolverErrorCode BREAK_LABEL_ON_SWITCH_MEMBER = new ResolverErrorCode('BREAK_LABEL_ON_SWITCH_MEMBER', 0, ErrorType.COMPILE_TIME_ERROR, "Break label resolves to case or default statement");
static final ResolverErrorCode CONTINUE_LABEL_ON_SWITCH = new ResolverErrorCode('CONTINUE_LABEL_ON_SWITCH', 1, ErrorType.COMPILE_TIME_ERROR, "A continue label resolves to switch, must be loop or switch member");
static final ResolverErrorCode MISSING_LIBRARY_DIRECTIVE_WITH_PART = new ResolverErrorCode('MISSING_LIBRARY_DIRECTIVE_WITH_PART', 2, ErrorType.COMPILE_TIME_ERROR, "Libraries that have parts must have a library directive");

Powered by Google App Engine
This is Rietveld 408576698