Index: pkg/analyzer/lib/src/generated/resolver.dart |
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart |
index 9ec01641fe353eb1fe37c65e8874b9cca9a90449..504f25be87a35fac52aa641b49c47c3aeaef2830 100644 |
--- a/pkg/analyzer/lib/src/generated/resolver.dart |
+++ b/pkg/analyzer/lib/src/generated/resolver.dart |
@@ -3863,9 +3863,9 @@ class ImportsVerifier extends RecursiveAstVisitor<Object> { |
* @param annotations the list of annotations to visit |
*/ |
void _visitMetadata(NodeList<Annotation> annotations) { |
- for (Annotation annotation in annotations) { |
- Identifier name = annotation.name; |
- _visitIdentifier(name.staticElement, name.name); |
+ int count = annotations.length; |
+ for (int i = 0; i < count; i++) { |
+ annotations[i].accept(this); |
} |
} |
} |
@@ -5539,9 +5539,9 @@ class ElementResolver extends SimpleAstVisitor<Object> { |
MethodElement propagatedMethod = _lookUpMethod(leftHandSide, propagatedType, methodName); |
node.propagatedElement = propagatedMethod; |
if (_shouldReportMissingMember(staticType, staticMethod)) { |
- _resolver.reportErrorProxyConditionalAnalysisError(staticType.element, StaticTypeWarningCode.UNDEFINED_METHOD, operator, [methodName, staticType.displayName]); |
+ _resolver.reportProxyConditionalErrorForToken(staticType.element, StaticTypeWarningCode.UNDEFINED_METHOD, operator, [methodName, staticType.displayName]); |
} else if (_enableHints && _shouldReportMissingMember(propagatedType, propagatedMethod) && !_memberFoundInSubclass(propagatedType.element, methodName, true, false)) { |
- _resolver.reportErrorProxyConditionalAnalysisError(propagatedType.element, HintCode.UNDEFINED_METHOD, operator, [methodName, propagatedType.displayName]); |
+ _resolver.reportProxyConditionalErrorForToken(propagatedType.element, HintCode.UNDEFINED_METHOD, operator, [methodName, propagatedType.displayName]); |
} |
} |
} |
@@ -5562,9 +5562,9 @@ class ElementResolver extends SimpleAstVisitor<Object> { |
MethodElement propagatedMethod = _lookUpMethod(leftOperand, propagatedType, methodName); |
node.propagatedElement = propagatedMethod; |
if (_shouldReportMissingMember(staticType, staticMethod)) { |
- _resolver.reportErrorProxyConditionalAnalysisError(staticType.element, StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [methodName, staticType.displayName]); |
+ _resolver.reportProxyConditionalErrorForToken(staticType.element, StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [methodName, staticType.displayName]); |
} else if (_enableHints && _shouldReportMissingMember(propagatedType, propagatedMethod) && !_memberFoundInSubclass(propagatedType.element, methodName, true, false)) { |
- _resolver.reportErrorProxyConditionalAnalysisError(propagatedType.element, HintCode.UNDEFINED_OPERATOR, operator, [methodName, propagatedType.displayName]); |
+ _resolver.reportProxyConditionalErrorForToken(propagatedType.element, HintCode.UNDEFINED_OPERATOR, operator, [methodName, propagatedType.displayName]); |
} |
} |
} |
@@ -6059,9 +6059,9 @@ class ElementResolver extends SimpleAstVisitor<Object> { |
MethodElement propagatedMethod = _lookUpMethod(operand, propagatedType, methodName); |
node.propagatedElement = propagatedMethod; |
if (_shouldReportMissingMember(staticType, staticMethod)) { |
- _resolver.reportErrorProxyConditionalAnalysisError(staticType.element, StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [methodName, staticType.displayName]); |
+ _resolver.reportProxyConditionalErrorForToken(staticType.element, StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [methodName, staticType.displayName]); |
} else if (_enableHints && _shouldReportMissingMember(propagatedType, propagatedMethod) && !_memberFoundInSubclass(propagatedType.element, methodName, true, false)) { |
- _resolver.reportErrorProxyConditionalAnalysisError(propagatedType.element, HintCode.UNDEFINED_OPERATOR, node.operator, [methodName, propagatedType.displayName]); |
+ _resolver.reportProxyConditionalErrorForToken(propagatedType.element, HintCode.UNDEFINED_OPERATOR, node.operator, [methodName, propagatedType.displayName]); |
} |
return null; |
} |
@@ -6138,9 +6138,9 @@ class ElementResolver extends SimpleAstVisitor<Object> { |
MethodElement propagatedMethod = _lookUpMethod(operand, propagatedType, methodName); |
node.propagatedElement = propagatedMethod; |
if (_shouldReportMissingMember(staticType, staticMethod)) { |
- _resolver.reportErrorProxyConditionalAnalysisError(staticType.element, StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [methodName, staticType.displayName]); |
+ _resolver.reportProxyConditionalErrorForToken(staticType.element, StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [methodName, staticType.displayName]); |
} else if (_enableHints && _shouldReportMissingMember(propagatedType, propagatedMethod) && !_memberFoundInSubclass(propagatedType.element, methodName, true, false)) { |
- _resolver.reportErrorProxyConditionalAnalysisError(propagatedType.element, HintCode.UNDEFINED_OPERATOR, operator, [methodName, propagatedType.displayName]); |
+ _resolver.reportProxyConditionalErrorForToken(propagatedType.element, HintCode.UNDEFINED_OPERATOR, operator, [methodName, propagatedType.displayName]); |
} |
} |
return null; |
@@ -9040,11 +9040,12 @@ class LibraryElementBuilder { |
/** |
* Initialize a newly created library element builder. |
* |
- * @param resolver the resolver for which the element model is being built |
+ * @param analysisContext the analysis context in which the element model will be built |
+ * @param errorListener the listener to which errors will be reported |
*/ |
- LibraryElementBuilder(LibraryResolver resolver) { |
- this._analysisContext = resolver.analysisContext; |
- this._errorListener = resolver.errorListener; |
+ LibraryElementBuilder(InternalAnalysisContext analysisContext, AnalysisErrorListener errorListener) { |
+ this._analysisContext = analysisContext; |
+ this._errorListener = errorListener; |
} |
/** |
@@ -9083,14 +9084,97 @@ class LibraryElementBuilder { |
Source partSource = library.getSource(partDirective); |
if (_analysisContext.exists(partSource)) { |
hasPartDirective = true; |
- CompilationUnitElementImpl part = builder.buildCompilationUnit(partSource, library.getAST(partSource)); |
+ CompilationUnit partUnit = library.getAST(partSource); |
+ CompilationUnitElementImpl part = builder.buildCompilationUnit(partSource, partUnit); |
part.uriOffset = partUri.offset; |
part.uriEnd = partUri.end; |
part.uri = library.getUri(partDirective); |
// |
// Validate that the part contains a part-of directive with the same name as the library. |
// |
- String partLibraryName = _getPartLibraryName(library, partSource, directivesToResolve); |
+ String partLibraryName = _getPartLibraryName(partSource, partUnit, directivesToResolve); |
+ if (partLibraryName == null) { |
+ _errorListener.onError(new AnalysisError.con2(librarySource, partUri.offset, partUri.length, CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSource()])); |
+ } else if (libraryNameNode == null) { |
+ } else if (libraryNameNode.name != partLibraryName) { |
+ _errorListener.onError(new AnalysisError.con2(librarySource, partUri.offset, partUri.length, StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [libraryNameNode.name, partLibraryName])); |
+ } |
+ if (entryPoint == null) { |
+ entryPoint = _findEntryPoint(part); |
+ } |
+ directive.element = part; |
+ sourcedCompilationUnits.add(part); |
+ } |
+ } |
+ } |
+ if (hasPartDirective && libraryNameNode == null) { |
+ _errorListener.onError(new AnalysisError.con1(librarySource, ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART, [])); |
+ } |
+ // |
+ // Create and populate the library element. |
+ // |
+ LibraryElementImpl libraryElement = new LibraryElementImpl(_analysisContext, libraryNameNode); |
+ libraryElement.definingCompilationUnit = definingCompilationUnitElement; |
+ if (entryPoint != null) { |
+ libraryElement.entryPoint = entryPoint; |
+ } |
+ int sourcedUnitCount = sourcedCompilationUnits.length; |
+ libraryElement.parts = new List.from(sourcedCompilationUnits); |
+ for (Directive directive in directivesToResolve) { |
+ directive.element = libraryElement; |
+ } |
+ library.libraryElement = libraryElement; |
+ if (sourcedUnitCount > 0) { |
+ _patchTopLevelAccessors(libraryElement); |
+ } |
+ return libraryElement; |
+ } |
+ |
+ /** |
+ * Build the library element for the given library. |
+ * |
+ * @param library the library for which an element model is to be built |
+ * @return the library element that was built |
+ * @throws AnalysisException if the analysis could not be performed |
+ */ |
+ LibraryElementImpl buildLibrary2(ResolvableLibrary library) { |
+ CompilationUnitBuilder builder = new CompilationUnitBuilder(); |
+ Source librarySource = library.librarySource; |
+ CompilationUnit definingCompilationUnit = library.definingCompilationUnit; |
+ CompilationUnitElementImpl definingCompilationUnitElement = builder.buildCompilationUnit(librarySource, definingCompilationUnit); |
+ NodeList<Directive> directives = definingCompilationUnit.directives; |
+ LibraryIdentifier libraryNameNode = null; |
+ bool hasPartDirective = false; |
+ FunctionElement entryPoint = _findEntryPoint(definingCompilationUnitElement); |
+ List<Directive> directivesToResolve = new List<Directive>(); |
+ List<CompilationUnitElementImpl> sourcedCompilationUnits = new List<CompilationUnitElementImpl>(); |
+ for (Directive directive in directives) { |
+ // |
+ // We do not build the elements representing the import and export directives at this point. |
+ // That is not done until we get to LibraryResolver.buildDirectiveModels() because we need the |
+ // LibraryElements for the referenced libraries, which might not exist at this point (due to |
+ // the possibility of circular references). |
+ // |
+ if (directive is LibraryDirective) { |
+ if (libraryNameNode == null) { |
+ libraryNameNode = directive.name; |
+ directivesToResolve.add(directive); |
+ } |
+ } else if (directive is PartDirective) { |
+ PartDirective partDirective = directive; |
+ StringLiteral partUri = partDirective.uri; |
+ Source partSource = partDirective.source; |
+ if (_analysisContext.exists(partSource)) { |
+ hasPartDirective = true; |
+ CompilationUnit partUnit = library.getAST(partSource); |
+ CompilationUnitElementImpl part = builder.buildCompilationUnit(partSource, partUnit); |
+ part.uriOffset = partUri.offset; |
+ part.uriEnd = partUri.end; |
+ part.uri = partDirective.uriContent; |
+ // |
+ // Validate that the part contains a part-of directive with the same name as the library. |
+ // |
+ String partLibraryName = _getPartLibraryName(partSource, partUnit, directivesToResolve); |
if (partLibraryName == null) { |
_errorListener.onError(new AnalysisError.con2(librarySource, partUri.offset, partUri.length, CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSource()])); |
} else if (libraryNameNode == null) { |
@@ -9170,25 +9254,21 @@ class LibraryElementBuilder { |
* Return the name of the library that the given part is declared to be a part of, or `null` |
* if the part does not contain a part-of directive. |
* |
- * @param library the library containing the part |
* @param partSource the source representing the part |
+ * @param partUnit the AST structure of the part |
* @param directivesToResolve a list of directives that should be resolved to the library being |
* built |
* @return the name of the library that the given part is declared to be a part of |
*/ |
- String _getPartLibraryName(Library library, Source partSource, List<Directive> directivesToResolve) { |
- try { |
- CompilationUnit partUnit = library.getAST(partSource); |
- for (Directive directive in partUnit.directives) { |
- if (directive is PartOfDirective) { |
- directivesToResolve.add(directive); |
- LibraryIdentifier libraryName = directive.libraryName; |
- if (libraryName != null) { |
- return libraryName.name; |
- } |
+ String _getPartLibraryName(Source partSource, CompilationUnit partUnit, List<Directive> directivesToResolve) { |
+ for (Directive directive in partUnit.directives) { |
+ if (directive is PartOfDirective) { |
+ directivesToResolve.add(directive); |
+ LibraryIdentifier libraryName = directive.libraryName; |
+ if (libraryName != null) { |
+ return libraryName.name; |
} |
} |
- } on AnalysisException catch (exception) { |
} |
return null; |
} |
@@ -9652,7 +9732,7 @@ class LibraryResolver { |
*/ |
void _buildElementModels() { |
for (Library library in _librariesInCycles) { |
- LibraryElementBuilder builder = new LibraryElementBuilder(this); |
+ LibraryElementBuilder builder = new LibraryElementBuilder(analysisContext, errorListener); |
LibraryElementImpl libraryElement = builder.buildLibrary(library); |
library.libraryElement = libraryElement; |
} |
@@ -9949,212 +10029,885 @@ class LibraryResolver { |
} |
/** |
- * This class is used to replace uses of `HashMap<String, ExecutableElement>` which are not as |
- * performant as this class. |
+ * Instances of the class `LibraryResolver` are used to resolve one or more mutually dependent |
+ * libraries within a single context. |
*/ |
-class MemberMap { |
+class LibraryResolver2 { |
/** |
- * The current size of this map. |
+ * The analysis context in which the libraries are being analyzed. |
*/ |
- int _size = 0; |
+ InternalAnalysisContext analysisContext; |
/** |
- * The array of keys. |
+ * The listener to which analysis errors will be reported, this error listener is either |
+ * references [recordingErrorListener], or it unions the passed |
+ * [AnalysisErrorListener] with the [recordingErrorListener]. |
*/ |
- List<String> _keys; |
+ RecordingErrorListener _errorListener; |
/** |
- * The array of ExecutableElement values. |
+ * A source object representing the core library (dart:core). |
*/ |
- List<ExecutableElement> _values; |
+ Source _coreLibrarySource; |
/** |
- * Default constructor. |
+ * The object representing the core library. |
*/ |
- MemberMap() : this.con1(10); |
+ ResolvableLibrary _coreLibrary; |
/** |
- * This constructor takes an initial capacity of the map. |
+ * The object used to access the types from the core library. |
+ */ |
+ TypeProvider _typeProvider; |
+ |
+ /** |
+ * A table mapping library sources to the information being maintained for those libraries. |
+ */ |
+ Map<Source, ResolvableLibrary> _libraryMap = new Map<Source, ResolvableLibrary>(); |
+ |
+ /** |
+ * A collection containing the libraries that are being resolved together. |
+ */ |
+ List<ResolvableLibrary> _librariesInCycle; |
+ |
+ /** |
+ * Initialize a newly created library resolver to resolve libraries within the given context. |
* |
- * @param initialCapacity the initial capacity |
+ * @param analysisContext the analysis context in which the library is being analyzed |
*/ |
- MemberMap.con1(int initialCapacity) { |
- _initArrays(initialCapacity); |
+ LibraryResolver2(InternalAnalysisContext analysisContext) { |
+ this.analysisContext = analysisContext; |
+ this._errorListener = new RecordingErrorListener(); |
+ _coreLibrarySource = analysisContext.sourceFactory.forUri(DartSdk.DART_CORE); |
} |
/** |
- * Copy constructor. |
+ * Return the listener to which analysis errors will be reported. |
+ * |
+ * @return the listener to which analysis errors will be reported |
*/ |
- MemberMap.con2(MemberMap memberMap) { |
- _initArrays(memberMap._size + 5); |
- for (int i = 0; i < memberMap._size; i++) { |
- _keys[i] = memberMap._keys[i]; |
- _values[i] = memberMap._values[i]; |
+ RecordingErrorListener get errorListener => _errorListener; |
+ |
+ /** |
+ * Return an array containing information about all of the libraries that were resolved. |
+ * |
+ * @return an array containing the libraries that were resolved |
+ */ |
+ List<ResolvableLibrary> get resolvedLibraries => _librariesInCycle; |
+ |
+ /** |
+ * Resolve the library specified by the given source in the given context. |
+ * |
+ * Note that because Dart allows circular imports between libraries, it is possible that more than |
+ * one library will need to be resolved. In such cases the error listener can receive errors from |
+ * multiple libraries. |
+ * |
+ * @param librarySource the source specifying the defining compilation unit of the library to be |
+ * resolved |
+ * @param fullAnalysis `true` if a full analysis should be performed |
+ * @return the element representing the resolved library |
+ * @throws AnalysisException if the library could not be resolved for some reason |
+ */ |
+ LibraryElement resolveLibrary(Source librarySource, List<ResolvableLibrary> librariesInCycle) { |
+ InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.LibraryResolver.resolveLibrary"); |
+ try { |
+ instrumentation.data3("fullName", librarySource.fullName); |
+ // |
+ // Build the map of libraries that are known. |
+ // |
+ this._librariesInCycle = librariesInCycle; |
+ _libraryMap = _buildLibraryMap(); |
+ ResolvableLibrary targetLibrary = _libraryMap[librarySource]; |
+ _coreLibrary = _libraryMap[_coreLibrarySource]; |
+ instrumentation.metric3("buildLibraryMap", "complete"); |
+ // |
+ // Build the element models representing the libraries being resolved. This is done in three |
+ // steps: |
+ // |
+ // 1. Build the basic element models without making any connections between elements other than |
+ // the basic parent/child relationships. This includes building the elements representing the |
+ // libraries. |
+ // 2. Build the elements for the import and export directives. This requires that we have the |
+ // elements built for the referenced libraries, but because of the possibility of circular |
+ // references needs to happen after all of the library elements have been created. |
+ // 3. Build the rest of the type model by connecting superclasses, mixins, and interfaces. This |
+ // requires that we be able to compute the names visible in the libraries being resolved, |
+ // which in turn requires that we have resolved the import directives. |
+ // |
+ _buildElementModels(); |
+ instrumentation.metric3("buildElementModels", "complete"); |
+ LibraryElement coreElement = _coreLibrary.libraryElement; |
+ if (coreElement == null) { |
+ throw new AnalysisException.con1("Could not resolve dart:core"); |
+ } |
+ _buildDirectiveModels(); |
+ instrumentation.metric3("buildDirectiveModels", "complete"); |
+ _typeProvider = new TypeProviderImpl(coreElement); |
+ _buildTypeHierarchies(); |
+ instrumentation.metric3("buildTypeHierarchies", "complete"); |
+ // |
+ // Perform resolution and type analysis. |
+ // |
+ // TODO(brianwilkerson) Decide whether we want to resolve all of the libraries or whether we |
+ // want to only resolve the target library. The advantage to resolving everything is that we |
+ // have already done part of the work so we'll avoid duplicated effort. The disadvantage of |
+ // resolving everything is that we might do extra work that we don't really care about. Another |
+ // possibility is to add a parameter to this method and punt the decision to the clients. |
+ // |
+ //if (analyzeAll) { |
+ _resolveReferencesAndTypes(); |
+ instrumentation.metric3("resolveReferencesAndTypes", "complete"); |
+ //} else { |
+ // resolveReferencesAndTypes(targetLibrary); |
+ //} |
+ _performConstantEvaluation(); |
+ instrumentation.metric3("performConstantEvaluation", "complete"); |
+ instrumentation.metric2("librariesInCycles", librariesInCycle.length); |
+ for (ResolvableLibrary lib in librariesInCycle) { |
+ instrumentation.metric2("librariesInCycles-CompilationUnitSources-Size", lib.compilationUnitSources.length); |
+ } |
+ return targetLibrary.libraryElement; |
+ } finally { |
+ instrumentation.log(); |
} |
- _size = memberMap._size; |
} |
/** |
- * Given some key, return the ExecutableElement value from the map, if the key does not exist in |
- * the map, `null` is returned. |
+ * Build the element model representing the combinators declared by the given directive. |
+ * |
+ * @param directive the directive that declares the combinators |
+ * @return an array containing the import combinators that were built |
+ */ |
+ List<NamespaceCombinator> _buildCombinators(NamespaceDirective directive) { |
+ List<NamespaceCombinator> combinators = new List<NamespaceCombinator>(); |
+ for (Combinator combinator in directive.combinators) { |
+ if (combinator is HideCombinator) { |
+ HideElementCombinatorImpl hide = new HideElementCombinatorImpl(); |
+ hide.hiddenNames = _getIdentifiers(combinator.hiddenNames); |
+ combinators.add(hide); |
+ } else { |
+ ShowElementCombinatorImpl show = new ShowElementCombinatorImpl(); |
+ show.offset = combinator.offset; |
+ show.end = combinator.end; |
+ show.shownNames = _getIdentifiers((combinator as ShowCombinator).shownNames); |
+ combinators.add(show); |
+ } |
+ } |
+ return new List.from(combinators); |
+ } |
+ |
+ /** |
+ * Every library now has a corresponding [LibraryElement], so it is now possible to resolve |
+ * the import and export directives. |
+ * |
+ * @throws AnalysisException if the defining compilation unit for any of the libraries could not |
+ * be accessed |
+ */ |
+ void _buildDirectiveModels() { |
+ for (ResolvableLibrary library in _librariesInCycle) { |
+ Map<String, PrefixElementImpl> nameToPrefixMap = new Map<String, PrefixElementImpl>(); |
+ List<ImportElement> imports = new List<ImportElement>(); |
+ List<ExportElement> exports = new List<ExportElement>(); |
+ for (Directive directive in library.definingCompilationUnit.directives) { |
+ if (directive is ImportDirective) { |
+ ImportDirective importDirective = directive; |
+ Source importedSource = importDirective.source; |
+ if (importedSource != null && analysisContext.exists(importedSource)) { |
+ // The imported source will be null if the URI in the import directive was invalid. |
+ ResolvableLibrary importedLibrary = _libraryMap[importedSource]; |
+ if (importedLibrary != null) { |
+ ImportElementImpl importElement = new ImportElementImpl(directive.offset); |
+ StringLiteral uriLiteral = importDirective.uri; |
+ if (uriLiteral != null) { |
+ importElement.uriOffset = uriLiteral.offset; |
+ importElement.uriEnd = uriLiteral.end; |
+ } |
+ importElement.uri = importDirective.uriContent; |
+ importElement.combinators = _buildCombinators(importDirective); |
+ LibraryElement importedLibraryElement = importedLibrary.libraryElement; |
+ if (importedLibraryElement != null) { |
+ importElement.importedLibrary = importedLibraryElement; |
+ } |
+ SimpleIdentifier prefixNode = directive.prefix; |
+ if (prefixNode != null) { |
+ importElement.prefixOffset = prefixNode.offset; |
+ String prefixName = prefixNode.name; |
+ PrefixElementImpl prefix = nameToPrefixMap[prefixName]; |
+ if (prefix == null) { |
+ prefix = new PrefixElementImpl(prefixNode); |
+ nameToPrefixMap[prefixName] = prefix; |
+ } |
+ importElement.prefix = prefix; |
+ prefixNode.staticElement = prefix; |
+ } |
+ directive.element = importElement; |
+ imports.add(importElement); |
+ if (analysisContext.computeKindOf(importedSource) != SourceKind.LIBRARY) { |
+ _errorListener.onError(new AnalysisError.con2(library.librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY, [uriLiteral.toSource()])); |
+ } |
+ } |
+ } |
+ } else if (directive is ExportDirective) { |
+ ExportDirective exportDirective = directive; |
+ Source exportedSource = exportDirective.source; |
+ if (exportedSource != null && analysisContext.exists(exportedSource)) { |
+ // The exported source will be null if the URI in the export directive was invalid. |
+ ResolvableLibrary exportedLibrary = _libraryMap[exportedSource]; |
+ if (exportedLibrary != null) { |
+ ExportElementImpl exportElement = new ExportElementImpl(); |
+ StringLiteral uriLiteral = exportDirective.uri; |
+ if (uriLiteral != null) { |
+ exportElement.uriOffset = uriLiteral.offset; |
+ exportElement.uriEnd = uriLiteral.end; |
+ } |
+ exportElement.uri = exportDirective.uriContent; |
+ exportElement.combinators = _buildCombinators(exportDirective); |
+ LibraryElement exportedLibraryElement = exportedLibrary.libraryElement; |
+ if (exportedLibraryElement != null) { |
+ exportElement.exportedLibrary = exportedLibraryElement; |
+ } |
+ directive.element = exportElement; |
+ exports.add(exportElement); |
+ if (analysisContext.computeKindOf(exportedSource) != SourceKind.LIBRARY) { |
+ _errorListener.onError(new AnalysisError.con2(library.librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, [uriLiteral.toSource()])); |
+ } |
+ } |
+ } |
+ } |
+ } |
+ Source librarySource = library.librarySource; |
+ if (!library.explicitlyImportsCore && _coreLibrarySource != librarySource) { |
+ ImportElementImpl importElement = new ImportElementImpl(-1); |
+ importElement.importedLibrary = _coreLibrary.libraryElement; |
+ importElement.synthetic = true; |
+ imports.add(importElement); |
+ } |
+ LibraryElementImpl libraryElement = library.libraryElement; |
+ libraryElement.imports = new List.from(imports); |
+ libraryElement.exports = new List.from(exports); |
+ if (libraryElement.entryPoint == null) { |
+ Namespace namespace = new NamespaceBuilder().createExportNamespaceForLibrary(libraryElement); |
+ Element element = namespace.get(LibraryElementBuilder.ENTRY_POINT_NAME); |
+ if (element is FunctionElement) { |
+ libraryElement.entryPoint = element; |
+ } |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * Build element models for all of the libraries in the current cycle. |
+ * |
+ * @throws AnalysisException if any of the element models cannot be built |
+ */ |
+ void _buildElementModels() { |
+ for (ResolvableLibrary library in _librariesInCycle) { |
+ LibraryElementBuilder builder = new LibraryElementBuilder(analysisContext, errorListener); |
+ LibraryElementImpl libraryElement = builder.buildLibrary2(library); |
+ library.libraryElement = libraryElement; |
+ } |
+ } |
+ |
+ Map<Source, ResolvableLibrary> _buildLibraryMap() { |
+ Map<Source, ResolvableLibrary> libraryMap = new Map<Source, ResolvableLibrary>(); |
+ int libraryCount = _librariesInCycle.length; |
+ for (int i = 0; i < libraryCount; i++) { |
+ ResolvableLibrary library = _librariesInCycle[i]; |
+ library.errorListener = _errorListener; |
+ libraryMap[library.librarySource] = library; |
+ List<ResolvableLibrary> dependencies = library.importsAndExports; |
+ int dependencyCount = dependencies.length; |
+ for (int j = 0; j < dependencyCount; j++) { |
+ ResolvableLibrary dependency = dependencies[j]; |
+ //dependency.setErrorListener(errorListener); |
+ libraryMap[dependency.librarySource] = dependency; |
+ } |
+ } |
+ return libraryMap; |
+ } |
+ |
+ /** |
+ * Resolve the type hierarchy across all of the types declared in the libraries in the current |
+ * cycle. |
+ * |
+ * @throws AnalysisException if any of the type hierarchies could not be resolved |
+ */ |
+ void _buildTypeHierarchies() { |
+ TimeCounter_TimeCounterHandle timeCounter = PerformanceStatistics.resolve.start(); |
+ try { |
+ for (ResolvableLibrary library in _librariesInCycle) { |
+ for (ResolvableCompilationUnit unit in library.resolvableCompilationUnits) { |
+ Source source = unit.source; |
+ CompilationUnit ast = unit.compilationUnit; |
+ TypeResolverVisitor visitor = new TypeResolverVisitor.con4(library, source, _typeProvider); |
+ ast.accept(visitor); |
+ } |
+ } |
+ } finally { |
+ timeCounter.stop(); |
+ } |
+ } |
+ |
+ /** |
+ * Return an array containing the lexical identifiers associated with the nodes in the given list. |
+ * |
+ * @param names the AST nodes representing the identifiers |
+ * @return the lexical identifiers associated with the nodes in the list |
+ */ |
+ List<String> _getIdentifiers(NodeList<SimpleIdentifier> names) { |
+ int count = names.length; |
+ List<String> identifiers = new List<String>(count); |
+ for (int i = 0; i < count; i++) { |
+ identifiers[i] = names[i].name; |
+ } |
+ return identifiers; |
+ } |
+ |
+ /** |
+ * Compute a value for all of the constants in the libraries being analyzed. |
+ */ |
+ void _performConstantEvaluation() { |
+ TimeCounter_TimeCounterHandle timeCounter = PerformanceStatistics.resolve.start(); |
+ try { |
+ ConstantValueComputer computer = new ConstantValueComputer(_typeProvider); |
+ for (ResolvableLibrary library in _librariesInCycle) { |
+ for (ResolvableCompilationUnit unit in library.resolvableCompilationUnits) { |
+ CompilationUnit ast = unit.compilationUnit; |
+ if (ast != null) { |
+ computer.add(ast); |
+ } |
+ } |
+ } |
+ computer.computeValues(); |
+ } finally { |
+ timeCounter.stop(); |
+ } |
+ } |
+ |
+ /** |
+ * Resolve the identifiers and perform type analysis in the libraries in the current cycle. |
+ * |
+ * @throws AnalysisException if any of the identifiers could not be resolved or if any of the |
+ * libraries could not have their types analyzed |
+ */ |
+ void _resolveReferencesAndTypes() { |
+ for (ResolvableLibrary library in _librariesInCycle) { |
+ _resolveReferencesAndTypesInLibrary(library); |
+ } |
+ } |
+ |
+ /** |
+ * Resolve the identifiers and perform type analysis in the given library. |
+ * |
+ * @param library the library to be resolved |
+ * @throws AnalysisException if any of the identifiers could not be resolved or if the types in |
+ * the library cannot be analyzed |
+ */ |
+ void _resolveReferencesAndTypesInLibrary(ResolvableLibrary library) { |
+ TimeCounter_TimeCounterHandle timeCounter = PerformanceStatistics.resolve.start(); |
+ try { |
+ for (ResolvableCompilationUnit unit in library.resolvableCompilationUnits) { |
+ Source source = unit.source; |
+ CompilationUnit ast = unit.compilationUnit; |
+ ast.accept(new VariableResolverVisitor.con3(library, source, _typeProvider)); |
+ ResolverVisitor visitor = new ResolverVisitor.con4(library, source, _typeProvider); |
+ ast.accept(visitor); |
+ for (ProxyConditionalAnalysisError conditionalCode in visitor.proxyConditionalAnalysisErrors) { |
+ if (conditionalCode.shouldIncludeErrorCode()) { |
+ visitor.reportError(conditionalCode.analysisError); |
+ } |
+ } |
+ } |
+ } finally { |
+ timeCounter.stop(); |
+ } |
+ // Angular |
+ timeCounter = PerformanceStatistics.angular.start(); |
+ try { |
+ for (ResolvableCompilationUnit unit in library.resolvableCompilationUnits) { |
+ Source source = unit.source; |
+ CompilationUnit ast = unit.compilationUnit; |
+ new AngularCompilationUnitBuilder(_errorListener, source, ast).build(); |
+ } |
+ } finally { |
+ timeCounter.stop(); |
+ } |
+ } |
+} |
+ |
+/** |
+ * This class is used to replace uses of `HashMap<String, ExecutableElement>` which are not as |
+ * performant as this class. |
+ */ |
+class MemberMap { |
+ /** |
+ * The current size of this map. |
+ */ |
+ int _size = 0; |
+ |
+ /** |
+ * The array of keys. |
+ */ |
+ List<String> _keys; |
+ |
+ /** |
+ * The array of ExecutableElement values. |
+ */ |
+ List<ExecutableElement> _values; |
+ |
+ /** |
+ * Default constructor. |
+ */ |
+ MemberMap() : this.con1(10); |
+ |
+ /** |
+ * This constructor takes an initial capacity of the map. |
+ * |
+ * @param initialCapacity the initial capacity |
+ */ |
+ MemberMap.con1(int initialCapacity) { |
+ _initArrays(initialCapacity); |
+ } |
+ |
+ /** |
+ * Copy constructor. |
+ */ |
+ MemberMap.con2(MemberMap memberMap) { |
+ _initArrays(memberMap._size + 5); |
+ for (int i = 0; i < memberMap._size; i++) { |
+ _keys[i] = memberMap._keys[i]; |
+ _values[i] = memberMap._values[i]; |
+ } |
+ _size = memberMap._size; |
+ } |
+ |
+ /** |
+ * Given some key, return the ExecutableElement value from the map, if the key does not exist in |
+ * the map, `null` is returned. |
+ * |
+ * @param key some key to look up in the map |
+ * @return the associated ExecutableElement value from the map, if the key does not exist in the |
+ * map, `null` is returned |
+ */ |
+ ExecutableElement get(String key) { |
+ for (int i = 0; i < _size; i++) { |
+ if (_keys[i] != null && _keys[i] == key) { |
+ return _values[i]; |
+ } |
+ } |
+ return null; |
+ } |
+ |
+ /** |
+ * Get and return the key at the specified location. If the key/value pair has been removed from |
+ * the set, then `null` is returned. |
+ * |
+ * @param i some non-zero value less than size |
+ * @return the key at the passed index |
+ * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than |
+ * zero or greater than or equal to the capacity of the arrays |
+ */ |
+ String getKey(int i) => _keys[i]; |
+ |
+ /** |
+ * The size of the map. |
+ * |
+ * @return the size of the map. |
+ */ |
+ int get size => _size; |
+ |
+ /** |
+ * Get and return the ExecutableElement at the specified location. If the key/value pair has been |
+ * removed from the set, then then `null` is returned. |
+ * |
+ * @param i some non-zero value less than size |
+ * @return the key at the passed index |
+ * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than |
+ * zero or greater than or equal to the capacity of the arrays |
+ */ |
+ ExecutableElement getValue(int i) => _values[i]; |
+ |
+ /** |
+ * Given some key/value pair, store the pair in the map. If the key exists already, then the new |
+ * value overrides the old value. |
+ * |
+ * @param key the key to store in the map |
+ * @param value the ExecutableElement value to store in the map |
+ */ |
+ void put(String key, ExecutableElement value) { |
+ // If we already have a value with this key, override the value |
+ for (int i = 0; i < _size; i++) { |
+ if (_keys[i] != null && _keys[i] == key) { |
+ _values[i] = value; |
+ return; |
+ } |
+ } |
+ // If needed, double the size of our arrays and copy values over in both arrays |
+ if (_size == _keys.length) { |
+ int newArrayLength = _size * 2; |
+ List<String> keys_new_array = new List<String>(newArrayLength); |
+ List<ExecutableElement> values_new_array = new List<ExecutableElement>(newArrayLength); |
+ for (int i = 0; i < _size; i++) { |
+ keys_new_array[i] = _keys[i]; |
+ } |
+ for (int i = 0; i < _size; i++) { |
+ values_new_array[i] = _values[i]; |
+ } |
+ _keys = keys_new_array; |
+ _values = values_new_array; |
+ } |
+ // Put new value at end of array |
+ _keys[_size] = key; |
+ _values[_size] = value; |
+ _size++; |
+ } |
+ |
+ /** |
+ * Given some [String] key, this method replaces the associated key and value pair with |
+ * `null`. The size is not decremented with this call, instead it is expected that the users |
+ * check for `null`. |
+ * |
+ * @param key the key of the key/value pair to remove from the map |
+ */ |
+ void remove(String key) { |
+ for (int i = 0; i < _size; i++) { |
+ if (_keys[i] == key) { |
+ _keys[i] = null; |
+ _values[i] = null; |
+ return; |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * Sets the ExecutableElement at the specified location. |
+ * |
+ * @param i some non-zero value less than size |
+ * @param value the ExecutableElement value to store in the map |
+ */ |
+ void setValue(int i, ExecutableElement value) { |
+ _values[i] = value; |
+ } |
+ |
+ /** |
+ * Initializes [keys] and [values]. |
+ */ |
+ void _initArrays(int initialCapacity) { |
+ _keys = new List<String>(initialCapacity); |
+ _values = new List<ExecutableElement>(initialCapacity); |
+ } |
+} |
+ |
+/** |
+ * This class is a wrapper for an [AnalysisError] which can also be queried after resolution |
+ * to find out if the error should actually be reported. In this case, these errors are conditional |
+ * on the non-existence of an `@proxy` annotation. |
+ * |
+ * If we have other conditional error codes in the future, we should have this class implement some |
+ * ConditionalErrorCode so that after resolution, a list of ConditionalErrorCode can be visited |
+ * instead of multiple lists of *ConditionalErrorCodes. |
+ */ |
+class ProxyConditionalAnalysisError { |
+ /** |
+ * The enclosing [ClassElement], this is what will determine if the error code should, or |
+ * should not, be generated on the source. |
+ */ |
+ Element _enclosingElement; |
+ |
+ /** |
+ * The conditional analysis error. |
+ */ |
+ AnalysisError analysisError; |
+ |
+ /** |
+ * Instantiate a new [ProxyConditionalAnalysisError] with some enclosing element and the |
+ * conditional analysis error. |
+ * |
+ * @param enclosingElement the enclosing element |
+ * @param analysisError the conditional analysis error |
+ */ |
+ ProxyConditionalAnalysisError(Element enclosingElement, AnalysisError analysisError) { |
+ this._enclosingElement = enclosingElement; |
+ this.analysisError = analysisError; |
+ } |
+ |
+ /** |
+ * Return `true` iff the enclosing class has the proxy annotation. |
+ * |
+ * @return `true` iff the enclosing class has the proxy annotation |
+ */ |
+ bool shouldIncludeErrorCode() { |
+ if (_enclosingElement is ClassElement) { |
+ return !(_enclosingElement as ClassElement).isOrInheritsProxy; |
+ } |
+ return true; |
+ } |
+} |
+ |
+/** |
+ * Instances of the class `Library` represent the data about a single library during the |
+ * resolution of some (possibly different) library. They are not intended to be used except during |
+ * the resolution process. |
+ */ |
+class ResolvableLibrary { |
+ /** |
+ * The source specifying the defining compilation unit of this library. |
+ */ |
+ Source librarySource; |
+ |
+ /** |
+ * A list containing all of the libraries that are imported into this library. |
+ */ |
+ List<ResolvableLibrary> _importedLibraries = _EMPTY_ARRAY; |
+ |
+ /** |
+ * A flag indicating whether this library explicitly imports core. |
+ */ |
+ bool explicitlyImportsCore = false; |
+ |
+ /** |
+ * An array containing all of the libraries that are exported from this library. |
+ */ |
+ List<ResolvableLibrary> _exportedLibraries = _EMPTY_ARRAY; |
+ |
+ /** |
+ * An array containing the compilation units that comprise this library. The defining compilation |
+ * unit is always first. |
+ */ |
+ List<ResolvableCompilationUnit> _compilationUnits; |
+ |
+ /** |
+ * The library element representing this library. |
+ */ |
+ LibraryElementImpl _libraryElement; |
+ |
+ /** |
+ * The listener to which analysis errors will be reported. |
+ */ |
+ AnalysisErrorListener _errorListener; |
+ |
+ /** |
+ * The inheritance manager which is used for member lookups in this library. |
+ */ |
+ InheritanceManager _inheritanceManager; |
+ |
+ /** |
+ * An empty array that can be used to initialize lists of libraries. |
+ */ |
+ static List<ResolvableLibrary> _EMPTY_ARRAY = new List<ResolvableLibrary>(0); |
+ |
+ /** |
+ * The library scope used when resolving elements within this library's compilation units. |
+ */ |
+ LibraryScope _libraryScope; |
+ |
+ /** |
+ * Initialize a newly created data holder that can maintain the data associated with a library. |
+ * |
+ * @param librarySource the source specifying the defining compilation unit of this library |
+ * @param errorListener the listener to which analysis errors will be reported |
+ */ |
+ ResolvableLibrary(Source librarySource) { |
+ this.librarySource = librarySource; |
+ } |
+ |
+ /** |
+ * Return the AST structure associated with the given source, or `null` if the source does |
+ * not represent a compilation unit that is included in this library. |
+ * |
+ * @param source the source representing the compilation unit whose AST is to be returned |
+ * @return the AST structure associated with the given source |
+ * @throws AnalysisException if an AST structure could not be created for the compilation unit |
+ */ |
+ CompilationUnit getAST(Source source) { |
+ int count = _compilationUnits.length; |
+ for (int i = 0; i < count; i++) { |
+ if (_compilationUnits[i].source == source) { |
+ return _compilationUnits[i].compilationUnit; |
+ } |
+ } |
+ return null; |
+ } |
+ |
+ /** |
+ * 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 { |
+ int count = _compilationUnits.length; |
+ List<CompilationUnit> units = new List<CompilationUnit>(count); |
+ for (int i = 0; i < count; i++) { |
+ units[i] = _compilationUnits[i].compilationUnit; |
+ } |
+ return units; |
+ } |
+ |
+ /** |
+ * Return an array containing the sources for the compilation units in this library, including the |
+ * defining compilation unit. |
+ * |
+ * @return the sources for the compilation units in this library |
+ */ |
+ List<Source> get compilationUnitSources { |
+ int count = _compilationUnits.length; |
+ List<Source> sources = new List<Source>(count); |
+ for (int i = 0; i < count; i++) { |
+ sources[i] = _compilationUnits[i].source; |
+ } |
+ return sources; |
+ } |
+ |
+ /** |
+ * Return the AST structure associated with the defining compilation unit for this library. |
+ * |
+ * @return the AST structure associated with the defining compilation unit for this library |
+ * @throws AnalysisException if an AST structure could not be created for the defining compilation |
+ * unit |
+ */ |
+ CompilationUnit get definingCompilationUnit => _compilationUnits[0].compilationUnit; |
+ |
+ /** |
+ * Return an array containing the libraries that are exported from this library. |
* |
- * @param key some key to look up in the map |
- * @return the associated ExecutableElement value from the map, if the key does not exist in the |
- * map, `null` is returned |
+ * @return an array containing the libraries that are exported from this library |
*/ |
- ExecutableElement get(String key) { |
- for (int i = 0; i < _size; i++) { |
- if (_keys[i] != null && _keys[i] == key) { |
- return _values[i]; |
- } |
- } |
- return null; |
- } |
+ List<ResolvableLibrary> get exports => _exportedLibraries; |
/** |
- * Get and return the key at the specified location. If the key/value pair has been removed from |
- * the set, then `null` is returned. |
+ * Return an array containing the libraries that are imported into this library. |
* |
- * @param i some non-zero value less than size |
- * @return the key at the passed index |
- * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than |
- * zero or greater than or equal to the capacity of the arrays |
+ * @return an array containing the libraries that are imported into this library |
*/ |
- String getKey(int i) => _keys[i]; |
+ List<ResolvableLibrary> get imports => _importedLibraries; |
/** |
- * The size of the map. |
+ * Return an array containing the libraries that are either imported or exported from this |
+ * library. |
* |
- * @return the size of the map. |
+ * @return the libraries that are either imported or exported from this library |
*/ |
- int get size => _size; |
+ List<ResolvableLibrary> get importsAndExports { |
+ Set<ResolvableLibrary> libraries = new Set<ResolvableLibrary>(); |
+ for (ResolvableLibrary library in _importedLibraries) { |
+ libraries.add(library); |
+ } |
+ for (ResolvableLibrary library in _exportedLibraries) { |
+ libraries.add(library); |
+ } |
+ return new List.from(libraries); |
+ } |
/** |
- * Get and return the ExecutableElement at the specified location. If the key/value pair has been |
- * removed from the set, then then `null` is returned. |
+ * Return the inheritance manager for this library. |
* |
- * @param i some non-zero value less than size |
- * @return the key at the passed index |
- * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passed index is less than |
- * zero or greater than or equal to the capacity of the arrays |
+ * @return the inheritance manager for this library |
*/ |
- ExecutableElement getValue(int i) => _values[i]; |
+ InheritanceManager get inheritanceManager { |
+ if (_inheritanceManager == null) { |
+ return _inheritanceManager = new InheritanceManager(_libraryElement); |
+ } |
+ return _inheritanceManager; |
+ } |
/** |
- * Given some key/value pair, store the pair in the map. If the key exists already, then the new |
- * value overrides the old value. |
+ * Return the library element representing this library, creating it if necessary. |
* |
- * @param key the key to store in the map |
- * @param value the ExecutableElement value to store in the map |
+ * @return the library element representing this library |
*/ |
- void put(String key, ExecutableElement value) { |
- // If we already have a value with this key, override the value |
- for (int i = 0; i < _size; i++) { |
- if (_keys[i] != null && _keys[i] == key) { |
- _values[i] = value; |
- return; |
- } |
- } |
- // If needed, double the size of our arrays and copy values over in both arrays |
- if (_size == _keys.length) { |
- int newArrayLength = _size * 2; |
- List<String> keys_new_array = new List<String>(newArrayLength); |
- List<ExecutableElement> values_new_array = new List<ExecutableElement>(newArrayLength); |
- for (int i = 0; i < _size; i++) { |
- keys_new_array[i] = _keys[i]; |
- } |
- for (int i = 0; i < _size; i++) { |
- values_new_array[i] = _values[i]; |
- } |
- _keys = keys_new_array; |
- _values = values_new_array; |
+ LibraryElementImpl get libraryElement => _libraryElement; |
+ |
+ /** |
+ * Return the library scope used when resolving elements within this library's compilation units. |
+ * |
+ * @return the library scope used when resolving elements within this library's compilation units |
+ */ |
+ LibraryScope get libraryScope { |
+ if (_libraryScope == null) { |
+ _libraryScope = new LibraryScope(_libraryElement, _errorListener); |
} |
- // Put new value at end of array |
- _keys[_size] = key; |
- _values[_size] = value; |
- _size++; |
+ return _libraryScope; |
} |
/** |
- * Given some [String] key, this method replaces the associated key and value pair with |
- * `null`. The size is not decremented with this call, instead it is expected that the users |
- * check for `null`. |
+ * Return the modification time associated with the given source. |
* |
- * @param key the key of the key/value pair to remove from the map |
+ * @param source the source representing the compilation unit whose modification time is to be |
+ * returned |
+ * @return the modification time associated with the given source |
+ * @throws AnalysisException if an AST structure could not be created for the compilation unit |
*/ |
- void remove(String key) { |
- for (int i = 0; i < _size; i++) { |
- if (_keys[i] == key) { |
- _keys[i] = null; |
- _values[i] = null; |
- return; |
+ int getModificationTime(Source source) { |
+ int count = _compilationUnits.length; |
+ for (int i = 0; i < count; i++) { |
+ if (source == _compilationUnits[i].source) { |
+ return _compilationUnits[i].modificationTime; |
} |
} |
+ return -1; |
} |
/** |
- * Sets the ExecutableElement at the specified location. |
+ * Return an array containing the compilation units that comprise this library. The defining |
+ * compilation unit is always first. |
* |
- * @param i some non-zero value less than size |
- * @param value the ExecutableElement value to store in the map |
+ * @return the compilation units that comprise this library |
*/ |
- void setValue(int i, ExecutableElement value) { |
- _values[i] = value; |
- } |
+ List<ResolvableCompilationUnit> get resolvableCompilationUnits => _compilationUnits; |
/** |
- * Initializes [keys] and [values]. |
+ * Set the compilation unit in this library to the given compilation units. The defining |
+ * compilation unit must be the first element of the array. |
+ * |
+ * @param units the compilation units in this library |
*/ |
- void _initArrays(int initialCapacity) { |
- _keys = new List<String>(initialCapacity); |
- _values = new List<ExecutableElement>(initialCapacity); |
+ void set resolvableCompilationUnits(List<ResolvableCompilationUnit> units) { |
+ _compilationUnits = units; |
} |
-} |
-/** |
- * This class is a wrapper for an [AnalysisError] which can also be queried after resolution |
- * to find out if the error should actually be reported. In this case, these errors are conditional |
- * on the non-existence of an `@proxy` annotation. |
- * |
- * If we have other conditional error codes in the future, we should have this class implement some |
- * ConditionalErrorCode so that after resolution, a list of ConditionalErrorCode can be visited |
- * instead of multiple lists of *ConditionalErrorCodes. |
- */ |
-class ProxyConditionalAnalysisError { |
/** |
- * The enclosing [ClassElement], this is what will determine if the error code should, or |
- * should not, be generated on the source. |
+ * Set the listener to which analysis errors will be reported to be the given listener. |
+ * |
+ * @param errorListener the listener to which analysis errors will be reported |
*/ |
- Element _enclosingElement; |
+ void set errorListener(AnalysisErrorListener errorListener) { |
+ this._errorListener = errorListener; |
+ } |
/** |
- * The conditional analysis error. |
+ * Set the libraries that are exported by this library to be those in the given array. |
+ * |
+ * @param exportedLibraries the libraries that are exported by this library |
*/ |
- AnalysisError analysisError; |
+ void set exportedLibraries(List<ResolvableLibrary> exportedLibraries) { |
+ this._exportedLibraries = exportedLibraries; |
+ } |
/** |
- * Instantiate a new [ProxyConditionalAnalysisError] with some enclosing element and the |
- * conditional analysis error. |
+ * Set the libraries that are imported into this library to be those in the given array. |
* |
- * @param enclosingElement the enclosing element |
- * @param analysisError the conditional analysis error |
+ * @param importedLibraries the libraries that are imported into this library |
*/ |
- ProxyConditionalAnalysisError(Element enclosingElement, AnalysisError analysisError) { |
- this._enclosingElement = enclosingElement; |
- this.analysisError = analysisError; |
+ void set importedLibraries(List<ResolvableLibrary> importedLibraries) { |
+ this._importedLibraries = importedLibraries; |
} |
/** |
- * Return `true` iff the enclosing class has the proxy annotation. |
+ * Set the library element representing this library to the given library element. |
* |
- * @return `true` iff the enclosing class has the proxy annotation |
+ * @param libraryElement the library element representing this library |
*/ |
- bool shouldIncludeErrorCode() { |
- if (_enclosingElement is ClassElement) { |
- return !(_enclosingElement as ClassElement).isOrInheritsProxy; |
+ void set libraryElement(LibraryElementImpl libraryElement) { |
+ this._libraryElement = libraryElement; |
+ if (_inheritanceManager != null) { |
+ _inheritanceManager.libraryElement = libraryElement; |
} |
- return true; |
} |
+ |
+ @override |
+ String toString() => librarySource.shortName; |
} |
/** |
@@ -10256,6 +11009,19 @@ class ResolverVisitor extends ScopedVisitor { |
} |
/** |
+ * Initialize a newly created visitor to resolve the nodes in a compilation unit. |
+ * |
+ * @param library the library containing the compilation unit being resolved |
+ * @param source the source representing the compilation unit being visited |
+ * @param typeProvider the object used to access the types from the core library |
+ */ |
+ ResolverVisitor.con4(ResolvableLibrary library, Source source, TypeProvider typeProvider) : super.con4(library, source, typeProvider) { |
+ this._inheritanceManager = library.inheritanceManager; |
+ this._elementResolver = new ElementResolver(this); |
+ this._typeAnalyzer = new StaticTypeAnalyzer(this); |
+ } |
+ |
+ /** |
* Return the object keeping track of which elements have had their types overridden. |
* |
* @return the object keeping track of which elements have had their types overridden |
@@ -10992,7 +11758,7 @@ class ResolverVisitor extends ScopedVisitor { |
* @param token the token specifying the location of the error |
* @param arguments the arguments to the error, used to compose the error message |
*/ |
- void reportErrorProxyConditionalAnalysisError(Element enclosingElement, ErrorCode errorCode, sc.Token token, List<Object> arguments) { |
+ void reportProxyConditionalErrorForToken(Element enclosingElement, ErrorCode errorCode, sc.Token token, List<Object> arguments) { |
_proxyConditionalAnalysisErrors.add(new ProxyConditionalAnalysisError(enclosingElement, new AnalysisError.con2(source, token.offset, token.length, errorCode, arguments))); |
} |
@@ -11147,6 +11913,11 @@ class ResolverVisitor extends ScopedVisitor { |
return; |
} |
FunctionType expectedClosureType = mayByFunctionType as FunctionType; |
+ // If the expectedClosureType is not more specific than the static type, return. |
+ DartType staticClosureType = (closure.element != null ? closure.element.type : null) as DartType; |
+ if (staticClosureType != null && !expectedClosureType.isMoreSpecificThan(staticClosureType)) { |
+ return; |
+ } |
// set propagated type for the closure |
closure.propagatedType = expectedClosureType; |
// set inferred types for parameters |
@@ -11553,6 +12324,22 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
} |
/** |
+ * Initialize a newly created visitor to resolve the nodes in a compilation unit. |
+ * |
+ * @param library the library containing the compilation unit being resolved |
+ * @param source the source representing the compilation unit being visited |
+ * @param typeProvider the object used to access the types from the core library |
+ */ |
+ ScopedVisitor.con4(ResolvableLibrary library, Source source, TypeProvider typeProvider) { |
+ this._definingLibrary = library.libraryElement; |
+ this.source = source; |
+ LibraryScope libraryScope = library.libraryScope; |
+ this._errorListener = libraryScope.errorListener; |
+ this._nameScope = libraryScope; |
+ this.typeProvider = typeProvider; |
+ } |
+ |
+ /** |
* Return the library element for the library containing the compilation unit being resolved. |
* |
* @return the library element for the library containing the compilation unit being resolved |
@@ -11627,9 +12414,14 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
@override |
Object visitClassDeclaration(ClassDeclaration node) { |
+ ClassElement classElement = node.element; |
Scope outerScope = _nameScope; |
try { |
- _nameScope = new ClassScope(_nameScope, node.element); |
+ if (classElement == null) { |
+ AnalysisEngine.instance.logger.logInformation2("Missing element for constructor ${node.name.name} in ${definingLibrary.source.fullName}", new JavaException()); |
+ } else { |
+ _nameScope = new ClassScope(_nameScope, classElement); |
+ } |
visitClassDeclarationInScope(node); |
} finally { |
_nameScope = outerScope; |
@@ -11651,9 +12443,23 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
@override |
Object visitConstructorDeclaration(ConstructorDeclaration node) { |
+ ConstructorElement constructorElement = node.element; |
Scope outerScope = _nameScope; |
try { |
- _nameScope = new FunctionScope(_nameScope, node.element); |
+ if (constructorElement == null) { |
+ JavaStringBuilder builder = new JavaStringBuilder(); |
+ builder.append("Missing element for constructor "); |
+ builder.append(node.returnType.name); |
+ if (node.name != null) { |
+ builder.append("."); |
+ builder.append(node.name.name); |
+ } |
+ builder.append(" in "); |
+ builder.append(definingLibrary.source.fullName); |
+ AnalysisEngine.instance.logger.logInformation2(builder.toString(), new JavaException()); |
+ } else { |
+ _nameScope = new FunctionScope(_nameScope, constructorElement); |
+ } |
super.visitConstructorDeclaration(node); |
} finally { |
_nameScope = outerScope; |
@@ -11729,16 +12535,20 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
@override |
Object visitFunctionDeclaration(FunctionDeclaration node) { |
- ExecutableElement function = node.element; |
+ ExecutableElement functionElement = node.element; |
Scope outerScope = _nameScope; |
try { |
- _nameScope = new FunctionScope(_nameScope, function); |
+ if (functionElement == null) { |
+ AnalysisEngine.instance.logger.logInformation2("Missing element for top-level function ${node.name.name} in ${definingLibrary.source.fullName}", new JavaException()); |
+ } else { |
+ _nameScope = new FunctionScope(_nameScope, functionElement); |
+ } |
super.visitFunctionDeclaration(node); |
} finally { |
_nameScope = outerScope; |
} |
- if (function.enclosingElement is! CompilationUnitElement) { |
- _nameScope.define(function); |
+ if (functionElement.enclosingElement is! CompilationUnitElement) { |
+ _nameScope.define(functionElement); |
} |
return null; |
} |
@@ -11753,6 +12563,19 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
try { |
ExecutableElement functionElement = node.element; |
if (functionElement == null) { |
+ JavaStringBuilder builder = new JavaStringBuilder(); |
+ builder.append("Missing element for function "); |
+ AstNode parent = node.parent; |
+ while (parent != null) { |
+ if (parent is Declaration) { |
+ Element parentElement = (parent as Declaration).element; |
+ builder.append(parentElement == null ? "<unknown> " : ("${parentElement.name} ")); |
+ } |
+ parent = parent.parent; |
+ } |
+ builder.append("in "); |
+ builder.append(definingLibrary.source.fullName); |
+ AnalysisEngine.instance.logger.logInformation2(builder.toString(), new JavaException()); |
} else { |
_nameScope = new FunctionScope(_nameScope, functionElement); |
} |
@@ -11799,7 +12622,12 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
Object visitMethodDeclaration(MethodDeclaration node) { |
Scope outerScope = _nameScope; |
try { |
- _nameScope = new FunctionScope(_nameScope, node.element); |
+ ExecutableElement methodElement = node.element; |
+ if (methodElement == null) { |
+ AnalysisEngine.instance.logger.logInformation2("Missing element for method ${node.name.name} in ${definingLibrary.source.fullName}", new JavaException()); |
+ } else { |
+ _nameScope = new FunctionScope(_nameScope, methodElement); |
+ } |
super.visitMethodDeclaration(node); |
} finally { |
_nameScope = outerScope; |
@@ -14601,6 +15429,17 @@ class TypeResolverVisitor extends ScopedVisitor { |
_dynamicType = typeProvider.dynamicType; |
} |
+ /** |
+ * Initialize a newly created visitor to resolve the nodes in a compilation unit. |
+ * |
+ * @param library the library containing the compilation unit being resolved |
+ * @param source the source representing the compilation unit being visited |
+ * @param typeProvider the object used to access the types from the core library |
+ */ |
+ TypeResolverVisitor.con4(ResolvableLibrary library, Source source, TypeProvider typeProvider) : super.con4(library, source, typeProvider) { |
+ _dynamicType = typeProvider.dynamicType; |
+ } |
+ |
@override |
Object visitCatchClause(CatchClause node) { |
super.visitCatchClause(node); |
@@ -15652,6 +16491,15 @@ class VariableResolverVisitor extends ScopedVisitor { |
*/ |
VariableResolverVisitor.con2(LibraryElement definingLibrary, Source source, TypeProvider typeProvider, Scope nameScope, AnalysisErrorListener errorListener) : super.con3(definingLibrary, source, typeProvider, nameScope, errorListener); |
+ /** |
+ * Initialize a newly created visitor to resolve the nodes in a compilation unit. |
+ * |
+ * @param library the library containing the compilation unit being resolved |
+ * @param source the source representing the compilation unit being visited |
+ * @param typeProvider the object used to access the types from the core library |
+ */ |
+ VariableResolverVisitor.con3(ResolvableLibrary library, Source source, TypeProvider typeProvider) : super.con4(library, source, typeProvider); |
+ |
@override |
Object visitFunctionDeclaration(FunctionDeclaration node) { |
ExecutableElement outerFunction = _enclosingFunction; |
@@ -15743,6 +16591,9 @@ class ClassScope extends EnclosedScope { |
* @param typeElement the element representing the type represented by this scope |
*/ |
ClassScope(Scope enclosingScope, ClassElement typeElement) : super(new EnclosedScope(enclosingScope)) { |
+ if (typeElement == null) { |
+ throw new IllegalArgumentException("class element cannot be null"); |
+ } |
_defineTypeParameters(typeElement); |
_defineMembers(typeElement); |
} |
@@ -15871,6 +16722,9 @@ class FunctionScope extends EnclosedScope { |
* @param functionElement the element representing the type represented by this scope |
*/ |
FunctionScope(Scope enclosingScope, ExecutableElement functionElement) : super(new EnclosedScope(enclosingScope)) { |
+ if (functionElement == null) { |
+ throw new IllegalArgumentException("function element cannot be null"); |
+ } |
this._functionElement = functionElement; |
} |
@@ -16772,21 +17626,41 @@ class ScopeBuilder { |
} |
Scope scope = _scopeForAstNode(parent); |
if (node is ClassDeclaration) { |
- scope = new ClassScope(scope, node.element); |
+ ClassElement element = node.element; |
+ if (element == null) { |
+ throw new AnalysisException.con1("Cannot build a scope for an unresolved class"); |
+ } |
+ scope = new ClassScope(scope, element); |
} else if (node is ClassTypeAlias) { |
- scope = new ClassScope(scope, node.element); |
+ ClassElement element = node.element; |
+ if (element == null) { |
+ throw new AnalysisException.con1("Cannot build a scope for an unresolved class type alias"); |
+ } |
+ scope = new ClassScope(scope, element); |
} else if (node is ConstructorDeclaration) { |
- FunctionScope functionScope = new FunctionScope(scope, node.element); |
+ ConstructorElement element = node.element; |
+ if (element == null) { |
+ throw new AnalysisException.con1("Cannot build a scope for an unresolved constructor"); |
+ } |
+ FunctionScope functionScope = new FunctionScope(scope, element); |
functionScope.defineParameters(); |
scope = functionScope; |
} else if (node is FunctionDeclaration) { |
- FunctionScope functionScope = new FunctionScope(scope, node.element); |
+ ExecutableElement element = node.element; |
+ if (element == null) { |
+ throw new AnalysisException.con1("Cannot build a scope for an unresolved function"); |
+ } |
+ FunctionScope functionScope = new FunctionScope(scope, element); |
functionScope.defineParameters(); |
scope = functionScope; |
} else if (node is FunctionTypeAlias) { |
scope = new FunctionTypeScope(scope, node.element); |
} else if (node is MethodDeclaration) { |
- FunctionScope functionScope = new FunctionScope(scope, node.element); |
+ ExecutableElement element = node.element; |
+ if (element == null) { |
+ throw new AnalysisException.con1("Cannot build a scope for an unresolved method"); |
+ } |
+ FunctionScope functionScope = new FunctionScope(scope, element); |
functionScope.defineParameters(); |
scope = functionScope; |
} |
@@ -17507,6 +18381,8 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
@override |
Object visitClassTypeAlias(ClassTypeAlias node) { |
_checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME); |
+ _checkForExtendsDisallowedClassInTypeAlias(node); |
+ _checkForImplementsDisallowedClass(node.implementsClause); |
_checkForAllMixinErrorCodes(node.withClause); |
ClassElement outerClassElement = _enclosingClass; |
try { |
@@ -19741,6 +20617,20 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
} |
/** |
+ * This verifies that the passed type alias does not extend classes such as num or String. |
+ * |
+ * @param node the extends clause to test |
+ * @return `true` if and only if an error code is generated on the passed node |
+ * @see CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS |
+ */ |
+ bool _checkForExtendsDisallowedClassInTypeAlias(ClassTypeAlias node) { |
+ if (node == null) { |
+ return false; |
+ } |
+ return _checkForExtendsOrImplementsDisallowedClass(node.superclass, CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS); |
+ } |
+ |
+ /** |
* This verifies that the passed type name does not extend or implement classes such as 'num' or |
* 'String'. |
* |