| // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:collection'; |
| |
| import 'package:analyzer/dart/analysis/session.dart'; |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/dart/element/handle.dart'; |
| import 'package:analyzer/src/dart/element/member.dart'; |
| import 'package:analyzer/src/dart/element/type.dart'; |
| import 'package:analyzer/src/generated/engine.dart'; |
| import 'package:analyzer/src/generated/resolver.dart'; |
| import 'package:analyzer/src/generated/source_io.dart'; |
| import 'package:analyzer/src/generated/testing/ast_test_factory.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:analyzer/src/summary/expr_builder.dart'; |
| import 'package:analyzer/src/summary/format.dart'; |
| import 'package:analyzer/src/summary/idl.dart'; |
| import 'package:analyzer/src/summary/summary_sdk.dart'; |
| |
| /** |
| * Expando for marking types with implicit type arguments, which are the same as |
| * type parameter bounds (in strong mode), or `dynamic` (in spec mode). |
| * |
| * If a type is associated with a non-null value in this expando, then it has |
| * implicit type arguments. |
| */ |
| final _typesWithImplicitTypeArguments = new Expando(); |
| |
| /// An instance of [LibraryResynthesizer] is responsible for resynthesizing the |
| /// elements in a single library from that library's summary. |
| abstract class LibraryResynthesizer { |
| /// Builds the export namespace for the library by aggregating together its |
| /// public namespace and export names. |
| Namespace buildExportNamespace(); |
| |
| /// Builds the public namespace for the library. |
| Namespace buildPublicNamespace(); |
| } |
| |
| /// [LibraryResynthesizerContextMixin] contains methods useful for implementing |
| /// the [LibraryResynthesizerContext] interface. |
| abstract class LibraryResynthesizerContextMixin |
| implements LibraryResynthesizerContext { |
| /// Gets the associated [LibraryResynthesizer]. |
| LibraryResynthesizer get resynthesizer; |
| |
| @override |
| Namespace buildExportNamespace() => resynthesizer.buildExportNamespace(); |
| |
| @override |
| Namespace buildPublicNamespace() => resynthesizer.buildPublicNamespace(); |
| } |
| |
| /// [LibraryResynthesizerMixin] contains methods useful for implementing the |
| /// [LibraryResynthesizer] interface. |
| abstract class LibraryResynthesizerMixin implements LibraryResynthesizer { |
| /// Gets the library element being resynthesized. |
| LibraryElement get library; |
| |
| /// Gets the list of export names created during summary linking. |
| List<LinkedExportName> get linkedExportNames; |
| |
| /// Builds or retrieves an [Element] for the entity referred to by the given |
| /// [exportName]. |
| Element buildExportName(LinkedExportName exportName); |
| |
| @override |
| Namespace buildExportNamespace() { |
| Namespace publicNamespace = library.publicNamespace; |
| List<LinkedExportName> exportNames = linkedExportNames; |
| Map<String, Element> definedNames = new HashMap<String, Element>(); |
| // Start by populating all the public names from [publicNamespace]. |
| publicNamespace.definedNames.forEach((String name, Element element) { |
| definedNames[name] = element; |
| }); |
| // Add all the names from [exportNames]. |
| for (LinkedExportName exportName in exportNames) { |
| String name = exportName.name; |
| if (!definedNames.containsKey(name)) { |
| definedNames[name] = buildExportName(exportName); |
| } |
| } |
| return new Namespace(definedNames); |
| } |
| |
| @override |
| Namespace buildPublicNamespace() => |
| new NamespaceBuilder().createPublicNamespaceForLibrary(library); |
| } |
| |
| class RecursiveInstantiateToBounds {} |
| |
| /// Data structure used during resynthesis to record all the information that is |
| /// known about how to resynthesize a single entry in [LinkedUnit.references] |
| /// (and its associated entry in [UnlinkedUnit.references], if it exists). |
| abstract class ReferenceInfo { |
| /// The element referred to by this reference, or `null` if there is no |
| /// associated element (e.g. because it is a reference to an undefined |
| /// entity). |
| Element get element; |
| |
| /// The enclosing [_ReferenceInfo], or `null` for top-level elements. |
| ReferenceInfo get enclosing; |
| |
| /// Indicates whether the thing being referenced has at least one type |
| /// parameter. |
| bool get hasTypeParameters; |
| |
| /// The name of the entity referred to by this reference. |
| String get name; |
| |
| /// If this reference refers to a non-generic type, the type it refers to. |
| /// Otherwise `null`. |
| DartType get type; |
| } |
| |
| /** |
| * Implementation of [ElementResynthesizer] used when resynthesizing an element |
| * model from summaries. |
| */ |
| abstract class SummaryResynthesizer extends ElementResynthesizer { |
| /** |
| * Source factory used to convert URIs to [Source] objects. |
| */ |
| final SourceFactory sourceFactory; |
| |
| /** |
| * Cache of [Source] objects that have already been converted from URIs. |
| */ |
| final Map<String, Source> _sources = <String, Source>{}; |
| |
| /** |
| * The `dart:core` library for the context. |
| */ |
| LibraryElementImpl _coreLibrary; |
| |
| /** |
| * The `dart:async` library for the context. |
| */ |
| LibraryElementImpl _asyncLibrary; |
| |
| /** |
| * The [TypeProvider] used to obtain SDK types during resynthesis. |
| */ |
| TypeProvider _typeProvider; |
| |
| /** |
| * Map of compilation units resynthesized from summaries. The two map keys |
| * are the first two elements of the element's location (the library URI and |
| * the compilation unit URI). |
| */ |
| final Map<String, Map<String, CompilationUnitElementImpl>> |
| _resynthesizedUnits = <String, Map<String, CompilationUnitElementImpl>>{}; |
| |
| /** |
| * Map of top level elements resynthesized from summaries. The three map |
| * keys are the first three elements of the element's location (the library |
| * URI, the compilation unit URI, and the name of the top level declaration). |
| */ |
| final Map<String, Map<String, Map<String, Element>>> _resynthesizedElements = |
| <String, Map<String, Map<String, Element>>>{}; |
| |
| /** |
| * Map of libraries which have been resynthesized from summaries. The map |
| * key is the library URI. |
| */ |
| final Map<String, LibraryElement> _resynthesizedLibraries = |
| <String, LibraryElement>{}; |
| |
| SummaryResynthesizer(AnalysisContext context, AnalysisSession session, |
| this.sourceFactory, bool _) |
| : super(context, session) { |
| _buildTypeProvider(); |
| } |
| |
| /** |
| * Number of libraries that have been resynthesized so far. |
| */ |
| int get resynthesisCount => _resynthesizedLibraries.length; |
| |
| /** |
| * Indicates whether the summary should be resynthesized assuming strong mode |
| * semantics. |
| */ |
| @deprecated |
| bool get strongMode => true; |
| |
| /** |
| * The [TypeProvider] used to obtain SDK types during resynthesis. |
| */ |
| TypeProvider get typeProvider => _typeProvider; |
| |
| /** |
| * The [TypeSystem] used perform type operations. |
| */ |
| TypeSystem get typeSystem => context.typeSystem; |
| |
| /** |
| * The client installed this resynthesizer into the context, and set its |
| * type provider, so it is not safe to access type provider to create |
| * additional types. |
| */ |
| void finishCoreAsyncLibraries() { |
| _coreLibrary.createLoadLibraryFunction(_typeProvider); |
| _asyncLibrary.createLoadLibraryFunction(_typeProvider); |
| } |
| |
| @override |
| Element getElement(ElementLocation location) { |
| List<String> components = location.components; |
| String libraryUri = components[0]; |
| // Resynthesize locally. |
| if (components.length == 1) { |
| return getLibraryElement(libraryUri); |
| } else if (components.length == 2) { |
| LibraryElement libraryElement = getLibraryElement(libraryUri); |
| // Try to find the unit element. |
| { |
| Map<String, CompilationUnitElement> libraryMap = |
| _resynthesizedUnits[libraryUri]; |
| assert(libraryMap != null); |
| String unitUri = components[1]; |
| CompilationUnitElement unitElement = libraryMap[unitUri]; |
| if (unitElement != null) { |
| return unitElement; |
| } |
| } |
| // Try to find the prefix element. |
| { |
| String name = components[1]; |
| for (PrefixElement prefix in libraryElement.prefixes) { |
| if (prefix.name == name) { |
| return prefix; |
| } |
| } |
| } |
| // Fail. |
| throw new Exception('The element not found in summary: $location'); |
| } else if (components.length == 3 || components.length == 4) { |
| String unitUri = components[1]; |
| // Prepare elements-in-units in the library. |
| Map<String, Map<String, Element>> unitsInLibrary = |
| _resynthesizedElements[libraryUri]; |
| if (unitsInLibrary == null) { |
| unitsInLibrary = new HashMap<String, Map<String, Element>>(); |
| _resynthesizedElements[libraryUri] = unitsInLibrary; |
| } |
| // Prepare elements in the unit. |
| Map<String, Element> elementsInUnit = unitsInLibrary[unitUri]; |
| if (elementsInUnit == null) { |
| // Prepare the CompilationUnitElementImpl. |
| Map<String, CompilationUnitElementImpl> libraryMap = |
| _resynthesizedUnits[libraryUri]; |
| if (libraryMap == null) { |
| getLibraryElement(libraryUri); |
| libraryMap = _resynthesizedUnits[libraryUri]; |
| if (libraryMap == null) { |
| throw new StateError( |
| 'Unable to find library `$libraryUri` in a summary file.'); |
| } |
| } |
| CompilationUnitElementImpl unitElement = libraryMap[unitUri]; |
| // Fill elements in the unit map. |
| if (unitElement != null) { |
| elementsInUnit = new HashMap<String, Element>(); |
| void putElement(Element e) { |
| String id = |
| e is PropertyAccessorElementImpl ? e.identifier : e.name; |
| elementsInUnit[id] = e; |
| } |
| |
| unitElement.accessors.forEach(putElement); |
| unitElement.enums.forEach(putElement); |
| unitElement.functions.forEach(putElement); |
| unitElement.functionTypeAliases.forEach(putElement); |
| unitElement.mixins.forEach(putElement); |
| unitElement.topLevelVariables.forEach(putElement); |
| unitElement.types.forEach(putElement); |
| unitsInLibrary[unitUri] = elementsInUnit; |
| } |
| } |
| // Get the element. |
| Element element = elementsInUnit[components[2]]; |
| if (element != null && components.length == 4) { |
| String name = components[3]; |
| Element parentElement = element; |
| if (parentElement is ClassElement) { |
| if (name.endsWith('?')) { |
| element = |
| parentElement.getGetter(name.substring(0, name.length - 1)); |
| } else if (name.endsWith('=')) { |
| element = |
| parentElement.getSetter(name.substring(0, name.length - 1)); |
| } else if (name.isEmpty) { |
| element = parentElement.unnamedConstructor; |
| } else { |
| element = parentElement.getField(name) ?? |
| parentElement.getMethod(name) ?? |
| parentElement.getNamedConstructor(name); |
| } |
| } else { |
| // The only elements that are currently retrieved using 4-component |
| // locations are class members. |
| throw new StateError( |
| '4-element locations not supported for ${element.runtimeType}'); |
| } |
| } |
| if (element == null) { |
| throw new Exception('Element not found in summary: $location'); |
| } |
| return element; |
| } else { |
| throw new UnimplementedError(location.toString()); |
| } |
| } |
| |
| /** |
| * Get the [LibraryElement] for the given [uri], resynthesizing it if it |
| * hasn't been resynthesized already. |
| */ |
| LibraryElement getLibraryElement(String uri) { |
| return _resynthesizedLibraries.putIfAbsent(uri, () { |
| LinkedLibrary serializedLibrary = getLinkedSummary(uri); |
| Source librarySource = _getSource(uri); |
| if (serializedLibrary == null) { |
| LibraryElementImpl libraryElement = |
| new LibraryElementImpl(context, session, '', -1, 0); |
| libraryElement.isSynthetic = true; |
| CompilationUnitElementImpl unitElement = |
| new CompilationUnitElementImpl(); |
| libraryElement.definingCompilationUnit = unitElement; |
| unitElement.source = librarySource; |
| unitElement.librarySource = librarySource; |
| libraryElement.createLoadLibraryFunction(typeProvider); |
| libraryElement.publicNamespace = new Namespace({}); |
| libraryElement.exportNamespace = new Namespace({}); |
| _resynthesizedUnits[uri] = {uri: unitElement}; |
| return libraryElement; |
| } |
| UnlinkedUnit unlinkedSummary = getUnlinkedSummary(uri); |
| if (unlinkedSummary == null) { |
| throw new StateError('Unable to find unlinked summary: $uri'); |
| } |
| List<UnlinkedUnit> serializedUnits = <UnlinkedUnit>[unlinkedSummary]; |
| for (String part in serializedUnits[0].publicNamespace.parts) { |
| Source partSource = sourceFactory.resolveUri(librarySource, part); |
| UnlinkedUnit partUnlinkedUnit; |
| if (partSource != null) { |
| String partAbsUri = partSource.uri.toString(); |
| partUnlinkedUnit = getUnlinkedSummary(partAbsUri); |
| } |
| serializedUnits.add(partUnlinkedUnit ?? |
| new UnlinkedUnitBuilder(codeRange: new CodeRangeBuilder())); |
| } |
| _LibraryResynthesizer libraryResynthesizer = new _LibraryResynthesizer( |
| this, serializedLibrary, serializedUnits, librarySource); |
| LibraryElement library = libraryResynthesizer.buildLibrary(); |
| _resynthesizedUnits[uri] = libraryResynthesizer.resynthesizedUnits; |
| return library; |
| }); |
| } |
| |
| /** |
| * Return the [LinkedLibrary] for the given [uri] or `null` if it could not |
| * be found. Caller has already checked that `parent.hasLibrarySummary(uri)` |
| * returns `false`. |
| */ |
| LinkedLibrary getLinkedSummary(String uri); |
| |
| /** |
| * Return the [UnlinkedUnit] for the given [uri] or `null` if it could not |
| * be found. Caller has already checked that `parent.hasLibrarySummary(uri)` |
| * returns `false`. |
| */ |
| UnlinkedUnit getUnlinkedSummary(String uri); |
| |
| /** |
| * Return `true` if this resynthesizer can provide summaries of the libraries |
| * with the given [uri]. Caller has already checked that |
| * `parent.hasLibrarySummary(uri)` returns `false`. |
| */ |
| bool hasLibrarySummary(String uri); |
| |
| void _buildTypeProvider() { |
| _coreLibrary = getLibraryElement('dart:core') as LibraryElementImpl; |
| _asyncLibrary = getLibraryElement('dart:async') as LibraryElementImpl; |
| SummaryTypeProvider summaryTypeProvider = new SummaryTypeProvider(); |
| summaryTypeProvider.initializeCore(_coreLibrary); |
| summaryTypeProvider.initializeAsync(_asyncLibrary); |
| _typeProvider = summaryTypeProvider; |
| } |
| |
| /** |
| * Get the [Source] object for the given [uri]. |
| */ |
| Source _getSource(String uri) { |
| return _sources.putIfAbsent(uri, () => sourceFactory.forUri(uri)); |
| } |
| } |
| |
| class SummaryResynthesizerContext implements ResynthesizerContext { |
| final _UnitResynthesizer unitResynthesizer; |
| |
| SummaryResynthesizerContext(this.unitResynthesizer); |
| |
| @deprecated |
| @override |
| bool get isStrongMode => true; |
| |
| @override |
| ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedExpr uc) { |
| return unitResynthesizer.buildAnnotation(context, uc); |
| } |
| |
| @override |
| Expression buildExpression(ElementImpl context, UnlinkedExpr uc) { |
| return unitResynthesizer._buildConstExpression(context, uc); |
| } |
| |
| @override |
| UnitExplicitTopLevelAccessors buildTopLevelAccessors() { |
| return unitResynthesizer.buildUnitExplicitTopLevelAccessors(); |
| } |
| |
| @override |
| UnitExplicitTopLevelVariables buildTopLevelVariables() { |
| return unitResynthesizer.buildUnitExplicitTopLevelVariables(); |
| } |
| |
| @override |
| TopLevelInferenceError getTypeInferenceError(int slot) { |
| return unitResynthesizer.getTypeInferenceError(slot); |
| } |
| |
| @override |
| bool inheritsCovariant(int slot) { |
| return unitResynthesizer.parametersInheritingCovariant.contains(slot); |
| } |
| |
| @override |
| bool isInConstCycle(int slot) { |
| return unitResynthesizer.constCycles.contains(slot); |
| } |
| |
| @override |
| bool isSimplyBounded(int notSimplyBoundedSlot) { |
| return !unitResynthesizer.linkedUnit.notSimplyBounded |
| .contains(notSimplyBoundedSlot); |
| } |
| |
| @override |
| ConstructorElement resolveConstructorRef( |
| ElementImpl context, EntityRef entry) { |
| return unitResynthesizer._getConstructorForEntry(context, entry); |
| } |
| |
| @override |
| DartType resolveLinkedType(ElementImpl context, int slot) { |
| return unitResynthesizer.buildLinkedType(context, slot); |
| } |
| |
| @override |
| DartType resolveTypeRef(ElementImpl context, EntityRef type, |
| {bool defaultVoid: false, |
| bool instantiateToBoundsAllowed: true, |
| bool declaredType: false}) { |
| return unitResynthesizer.buildType(context, type, |
| defaultVoid: defaultVoid, |
| instantiateToBoundsAllowed: instantiateToBoundsAllowed, |
| declaredType: declaredType); |
| } |
| } |
| |
| /// An instance of [_UnitResynthesizer] is responsible for resynthesizing the |
| /// elements in a single unit from that unit's summary. |
| abstract class UnitResynthesizer { |
| /// Gets the [LibraryElement] being resynthesized. |
| LibraryElement get library; |
| |
| /// Gets the [TypeProvider], which may be used to create core types. |
| TypeProvider get typeProvider; |
| |
| /// Gets the [TypeSystem], which may be used to create core types. |
| TypeSystem get typeSystem; |
| |
| /// Builds a [DartType] object based on a [EntityRef]. This [DartType] |
| /// may refer to elements in other libraries than the library being |
| /// deserialized, so handles may be used to avoid having to deserialize other |
| /// libraries in the process. |
| DartType buildType(ElementImpl context, EntityRef type); |
| |
| /// Builds a [DartType] object based on [ReferenceInfo], which should refer to |
| /// a class, by filling in the type arguments as appropriate, and performing |
| /// instantiate to bounds if necessary. |
| DartType buildTypeForClassInfo(ReferenceInfo info, int numTypeArguments, |
| DartType getTypeArgument(int i)); |
| |
| /// Returns the defining type for a [ConstructorElement] by applying |
| /// [typeArgumentRefs] to the given linked [info]. Returns [DynamicTypeImpl] |
| /// if the [info] is unresolved. |
| DartType createConstructorDefiningType(ElementImpl context, |
| ReferenceInfo info, List<EntityRef> typeArgumentRefs); |
| |
| /// Determines if the given [type] has implicit type arguments. |
| bool doesTypeHaveImplicitArguments(ParameterizedType type); |
| |
| /// Returns the [ConstructorElement] corresponding to the given linked [info], |
| /// using the [classType] which has already been computed (e.g. by |
| /// [createConstructorDefiningType]). Both cases when [info] is a |
| /// [ClassElement] and [ConstructorElement] are supported. |
| ConstructorElement getConstructorForInfo( |
| InterfaceType classType, ReferenceInfo info); |
| |
| /// Returns the [ReferenceInfo] with the given [index]. |
| ReferenceInfo getReferenceInfo(int index); |
| } |
| |
| /// [UnitResynthesizerMixin] contains methods useful for implementing the |
| /// [UnitResynthesizer] interface. |
| mixin UnitResynthesizerMixin implements UnitResynthesizer { |
| @override |
| DartType createConstructorDefiningType(ElementImpl context, |
| ReferenceInfo info, List<EntityRef> typeArgumentRefs) { |
| bool isClass = info.element is ClassElement; |
| ReferenceInfo classInfo = isClass ? info : info.enclosing; |
| if (classInfo == null) { |
| return DynamicTypeImpl.instance; |
| } |
| List<DartType> typeArguments = |
| typeArgumentRefs.map((t) => buildType(context, t)).toList(); |
| return buildTypeForClassInfo(classInfo, typeArguments.length, (i) { |
| if (i < typeArguments.length) { |
| return typeArguments[i]; |
| } else { |
| return DynamicTypeImpl.instance; |
| } |
| }); |
| } |
| |
| @override |
| ConstructorElement getConstructorForInfo( |
| InterfaceType classType, ReferenceInfo info) { |
| ConstructorElement element; |
| Element infoElement = info.element; |
| if (infoElement is ConstructorElement) { |
| element = infoElement; |
| } else if (infoElement is ClassElement) { |
| element = infoElement.unnamedConstructor; |
| } |
| if (element != null && info.hasTypeParameters) { |
| return new ConstructorMember(element, classType); |
| } |
| return element; |
| } |
| } |
| |
| /** |
| * Local function element representing the initializer for a variable that has |
| * been resynthesized from a summary. The actual element won't be constructed |
| * until it is requested. But properties [context] and [enclosingElement] can |
| * be used without creating the actual element. |
| */ |
| class _DeferredInitializerElement extends FunctionElementHandle { |
| /** |
| * The variable element containing this element. |
| */ |
| @override |
| final VariableElement enclosingElement; |
| |
| _DeferredInitializerElement(this.enclosingElement) : super(null, null); |
| |
| @override |
| FunctionElement get actualElement => enclosingElement.initializer; |
| |
| @override |
| AnalysisContext get context => enclosingElement.context; |
| |
| @override |
| ElementLocation get location => actualElement.location; |
| |
| @override |
| AnalysisSession get session => enclosingElement.session; |
| } |
| |
| /// Specialization of [LibraryResynthesizer] for resynthesis from linked |
| /// summaries. |
| class _LibraryResynthesizer extends LibraryResynthesizerMixin { |
| /** |
| * The [SummaryResynthesizer] which is being used to obtain summaries. |
| */ |
| final SummaryResynthesizer summaryResynthesizer; |
| |
| /** |
| * Linked summary of the library to be resynthesized. |
| */ |
| final LinkedLibrary linkedLibrary; |
| |
| /** |
| * Unlinked compilation units constituting the library to be resynthesized. |
| */ |
| final List<UnlinkedUnit> unlinkedUnits; |
| |
| /** |
| * [Source] object for the library to be resynthesized. |
| */ |
| final Source librarySource; |
| |
| /** |
| * The URI of [librarySource]. |
| */ |
| Uri libraryUri; |
| |
| /** |
| * The URI of [librarySource]. |
| */ |
| String libraryUriStr; |
| |
| /** |
| * Indicates whether [librarySource] is the `dart:core` library. |
| */ |
| bool isCoreLibrary; |
| |
| /** |
| * The resynthesized library. |
| */ |
| LibraryElementImpl library; |
| |
| /** |
| * Map of compilation unit elements that have been resynthesized so far. The |
| * key is the URI of the compilation unit. |
| */ |
| final Map<String, CompilationUnitElementImpl> resynthesizedUnits = |
| <String, CompilationUnitElementImpl>{}; |
| |
| _LibraryResynthesizer(this.summaryResynthesizer, this.linkedLibrary, |
| this.unlinkedUnits, this.librarySource) { |
| libraryUri = librarySource.uri; |
| libraryUriStr = libraryUri.toString(); |
| isCoreLibrary = libraryUriStr == 'dart:core'; |
| } |
| |
| @override |
| List<LinkedExportName> get linkedExportNames => linkedLibrary.exportNames; |
| |
| /** |
| * Resynthesize a [NamespaceCombinator]. |
| */ |
| NamespaceCombinator buildCombinator(UnlinkedCombinator serializedCombinator) { |
| if (serializedCombinator.shows.isNotEmpty) { |
| return new ShowElementCombinatorImpl.forSerialized(serializedCombinator); |
| } else { |
| return new HideElementCombinatorImpl.forSerialized(serializedCombinator); |
| } |
| } |
| |
| @override |
| ElementHandle buildExportName(LinkedExportName exportName) { |
| String name = exportName.name; |
| if (exportName.kind == ReferenceKind.topLevelPropertyAccessor && |
| !name.endsWith('=')) { |
| name += '?'; |
| } |
| ElementLocationImpl location = new ElementLocationImpl.con3( |
| getReferencedLocationComponents( |
| exportName.dependency, exportName.unit, name)); |
| switch (exportName.kind) { |
| case ReferenceKind.classOrEnum: |
| return new ClassElementHandle(summaryResynthesizer, location); |
| case ReferenceKind.typedef: |
| return new FunctionTypeAliasElementHandle( |
| summaryResynthesizer, location); |
| case ReferenceKind.genericFunctionTypedef: |
| return new GenericTypeAliasElementHandle( |
| summaryResynthesizer, location); |
| case ReferenceKind.topLevelFunction: |
| return new FunctionElementHandle(summaryResynthesizer, location); |
| case ReferenceKind.topLevelPropertyAccessor: |
| return new PropertyAccessorElementHandle( |
| summaryResynthesizer, location); |
| case ReferenceKind.constructor: |
| case ReferenceKind.function: |
| case ReferenceKind.propertyAccessor: |
| case ReferenceKind.method: |
| case ReferenceKind.prefix: |
| case ReferenceKind.unresolved: |
| case ReferenceKind.variable: |
| // Should never happen. Exported names never refer to import prefixes, |
| // and they always refer to defined top-level entities. |
| throw new StateError('Unexpected export name kind: ${exportName.kind}'); |
| } |
| return null; |
| } |
| |
| /** |
| * Main entry point. Resynthesize the [LibraryElement] and return it. |
| */ |
| LibraryElement buildLibrary() { |
| // Create LibraryElementImpl. |
| bool hasName = unlinkedUnits[0].libraryName.isNotEmpty; |
| library = new LibraryElementImpl.forSerialized( |
| summaryResynthesizer.context, |
| summaryResynthesizer.session, |
| unlinkedUnits[0].libraryName, |
| hasName ? unlinkedUnits[0].libraryNameOffset : -1, |
| unlinkedUnits[0].libraryNameLength, |
| new _LibraryResynthesizerContext(this), |
| unlinkedUnits[0]); |
| // Create the defining unit. |
| _UnitResynthesizer definingUnitResynthesizer = |
| createUnitResynthesizer(0, librarySource, null); |
| CompilationUnitElementImpl definingUnit = definingUnitResynthesizer.unit; |
| library.definingCompilationUnit = definingUnit; |
| definingUnit.source = librarySource; |
| definingUnit.librarySource = librarySource; |
| // Create parts. |
| List<_UnitResynthesizer> partResynthesizers = <_UnitResynthesizer>[]; |
| UnlinkedUnit unlinkedDefiningUnit = unlinkedUnits[0]; |
| assert(unlinkedDefiningUnit.publicNamespace.parts.length + 1 == |
| linkedLibrary.units.length); |
| for (int i = 1; i < linkedLibrary.units.length; i++) { |
| _UnitResynthesizer partResynthesizer = buildPart( |
| definingUnitResynthesizer, |
| unlinkedDefiningUnit.publicNamespace.parts[i - 1], |
| unlinkedDefiningUnit.parts[i - 1], |
| i); |
| if (partResynthesizer != null) { |
| partResynthesizers.add(partResynthesizer); |
| } |
| } |
| library.parts = partResynthesizers.map((r) => r.unit).toList(); |
| // Populate units. |
| rememberUriToUnit(definingUnitResynthesizer); |
| for (_UnitResynthesizer partResynthesizer in partResynthesizers) { |
| rememberUriToUnit(partResynthesizer); |
| } |
| // Create the synthetic element for `loadLibrary`. |
| // Until the client received dart:core and dart:async, we cannot do this, |
| // because the TypeProvider is not fully initialized. So, it is up to the |
| // Dart SDK client to initialize TypeProvider and finish the dart:core and |
| // dart:async libraries creation. |
| if (library.name != 'dart.core' && library.name != 'dart.async') { |
| library.createLoadLibraryFunction(summaryResynthesizer.typeProvider); |
| } |
| // Done. |
| return library; |
| } |
| |
| /** |
| * Create a [_UnitResynthesizer] that will resynthesize the part with the |
| * given [uri]. Return `null` if the [uri] is invalid. |
| */ |
| _UnitResynthesizer buildPart(_UnitResynthesizer definingUnitResynthesizer, |
| String uri, UnlinkedPart partDecl, int unitNum) { |
| Source unitSource = |
| summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri); |
| _UnitResynthesizer partResynthesizer = |
| createUnitResynthesizer(unitNum, unitSource, partDecl); |
| CompilationUnitElementImpl partUnit = partResynthesizer.unit; |
| partUnit.uriOffset = partDecl.uriOffset; |
| partUnit.uriEnd = partDecl.uriEnd; |
| partUnit.source = unitSource; |
| partUnit.librarySource = librarySource; |
| partUnit.uri = uri; |
| return partResynthesizer; |
| } |
| |
| /** |
| * Set up data structures for deserializing a compilation unit. |
| */ |
| _UnitResynthesizer createUnitResynthesizer( |
| int unitNum, Source unitSource, UnlinkedPart unlinkedPart) { |
| LinkedUnit linkedUnit = linkedLibrary.units[unitNum]; |
| UnlinkedUnit unlinkedUnit = unlinkedUnits[unitNum]; |
| return new _UnitResynthesizer( |
| this, unlinkedUnit, linkedUnit, unitSource, unlinkedPart); |
| } |
| |
| /** |
| * Build the components of an [ElementLocationImpl] for the entity in the |
| * given [unit] of the dependency located at [dependencyIndex], and having |
| * the given [name]. |
| */ |
| List<String> getReferencedLocationComponents( |
| int dependencyIndex, int unit, String name) { |
| if (dependencyIndex == 0) { |
| String partUri; |
| if (unit != 0) { |
| String uri = unlinkedUnits[0].publicNamespace.parts[unit - 1]; |
| partUri = _resolveRelativeUri(uri); |
| } else { |
| partUri = libraryUriStr; |
| } |
| return <String>[libraryUriStr, partUri, name]; |
| } |
| |
| LinkedDependency dependency = linkedLibrary.dependencies[dependencyIndex]; |
| String referencedLibraryUri = _resolveRelativeUri(dependency.uri); |
| |
| String partUri; |
| if (unit != 0) { |
| String uri = dependency.parts[unit - 1]; |
| partUri = _resolveRelativeUri(uri); |
| } else { |
| partUri = referencedLibraryUri; |
| } |
| return <String>[referencedLibraryUri, partUri, name]; |
| } |
| |
| /** |
| * Remember the absolute URI to the corresponding unit mapping. |
| */ |
| void rememberUriToUnit(_UnitResynthesizer unitResynthesizer) { |
| CompilationUnitElementImpl unit = unitResynthesizer.unit; |
| Source source = unit.source; |
| if (source != null) { |
| String absoluteUri = source.uri.toString(); |
| resynthesizedUnits[absoluteUri] = unit; |
| } |
| } |
| |
| /** |
| * Resolve the [relativeUriStr] against [libraryUri] using Dart rules. |
| */ |
| String _resolveRelativeUri(String relativeUriStr) { |
| Uri relativeUri = Uri.parse(relativeUriStr); |
| Uri resolvedUri = resolveRelativeUri(libraryUri, relativeUri); |
| return resolvedUri.toString(); |
| } |
| } |
| |
| /** |
| * Implementation of [LibraryResynthesizerContext] for [_LibraryResynthesizer]. |
| */ |
| class _LibraryResynthesizerContext extends LibraryResynthesizerContextMixin |
| implements LibraryResynthesizerContext { |
| final _LibraryResynthesizer resynthesizer; |
| |
| _LibraryResynthesizerContext(this.resynthesizer); |
| |
| @override |
| LinkedLibrary get linkedLibrary => resynthesizer.linkedLibrary; |
| |
| @override |
| LibraryElement buildExportedLibrary(String relativeUri) { |
| return _getLibraryByRelativeUri(relativeUri); |
| } |
| |
| @override |
| LibraryElement buildImportedLibrary(int dependency) { |
| String depUri = resynthesizer.linkedLibrary.dependencies[dependency].uri; |
| return _getLibraryByRelativeUri(depUri); |
| } |
| |
| @override |
| FunctionElement findEntryPoint() { |
| LibraryElementImpl library = resynthesizer.library; |
| Element entryPoint = |
| library.exportNamespace.get(FunctionElement.MAIN_FUNCTION_NAME); |
| if (entryPoint is FunctionElement) { |
| return entryPoint; |
| } |
| return null; |
| } |
| |
| @override |
| void patchTopLevelAccessors() { |
| LibraryElementImpl library = resynthesizer.library; |
| BuildLibraryElementUtils.patchTopLevelAccessors(library); |
| } |
| |
| LibraryElementHandle _getLibraryByRelativeUri(String depUri) { |
| Source source = resynthesizer.summaryResynthesizer.sourceFactory |
| .resolveUri(resynthesizer.librarySource, depUri); |
| if (source == null) { |
| return null; |
| } |
| String absoluteUri = source.uri.toString(); |
| return new LibraryElementHandle(resynthesizer.summaryResynthesizer, |
| new ElementLocationImpl.con3(<String>[absoluteUri])); |
| } |
| } |
| |
| /// Specialization of [ReferenceInfo] for resynthesis from linked summaries. |
| class _ReferenceInfo extends ReferenceInfo { |
| /** |
| * The [_LibraryResynthesizer] which is being used to obtain summaries. |
| */ |
| final _LibraryResynthesizer libraryResynthesizer; |
| |
| @override |
| final _ReferenceInfo enclosing; |
| |
| @override |
| final String name; |
| |
| /** |
| * Is `true` if the [element] can be used as a declared type. |
| */ |
| final bool isDeclarableType; |
| |
| @override |
| final Element element; |
| |
| /** |
| * If this reference refers to a non-generic type, the type it refers to. |
| * Otherwise `null`. |
| */ |
| DartType _type; |
| |
| /** |
| * The number of type parameters accepted by the entity referred to by this |
| * reference, or zero if it doesn't accept any type parameters. |
| */ |
| final int numTypeParameters; |
| |
| bool _isBeingInstantiatedToBounds = false; |
| bool _isRecursiveWhileInstantiateToBounds = false; |
| |
| /** |
| * Create a new [_ReferenceInfo] object referring to an element called [name] |
| * via the element handle [element], and having [numTypeParameters] type |
| * parameters. |
| * |
| * For the special types `dynamic` and `void`, [specialType] should point to |
| * the type itself. Otherwise, pass `null` and the type will be computed |
| * when appropriate. |
| */ |
| _ReferenceInfo( |
| this.libraryResynthesizer, |
| this.enclosing, |
| this.name, |
| this.isDeclarableType, |
| this.element, |
| DartType specialType, |
| this.numTypeParameters) { |
| if (specialType != null) { |
| _type = specialType; |
| } |
| } |
| |
| @override |
| bool get hasTypeParameters => numTypeParameters != 0; |
| |
| @override |
| DartType get type { |
| if (_type == null) { |
| _type = _buildType(true, 0, (_) => DynamicTypeImpl.instance, const []); |
| } |
| return _type; |
| } |
| |
| List<DartType> get _dynamicTypeArguments => |
| new List<DartType>.filled(numTypeParameters, DynamicTypeImpl.instance); |
| |
| /** |
| * Build a [DartType] corresponding to the result of applying some type |
| * arguments to the entity referred to by this [_ReferenceInfo]. The type |
| * arguments are retrieved by calling [getTypeArgument]. |
| * |
| * If [implicitFunctionTypeIndices] is not empty, a [DartType] should be |
| * created which refers to a function type implicitly defined by one of the |
| * element's parameters. [implicitFunctionTypeIndices] is interpreted as in |
| * [EntityRef.implicitFunctionTypeIndices]. |
| * |
| * If the entity referred to by this [_ReferenceInfo] is not a type, `null` |
| * is returned. |
| */ |
| DartType buildType(bool instantiateToBoundsAllowed, int numTypeArguments, |
| DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) { |
| DartType result = |
| (numTypeParameters == 0 && implicitFunctionTypeIndices.isEmpty) |
| ? type |
| : _buildType(instantiateToBoundsAllowed, numTypeArguments, |
| getTypeArgument, implicitFunctionTypeIndices); |
| if (result == null) { |
| return DynamicTypeImpl.instance; |
| } |
| return result; |
| } |
| |
| /** |
| * If this reference refers to a type, build a [DartType]. Otherwise return |
| * `null`. If [numTypeArguments] is the same as the [numTypeParameters], |
| * the type is instantiated with type arguments returned by [getTypeArgument], |
| * otherwise it is instantiated with type parameter bounds (if strong mode), |
| * or with `dynamic` type arguments. |
| * |
| * If [implicitFunctionTypeIndices] is not null, a [DartType] should be |
| * created which refers to a function type implicitly defined by one of the |
| * element's parameters. [implicitFunctionTypeIndices] is interpreted as in |
| * [EntityRef.implicitFunctionTypeIndices]. |
| */ |
| DartType _buildType(bool instantiateToBoundsAllowed, int numTypeArguments, |
| DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) { |
| ElementHandle element = this.element; // To allow type promotion |
| if (element is ClassElementHandle) { |
| List<DartType> typeArguments = null; |
| // If type arguments are specified, use them. |
| // Otherwise, delay until they are requested. |
| if (numTypeParameters == 0) { |
| return element.type; |
| } else if (numTypeArguments == numTypeParameters) { |
| typeArguments = _buildTypeArguments(numTypeArguments, getTypeArgument); |
| } |
| InterfaceTypeImpl type = |
| new InterfaceTypeImpl.elementWithNameAndArgs(element, name, () { |
| if (typeArguments == null) { |
| if (!_isBeingInstantiatedToBounds) { |
| _isBeingInstantiatedToBounds = true; |
| _isRecursiveWhileInstantiateToBounds = false; |
| try { |
| InterfaceType instantiatedToBounds = libraryResynthesizer |
| .summaryResynthesizer.context.typeSystem |
| .instantiateToBounds(element.type) as InterfaceType; |
| if (_isRecursiveWhileInstantiateToBounds) { |
| throw new RecursiveInstantiateToBounds(); |
| } |
| return instantiatedToBounds.typeArguments; |
| } finally { |
| _isBeingInstantiatedToBounds = false; |
| } |
| } else { |
| _isRecursiveWhileInstantiateToBounds = true; |
| typeArguments = _dynamicTypeArguments; |
| } |
| } |
| return typeArguments; |
| }); |
| // Mark the type as having implicit type arguments, so that we don't |
| // attempt to request them during constant expression resynthesizing. |
| if (typeArguments == null) { |
| _typesWithImplicitTypeArguments[type] = true; |
| } |
| // Done. |
| return type; |
| } else if (element is GenericTypeAliasElementHandle) { |
| GenericTypeAliasElementImpl actualElement = element.actualElement; |
| List<DartType> typeArguments; |
| if (numTypeArguments == numTypeParameters) { |
| typeArguments = _buildTypeArguments(numTypeArguments, getTypeArgument); |
| } else if (instantiateToBoundsAllowed) { |
| if (!_isBeingInstantiatedToBounds) { |
| _isBeingInstantiatedToBounds = true; |
| _isRecursiveWhileInstantiateToBounds = false; |
| try { |
| typeArguments = libraryResynthesizer |
| .summaryResynthesizer.context.typeSystem |
| .instantiateTypeFormalsToBounds(element.typeParameters); |
| if (_isRecursiveWhileInstantiateToBounds) { |
| typeArguments = _dynamicTypeArguments; |
| } |
| } finally { |
| _isBeingInstantiatedToBounds = false; |
| } |
| } else { |
| _isRecursiveWhileInstantiateToBounds = true; |
| typeArguments = _dynamicTypeArguments; |
| } |
| } else { |
| typeArguments = _dynamicTypeArguments; |
| } |
| return GenericTypeAliasElementImpl.typeAfterSubstitution( |
| actualElement, typeArguments); |
| } else if (element is FunctionTypedElement) { |
| if (element is FunctionTypeAliasElementHandle) { |
| List<DartType> typeArguments; |
| if (numTypeArguments == numTypeParameters) { |
| typeArguments = |
| _buildTypeArguments(numTypeArguments, getTypeArgument); |
| } else if (instantiateToBoundsAllowed) { |
| if (!_isBeingInstantiatedToBounds) { |
| _isBeingInstantiatedToBounds = true; |
| _isRecursiveWhileInstantiateToBounds = false; |
| try { |
| FunctionType instantiatedToBounds = libraryResynthesizer |
| .summaryResynthesizer.context.typeSystem |
| .instantiateToBounds(element.type) as FunctionType; |
| if (!_isRecursiveWhileInstantiateToBounds) { |
| typeArguments = instantiatedToBounds.typeArguments; |
| } else { |
| typeArguments = _dynamicTypeArguments; |
| } |
| } finally { |
| _isBeingInstantiatedToBounds = false; |
| } |
| } else { |
| _isRecursiveWhileInstantiateToBounds = true; |
| typeArguments = _dynamicTypeArguments; |
| } |
| } else { |
| typeArguments = _dynamicTypeArguments; |
| } |
| return element.instantiate(typeArguments); |
| } else { |
| FunctionTypedElementComputer computer; |
| if (implicitFunctionTypeIndices.isNotEmpty) { |
| numTypeArguments = numTypeParameters; |
| computer = () { |
| FunctionTypedElement element = this.element; |
| for (int index in implicitFunctionTypeIndices) { |
| element = element.parameters[index].type.element; |
| } |
| return element; |
| }; |
| } else { |
| // For a type that refers to a generic executable, the type arguments are |
| // not supposed to include the arguments to the executable itself. |
| if (element is MethodElementHandle && !element.isStatic) { |
| numTypeArguments = enclosing?.numTypeParameters ?? 0; |
| } else { |
| numTypeArguments = 0; |
| } |
| computer = () => this.element as FunctionTypedElement; |
| } |
| // TODO(paulberry): Is it a bug that we have to pass `false` for |
| // isInstantiated? |
| return new DeferredFunctionTypeImpl(computer, null, |
| _buildTypeArguments(numTypeArguments, getTypeArgument), false); |
| } |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Build a list of type arguments having length [numTypeArguments] where each |
| * type argument is obtained by calling [getTypeArgument]. |
| */ |
| List<DartType> _buildTypeArguments( |
| int numTypeArguments, DartType getTypeArgument(int i)) { |
| List<DartType> typeArguments = const <DartType>[]; |
| if (numTypeArguments != 0) { |
| typeArguments = new List<DartType>(numTypeArguments); |
| for (int i = 0; i < numTypeArguments; i++) { |
| typeArguments[i] = getTypeArgument(i); |
| } |
| } |
| return typeArguments; |
| } |
| } |
| |
| /// Specialization of [UnitResynthesizer] for resynthesis from linked summaries. |
| class _UnitResynthesizer extends UnitResynthesizer with UnitResynthesizerMixin { |
| /** |
| * The [_LibraryResynthesizer] which is being used to obtain summaries. |
| */ |
| final _LibraryResynthesizer libraryResynthesizer; |
| |
| /** |
| * The [UnlinkedUnit] from which elements are currently being resynthesized. |
| */ |
| final UnlinkedUnit unlinkedUnit; |
| |
| /** |
| * The [LinkedUnit] from which elements are currently being resynthesized. |
| */ |
| final LinkedUnit linkedUnit; |
| |
| /** |
| * The [CompilationUnitElementImpl] for the compilation unit currently being |
| * resynthesized. |
| */ |
| CompilationUnitElementImpl unit; |
| |
| /** |
| * Map from slot id to the corresponding [EntityRef] object for linked types |
| * (i.e. propagated and inferred types). |
| */ |
| final Map<int, EntityRef> linkedTypeMap = <int, EntityRef>{}; |
| |
| /** |
| * Set of slot ids corresponding to const constructors that are part of |
| * cycles. |
| */ |
| Set<int> constCycles; |
| |
| /** |
| * Set of slot ids corresponding to parameters that inherit `@covariant` |
| * behavior. |
| */ |
| Set<int> parametersInheritingCovariant; |
| |
| int numLinkedReferences; |
| int numUnlinkedReferences; |
| |
| /** |
| * List of [_ReferenceInfo] objects describing the references in the current |
| * compilation unit. This list is works as a lazily filled cache, use |
| * [getReferenceInfo] to get the [_ReferenceInfo] for an index. |
| */ |
| List<_ReferenceInfo> referenceInfos; |
| |
| /** |
| * The [ResynthesizerContext] for this resynthesize session. |
| */ |
| ResynthesizerContext _resynthesizerContext; |
| |
| _UnitResynthesizer(this.libraryResynthesizer, this.unlinkedUnit, |
| this.linkedUnit, Source unitSource, UnlinkedPart unlinkedPart) { |
| _resynthesizerContext = new SummaryResynthesizerContext(this); |
| unit = new CompilationUnitElementImpl.forSerialized( |
| libraryResynthesizer.library, |
| _resynthesizerContext, |
| unlinkedUnit, |
| unlinkedPart); |
| |
| { |
| List<int> lineStarts = unlinkedUnit.lineStarts; |
| if (lineStarts.isEmpty) { |
| lineStarts = const <int>[0]; |
| } |
| unit.lineInfo = new LineInfo(lineStarts); |
| } |
| |
| for (EntityRef t in linkedUnit.types) { |
| linkedTypeMap[t.slot] = t; |
| } |
| constCycles = linkedUnit.constCycles.toSet(); |
| parametersInheritingCovariant = |
| linkedUnit.parametersInheritingCovariant.toSet(); |
| numLinkedReferences = linkedUnit.references.length; |
| numUnlinkedReferences = unlinkedUnit.references.length; |
| referenceInfos = new List<_ReferenceInfo>(numLinkedReferences); |
| } |
| |
| @override |
| LibraryElement get library => libraryResynthesizer.library; |
| |
| SummaryResynthesizer get summaryResynthesizer => |
| libraryResynthesizer.summaryResynthesizer; |
| |
| @override |
| TypeProvider get typeProvider => summaryResynthesizer.typeProvider; |
| |
| @override |
| TypeSystem get typeSystem => summaryResynthesizer.typeSystem; |
| |
| /** |
| * Build [ElementAnnotationImpl] for the given [UnlinkedExpr]. |
| */ |
| ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedExpr uc) { |
| ElementAnnotationImpl elementAnnotation = new ElementAnnotationImpl(unit); |
| Expression constExpr = _buildConstExpression(context, uc); |
| if (constExpr == null) { |
| // Invalid constant expression. |
| } else if (constExpr is Identifier) { |
| ArgumentList arguments = constExpr.getProperty(ExprBuilder.ARGUMENT_LIST); |
| elementAnnotation.element = constExpr.staticElement; |
| elementAnnotation.annotationAst = |
| AstTestFactory.annotation2(constExpr, null, arguments); |
| } else if (constExpr is InstanceCreationExpression) { |
| var element = constExpr.staticElement; |
| elementAnnotation.element = element; |
| Identifier typeName = constExpr.constructorName.type.name; |
| SimpleIdentifier constructorName = constExpr.constructorName.name; |
| if (typeName is SimpleIdentifier && constructorName != null) { |
| // E.g. `@cls.ctor()`. Since `cls.ctor` would have been parsed as |
| // a PrefixedIdentifier, we need to resynthesize it as one. |
| typeName = AstTestFactory.identifier(typeName, constructorName); |
| constructorName = null; |
| } |
| elementAnnotation.annotationAst = AstTestFactory.annotation2( |
| typeName, constructorName, constExpr.argumentList) |
| ..element = constExpr.staticElement; |
| } else if (constExpr is PropertyAccess) { |
| var target = constExpr.target as Identifier; |
| var propertyName = constExpr.propertyName; |
| var propertyElement = propertyName.staticElement; |
| ArgumentList arguments = constExpr.getProperty(ExprBuilder.ARGUMENT_LIST); |
| elementAnnotation.element = propertyElement; |
| elementAnnotation.annotationAst = |
| AstTestFactory.annotation2(target, propertyName, arguments) |
| ..element = propertyElement; |
| } else { |
| throw new StateError( |
| 'Unexpected annotation type: ${constExpr.runtimeType}'); |
| } |
| return elementAnnotation; |
| } |
| |
| /** |
| * Build an implicit getter for the given [property] and bind it to the |
| * [property] and to its enclosing element. |
| */ |
| PropertyAccessorElementImpl buildImplicitGetter( |
| PropertyInducingElementImpl property) { |
| PropertyAccessorElementImpl_ImplicitGetter getter = |
| new PropertyAccessorElementImpl_ImplicitGetter(property); |
| getter.enclosingElement = property.enclosingElement; |
| return getter; |
| } |
| |
| /** |
| * Build an implicit setter for the given [property] and bind it to the |
| * [property] and to its enclosing element. |
| */ |
| PropertyAccessorElementImpl buildImplicitSetter( |
| PropertyInducingElementImpl property) { |
| PropertyAccessorElementImpl_ImplicitSetter setter = |
| new PropertyAccessorElementImpl_ImplicitSetter(property); |
| setter.enclosingElement = property.enclosingElement; |
| return setter; |
| } |
| |
| /** |
| * Build the appropriate [DartType] object corresponding to a slot id in the |
| * [LinkedUnit.types] table. |
| */ |
| DartType buildLinkedType(ElementImpl context, int slot) { |
| if (slot == 0) { |
| // A slot id of 0 means there is no [DartType] object to build. |
| return null; |
| } |
| EntityRef type = linkedTypeMap[slot]; |
| if (type == null) { |
| // A missing entry in [LinkedUnit.types] means there is no [DartType] |
| // stored in this slot. |
| return null; |
| } |
| return buildType(context, type); |
| } |
| |
| @override |
| DartType buildType(ElementImpl context, EntityRef type, |
| {bool defaultVoid: false, |
| bool instantiateToBoundsAllowed: true, |
| bool declaredType: false}) { |
| if (type == null) { |
| if (defaultVoid) { |
| return VoidTypeImpl.instance; |
| } else { |
| return DynamicTypeImpl.instance; |
| } |
| } |
| if (type.refinedSlot != 0) { |
| var refinedType = linkedTypeMap[type.refinedSlot]; |
| if (refinedType != null) { |
| type = refinedType; |
| } |
| } |
| if (type.paramReference != 0) { |
| return context.typeParameterContext |
| .getTypeParameterType(type.paramReference); |
| } else if (type.entityKind == EntityRefKind.genericFunctionType) { |
| GenericFunctionTypeElement element = |
| new GenericFunctionTypeElementImpl.forSerialized(context, type); |
| return element.type; |
| } else if (type.syntheticReturnType != null) { |
| FunctionElementImpl element = |
| new FunctionElementImpl_forLUB(context, type); |
| return element.type; |
| } else { |
| DartType getTypeArgument(int i) { |
| if (i < type.typeArguments.length) { |
| return buildType(context, type.typeArguments[i], |
| declaredType: declaredType); |
| } else { |
| return DynamicTypeImpl.instance; |
| } |
| } |
| |
| _ReferenceInfo referenceInfo = getReferenceInfo(type.reference); |
| if (declaredType && !referenceInfo.isDeclarableType) { |
| return DynamicTypeImpl.instance; |
| } |
| |
| return referenceInfo.buildType( |
| instantiateToBoundsAllowed, |
| type.typeArguments.length, |
| getTypeArgument, |
| type.implicitFunctionTypeIndices); |
| } |
| } |
| |
| @override |
| DartType buildTypeForClassInfo(covariant _ReferenceInfo info, |
| int numTypeArguments, DartType getTypeArgument(int i)) => |
| info.buildType(true, numTypeArguments, getTypeArgument, const <int>[]); |
| |
| UnitExplicitTopLevelAccessors buildUnitExplicitTopLevelAccessors() { |
| Map<String, TopLevelVariableElementImpl> implicitVariables = |
| new HashMap<String, TopLevelVariableElementImpl>(); |
| UnitExplicitTopLevelAccessors accessorsData = |
| new UnitExplicitTopLevelAccessors(); |
| for (UnlinkedExecutable unlinkedExecutable in unlinkedUnit.executables) { |
| UnlinkedExecutableKind kind = unlinkedExecutable.kind; |
| if (kind == UnlinkedExecutableKind.getter || |
| kind == UnlinkedExecutableKind.setter) { |
| // name |
| String name = unlinkedExecutable.name; |
| if (kind == UnlinkedExecutableKind.setter) { |
| assert(name.endsWith('=')); |
| name = name.substring(0, name.length - 1); |
| } |
| // create |
| PropertyAccessorElementImpl accessor = |
| new PropertyAccessorElementImpl.forSerialized( |
| unlinkedExecutable, unit); |
| accessorsData.accessors.add(accessor); |
| // implicit variable |
| TopLevelVariableElementImpl variable = implicitVariables[name]; |
| if (variable == null) { |
| variable = new TopLevelVariableElementImpl(name, -1); |
| variable.enclosingElement = unit; |
| implicitVariables[name] = variable; |
| accessorsData.implicitVariables.add(variable); |
| variable.isSynthetic = true; |
| variable.isFinal = kind == UnlinkedExecutableKind.getter; |
| } else { |
| variable.isFinal = false; |
| } |
| accessor.variable = variable; |
| // link |
| if (kind == UnlinkedExecutableKind.getter) { |
| variable.getter = accessor; |
| } else { |
| variable.setter = accessor; |
| } |
| } |
| } |
| return accessorsData; |
| } |
| |
| UnitExplicitTopLevelVariables buildUnitExplicitTopLevelVariables() { |
| List<UnlinkedVariable> unlinkedVariables = unlinkedUnit.variables; |
| int numberOfVariables = unlinkedVariables.length; |
| UnitExplicitTopLevelVariables variablesData = |
| new UnitExplicitTopLevelVariables(numberOfVariables); |
| for (int i = 0; i < numberOfVariables; i++) { |
| UnlinkedVariable unlinkedVariable = unlinkedVariables[i]; |
| TopLevelVariableElementImpl element; |
| if (unlinkedVariable.initializer?.bodyExpr != null && |
| unlinkedVariable.isConst) { |
| element = new ConstTopLevelVariableElementImpl.forSerialized( |
| unlinkedVariable, unit); |
| } else { |
| element = new TopLevelVariableElementImpl.forSerialized( |
| unlinkedVariable, unit); |
| } |
| variablesData.variables[i] = element; |
| // implicit accessors |
| variablesData.implicitAccessors.add(buildImplicitGetter(element)); |
| if (!(element.isConst || element.isFinal)) { |
| variablesData.implicitAccessors.add(buildImplicitSetter(element)); |
| } |
| } |
| return variablesData; |
| } |
| |
| @override |
| bool doesTypeHaveImplicitArguments(ParameterizedType type) => |
| _typesWithImplicitTypeArguments[type] != null; |
| |
| @override |
| _ReferenceInfo getReferenceInfo(int index) { |
| // We don't know how to reproduce this. |
| // https://github.com/dart-lang/sdk/issues/35551 |
| // https://github.com/dart-lang/sdk/issues/34534 |
| // So, adding logging to gather more information. |
| if (index >= referenceInfos.length) { |
| var buffer = StringBuffer(); |
| buffer.writeln('librarySource: ${unit.librarySource}'); |
| buffer.writeln('unitSource: ${unit.source}'); |
| buffer.writeln('unlinkedUnit: ${unlinkedUnit.toJson()}'); |
| buffer.writeln('linkedUnit: ${linkedUnit.toJson()}'); |
| throw StateError(buffer.toString()); |
| } |
| |
| _ReferenceInfo result = referenceInfos[index]; |
| if (result == null) { |
| LinkedReference linkedReference = linkedUnit.references[index]; |
| String name; |
| int containingReference; |
| if (index < numUnlinkedReferences) { |
| name = unlinkedUnit.references[index].name; |
| containingReference = unlinkedUnit.references[index].prefixReference; |
| } else { |
| name = linkedUnit.references[index].name; |
| containingReference = linkedUnit.references[index].containingReference; |
| } |
| _ReferenceInfo enclosingInfo = containingReference != 0 |
| ? getReferenceInfo(containingReference) |
| : null; |
| Element element; |
| DartType type; |
| bool isDeclarableType = false; |
| int numTypeParameters = linkedReference.numTypeParameters; |
| if (linkedReference.kind == ReferenceKind.unresolved) { |
| type = UndefinedTypeImpl.instance; |
| element = null; |
| isDeclarableType = true; |
| } else if (name == 'dynamic') { |
| type = DynamicTypeImpl.instance; |
| element = type.element; |
| isDeclarableType = true; |
| } else if (name == 'void') { |
| type = VoidTypeImpl.instance; |
| element = type.element; |
| isDeclarableType = true; |
| } else if (name == '*bottom*') { |
| type = BottomTypeImpl.instance; |
| element = null; |
| isDeclarableType = true; |
| } else { |
| List<String> locationComponents; |
| if (enclosingInfo != null && enclosingInfo.element is ClassElement) { |
| String identifier = _getElementIdentifier(name, linkedReference.kind); |
| locationComponents = |
| enclosingInfo.element.location.components.toList(); |
| locationComponents.add(identifier); |
| } else { |
| String identifier = _getElementIdentifier(name, linkedReference.kind); |
| locationComponents = |
| libraryResynthesizer.getReferencedLocationComponents( |
| linkedReference.dependency, linkedReference.unit, identifier); |
| if (linkedReference.kind == ReferenceKind.prefix) { |
| locationComponents = <String>[ |
| locationComponents[0], |
| locationComponents[2] |
| ]; |
| } |
| } |
| ElementLocation location = |
| new ElementLocationImpl.con3(locationComponents); |
| if (enclosingInfo != null) { |
| numTypeParameters += enclosingInfo.numTypeParameters; |
| } |
| switch (linkedReference.kind) { |
| case ReferenceKind.classOrEnum: |
| element = new ClassElementHandle(summaryResynthesizer, location); |
| isDeclarableType = true; |
| break; |
| case ReferenceKind.constructor: |
| assert(location.components.length == 4); |
| element = |
| new ConstructorElementHandle(summaryResynthesizer, location); |
| break; |
| case ReferenceKind.method: |
| assert(location.components.length == 4); |
| element = new MethodElementHandle(summaryResynthesizer, location); |
| break; |
| case ReferenceKind.propertyAccessor: |
| assert(location.components.length == 4); |
| element = new PropertyAccessorElementHandle( |
| summaryResynthesizer, location); |
| break; |
| case ReferenceKind.topLevelFunction: |
| assert(location.components.length == 3); |
| element = new FunctionElementHandle(summaryResynthesizer, location); |
| break; |
| case ReferenceKind.topLevelPropertyAccessor: |
| element = new PropertyAccessorElementHandle( |
| summaryResynthesizer, location); |
| break; |
| case ReferenceKind.typedef: |
| case ReferenceKind.genericFunctionTypedef: |
| element = new GenericTypeAliasElementHandle( |
| summaryResynthesizer, location); |
| isDeclarableType = true; |
| break; |
| case ReferenceKind.function: |
| Element enclosingElement = enclosingInfo.element; |
| if (enclosingElement is VariableElement) { |
| element = new _DeferredInitializerElement(enclosingElement); |
| } else { |
| throw new StateError('Unexpected element enclosing function:' |
| ' ${enclosingElement.runtimeType}'); |
| } |
| break; |
| case ReferenceKind.prefix: |
| element = new PrefixElementHandle(summaryResynthesizer, location); |
| break; |
| case ReferenceKind.variable: |
| case ReferenceKind.unresolved: |
| break; |
| } |
| } |
| result = new _ReferenceInfo(libraryResynthesizer, enclosingInfo, name, |
| isDeclarableType, element, type, numTypeParameters); |
| referenceInfos[index] = result; |
| } |
| return result; |
| } |
| |
| /** |
| * Return the error reported during type inference for the given [slot], |
| * or `null` if there were no error. |
| */ |
| TopLevelInferenceError getTypeInferenceError(int slot) { |
| if (slot == 0) { |
| return null; |
| } |
| for (TopLevelInferenceError error in linkedUnit.topLevelInferenceErrors) { |
| if (error.slot == slot) { |
| return error; |
| } |
| } |
| return null; |
| } |
| |
| Expression _buildConstExpression(ElementImpl context, UnlinkedExpr uc) { |
| return new ExprBuilder(this, context, uc).build(); |
| } |
| |
| /** |
| * Return the [ConstructorElement] corresponding to the given [entry]. |
| */ |
| ConstructorElement _getConstructorForEntry( |
| ElementImpl context, EntityRef entry) { |
| _ReferenceInfo info = getReferenceInfo(entry.reference); |
| DartType type = |
| createConstructorDefiningType(context, info, entry.typeArguments); |
| if (type is InterfaceType) { |
| return getConstructorForInfo(type, info); |
| } |
| return null; |
| } |
| |
| /** |
| * If the given [kind] is a top-level or class member property accessor, and |
| * the given [name] does not end with `=`, i.e. does not denote a setter, |
| * return the getter identifier by appending `?`. |
| */ |
| static String _getElementIdentifier(String name, ReferenceKind kind) { |
| if (kind == ReferenceKind.topLevelPropertyAccessor || |
| kind == ReferenceKind.propertyAccessor) { |
| if (!name.endsWith('=')) { |
| return name + '?'; |
| } |
| } |
| return name; |
| } |
| } |