blob: 5c72f8a59d22e74e8bd41fb12acb1e897b11b15d [file] [log] [blame]
// 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.
library summary_resynthesizer;
import 'dart:collection';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/listener.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);
}
/// 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;
/**
* Indicates whether the summary should be resynthesized assuming strong mode
* semantics.
*/
final bool strongMode;
/**
* 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, this.sourceFactory, this.strongMode)
: super(context) {
_buildTypeProvider();
}
/**
* Number of libraries that have been resynthesized so far.
*/
int get resynthesisCount => _resynthesizedLibraries.length;
/**
* The [TypeProvider] used to obtain SDK types during resynthesis.
*/
TypeProvider get typeProvider => _typeProvider;
/**
* 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];
assert(libraryMap != null);
}
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.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, '', -1, 0);
libraryElement.isSynthetic = true;
CompilationUnitElementImpl unitElement =
new CompilationUnitElementImpl(librarySource.shortName);
libraryElement.definingCompilationUnit = unitElement;
unitElement.source = librarySource;
unitElement.librarySource = librarySource;
libraryElement.createLoadLibraryFunction(typeProvider);
libraryElement.publicNamespace = new Namespace({});
libraryElement.exportNamespace = new Namespace({});
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);
@override
bool get isStrongMode => unitResynthesizer.summaryResynthesizer.strongMode;
@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
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 [TypeProvider], which may be used to create core types.
TypeProvider get typeProvider;
/// 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.
abstract class 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;
}
/// 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,
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]));
}
}
class RecursiveInstantiateToBounds {}
/// 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 {
if (libraryResynthesizer.summaryResynthesizer.strongMode) {
InterfaceType instantiatedToBounds = libraryResynthesizer
.summaryResynthesizer.context.typeSystem
.instantiateToBounds(element.type) as InterfaceType;
if (_isRecursiveWhileInstantiateToBounds) {
throw new RecursiveInstantiateToBounds();
}
return instantiatedToBounds.typeArguments;
} else {
return _dynamicTypeArguments;
}
} 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 (libraryResynthesizer.summaryResynthesizer.strongMode &&
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 actualElement.typeAfterSubstitution(typeArguments);
} else if (element is FunctionTypedElement) {
if (element is FunctionTypeAliasElementHandle) {
List<DartType> typeArguments;
if (numTypeArguments == numTypeParameters) {
typeArguments =
_buildTypeArguments(numTypeArguments, getTypeArgument);
} else if (libraryResynthesizer.summaryResynthesizer.strongMode &&
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 new FunctionTypeImpl.forTypedef(element,
typeArguments: 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;
/**
* The visitor to rewrite implicit `new` and `const`.
*/
AstRewriteVisitor astRewriteVisitor;
/**
* 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,
unitSource?.shortName);
{
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);
}
SummaryResynthesizer get summaryResynthesizer =>
libraryResynthesizer.summaryResynthesizer;
@override
TypeProvider get typeProvider => summaryResynthesizer.typeProvider;
/**
* 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) {
var element = constExpr.staticElement;
ArgumentList arguments = constExpr.getProperty(ExprBuilder.ARGUMENT_LIST);
if (element is PropertyAccessorElement && arguments == null) {
elementAnnotation.element = element;
elementAnnotation.annotationAst = AstTestFactory.annotation(constExpr);
} else if (element is ConstructorElement && arguments != null) {
elementAnnotation.element = element;
elementAnnotation.annotationAst =
AstTestFactory.annotation2(constExpr, null, arguments);
} else {
elementAnnotation.annotationAst = AstTestFactory
.annotation(AstTestFactory.identifier3(r'#invalidConst'));
}
} else if (constExpr is InstanceCreationExpression) {
elementAnnotation.element = constExpr.staticElement;
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);
if (propertyElement is PropertyAccessorElement && arguments == null) {
elementAnnotation.element = propertyElement;
elementAnnotation.annotationAst = AstTestFactory.annotation2(
target, propertyName, null)
..element = propertyElement;
} else if (propertyElement is ConstructorElement && arguments != null) {
elementAnnotation.element = propertyElement;
elementAnnotation.annotationAst = AstTestFactory.annotation2(
target, propertyName, arguments)
..element = propertyElement;
} else {
elementAnnotation.annotationAst = AstTestFactory
.annotation(AstTestFactory.identifier3(r'#invalidConst'));
}
} 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) {
_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]
];
}
}
if (!_resynthesizerContext.isStrongMode &&
locationComponents.length == 3 &&
locationComponents[0] == 'dart:async' &&
locationComponents[2] == 'FutureOr') {
type = typeProvider.dynamicType;
numTypeParameters = 0;
}
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) {
var expression = new ExprBuilder(this, context, uc).build();
if (expression != null && context.context.analysisOptions.previewDart2) {
astRewriteVisitor ??= new AstRewriteVisitor(
libraryResynthesizer.summaryResynthesizer.context.typeSystem,
libraryResynthesizer.library,
unit.source,
typeProvider,
AnalysisErrorListener.NULL_LISTENER,
addConstKeyword: true);
var container = astFactory.expressionStatement(expression, null);
expression.accept(astRewriteVisitor);
expression = container.expression;
}
return expression;
}
/**
* 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;
}
}