blob: e83b6619d47a447cf9a055e6cf0bf8470da9669a [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 'package:analyzer/analyzer.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/element_handle.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/summary/format.dart';
/**
* Callback used by [SummaryResynthesizer] to obtain the prelinked summary for
* a given URI.
*/
typedef PrelinkedLibrary GetPrelinkedSummaryCallback(String uri);
/**
* Callback used by [SummaryResynthesizer] to obtain the unlinked summary for a
* given URI.
*/
typedef UnlinkedUnit GetUnlinkedSummaryCallback(String uri);
/**
* Implementation of [ElementResynthesizer] used when resynthesizing an element
* model from summaries.
*/
class SummaryResynthesizer extends ElementResynthesizer {
/**
* Callback used to obtain the prelinked summary for a given URI.
*/
final GetPrelinkedSummaryCallback getPrelinkedSummary;
/**
* Callback used to obtain the unlinked summary for a given URI.
*/
final GetUnlinkedSummaryCallback getUnlinkedSummary;
/**
* 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 [TypeProvider] used to obtain core types (such as Object, int, List,
* and dynamic) during resynthesis.
*/
final TypeProvider typeProvider;
/**
* 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.typeProvider,
this.getPrelinkedSummary, this.getUnlinkedSummary, this.sourceFactory)
: super(context);
/**
* Number of libraries that have been resynthesized so far.
*/
int get resynthesisCount => _resynthesizedLibraries.length;
@override
Element getElement(ElementLocation location) {
if (location.components.length == 1) {
return getLibraryElement(location.components[0]);
} else if (location.components.length == 3) {
String uri = location.components[0];
Map<String, Map<String, Element>> libraryMap =
_resynthesizedElements[uri];
if (libraryMap == null) {
getLibraryElement(uri);
libraryMap = _resynthesizedElements[uri];
assert(libraryMap != null);
}
Map<String, Element> compilationUnitElements =
libraryMap[location.components[1]];
if (compilationUnitElements != null) {
Element element = compilationUnitElements[location.components[2]];
if (element != null) {
return element;
}
}
throw new Exception('Element not found in summary: $location');
} 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, () {
PrelinkedLibrary serializedLibrary = getPrelinkedSummary(uri);
List<UnlinkedUnit> serializedUnits = <UnlinkedUnit>[
getUnlinkedSummary(uri)
];
Source librarySource = _getSource(uri);
for (UnlinkedPart part in serializedUnits[0].publicNamespace.parts) {
String partAbsUri =
sourceFactory.resolveUri(librarySource, part.uri).uri.toString();
serializedUnits.add(getUnlinkedSummary(partAbsUri));
}
_LibraryResynthesizer libraryResynthesizer = new _LibraryResynthesizer(
this, serializedLibrary, serializedUnits, librarySource);
LibraryElement library = libraryResynthesizer.buildLibrary();
_resynthesizedElements[uri] = libraryResynthesizer.resummarizedElements;
return library;
});
}
/**
* Get the [Source] object for the given [uri].
*/
Source _getSource(String uri) {
return _sources.putIfAbsent(uri, () => sourceFactory.forUri(uri));
}
}
/**
* An instance of [_LibraryResynthesizer] is responsible for resynthesizing the
* elements in a single library from that library's summary.
*/
class _LibraryResynthesizer {
/**
* The [SummaryResynthesizer] which is being used to obtain summaries.
*/
final SummaryResynthesizer summaryResynthesizer;
/**
* Prelinked summary of the library to be resynthesized.
*/
final PrelinkedLibrary prelinkedLibrary;
/**
* Unlinked compilation units constituting the library to be resynthesized.
*/
final List<UnlinkedUnit> unlinkedUnits;
/**
* [Source] object for the library to be resynthesized.
*/
final Source librarySource;
/**
* Indicates whether [librarySource] is the `dart:core` library.
*/
bool isCoreLibrary;
/**
* Classes which should have their supertype set to "object" once
* resynthesis is complete. Only used if [isCoreLibrary] is `true`.
*/
List<ClassElementImpl> delayedObjectSubclasses = <ClassElementImpl>[];
/**
* [ElementHolder] into which resynthesized elements should be placed. This
* object is recreated afresh for each unit in the library, and is used to
* populate the [CompilationUnitElement].
*/
ElementHolder unitHolder;
/**
* The [PrelinkedUnit] from which elements are currently being resynthesized.
*/
PrelinkedUnit prelinkedUnit;
/**
* The [UnlinkedUnit] from which elements are currently being resynthesized.
*/
UnlinkedUnit unlinkedUnit;
/**
* Map of top level elements that have been resynthesized so far. The first
* key is the URI of the compilation unit; the second is the name of the top
* level element.
*/
final Map<String, Map<String, Element>> resummarizedElements =
<String, Map<String, Element>>{};
/**
* Type parameters for the class or typedef currently being resynthesized.
*
* TODO(paulberry): extend this to do the right thing for generic methods.
*/
List<TypeParameterElement> currentTypeParameters;
_LibraryResynthesizer(this.summaryResynthesizer, this.prelinkedLibrary,
this.unlinkedUnits, this.librarySource) {
isCoreLibrary = librarySource.uri.toString() == 'dart:core';
}
/**
* Resynthesize a [ClassElement] and place it in [unitHolder].
*/
void buildClass(UnlinkedClass serializedClass) {
try {
currentTypeParameters =
serializedClass.typeParameters.map(buildTypeParameter).toList();
for (int i = 0; i < serializedClass.typeParameters.length; i++) {
finishTypeParameter(
serializedClass.typeParameters[i], currentTypeParameters[i]);
}
ClassElementImpl classElement =
new ClassElementImpl(serializedClass.name, -1);
classElement.mixinApplication = serializedClass.isMixinApplication;
InterfaceTypeImpl correspondingType = new InterfaceTypeImpl(classElement);
if (serializedClass.supertype != null) {
classElement.supertype = buildType(serializedClass.supertype);
} else if (!serializedClass.hasNoSupertype) {
if (isCoreLibrary) {
delayedObjectSubclasses.add(classElement);
} else {
classElement.supertype = summaryResynthesizer.typeProvider.objectType;
}
}
classElement.interfaces =
serializedClass.interfaces.map(buildType).toList();
classElement.mixins = serializedClass.mixins.map(buildType).toList();
classElement.typeParameters = currentTypeParameters;
ElementHolder memberHolder = new ElementHolder();
bool constructorFound = false;
for (UnlinkedExecutable serializedExecutable
in serializedClass.executables) {
switch (serializedExecutable.kind) {
case UnlinkedExecutableKind.constructor:
constructorFound = true;
buildConstructor(serializedExecutable, memberHolder);
break;
case UnlinkedExecutableKind.functionOrMethod:
case UnlinkedExecutableKind.getter:
case UnlinkedExecutableKind.setter:
buildExecutable(serializedExecutable, memberHolder);
break;
}
}
for (UnlinkedVariable serializedVariable in serializedClass.fields) {
buildVariable(serializedVariable, memberHolder);
}
if (!serializedClass.isMixinApplication) {
if (!constructorFound) {
// Synthesize implicit constructors.
ConstructorElementImpl constructor =
new ConstructorElementImpl('', -1);
constructor.synthetic = true;
constructor.returnType = correspondingType;
constructor.type = new FunctionTypeImpl.elementWithNameAndArgs(
constructor,
null,
currentTypeParameters
.map((TypeParameterElement e) => e.type)
.toList());
memberHolder.addConstructor(constructor);
}
classElement.constructors = memberHolder.constructors;
}
classElement.accessors = memberHolder.accessors;
classElement.fields = memberHolder.fields;
classElement.methods = memberHolder.methods;
correspondingType.typeArguments =
currentTypeParameters.map((param) => param.type).toList();
classElement.type = correspondingType;
unitHolder.addType(classElement);
} finally {
currentTypeParameters = null;
}
}
/**
* Resynthesize a [NamespaceCombinator].
*/
NamespaceCombinator buildCombinator(UnlinkedCombinator serializedCombinator) {
if (serializedCombinator.shows.isNotEmpty) {
ShowElementCombinatorImpl combinator = new ShowElementCombinatorImpl();
// Note: we call toList() so that we don't retain a reference to the
// deserialized data structure.
combinator.shownNames = serializedCombinator.shows.toList();
return combinator;
} else {
HideElementCombinatorImpl combinator = new HideElementCombinatorImpl();
// Note: we call toList() so that we don't retain a reference to the
// deserialized data structure.
combinator.hiddenNames = serializedCombinator.hides.toList();
return combinator;
}
}
/**
* Resynthesize a [ConstructorElement] and place it in the given [holder].
*/
void buildConstructor(
UnlinkedExecutable serializedExecutable, ElementHolder holder) {
assert(serializedExecutable.kind == UnlinkedExecutableKind.constructor);
ConstructorElementImpl constructorElement =
new ConstructorElementImpl(serializedExecutable.name, -1);
buildExecutableCommonParts(constructorElement, serializedExecutable);
constructorElement.factory = serializedExecutable.isFactory;
constructorElement.const2 = serializedExecutable.isConst;
holder.addConstructor(constructorElement);
}
/**
* Resynthesize the [ClassElement] corresponding to an enum, along with the
* associated fields and implicit accessors.
*/
void buildEnum(UnlinkedEnum serializedEnum) {
assert(!isCoreLibrary);
// TODO(paulberry): add offset support (for this element type and others)
ClassElementImpl classElement =
new ClassElementImpl(serializedEnum.name, -1);
classElement.enum2 = true;
InterfaceType enumType = new InterfaceTypeImpl(classElement);
classElement.type = enumType;
classElement.supertype = summaryResynthesizer.typeProvider.objectType;
ElementHolder memberHolder = new ElementHolder();
FieldElementImpl indexField = new FieldElementImpl('index', -1);
indexField.final2 = true;
indexField.synthetic = true;
indexField.type = summaryResynthesizer.typeProvider.intType;
memberHolder.addField(indexField);
buildImplicitAccessors(indexField, memberHolder);
FieldElementImpl valuesField = new ConstFieldElementImpl('values', -1);
valuesField.synthetic = true;
valuesField.const3 = true;
valuesField.static = true;
valuesField.type = summaryResynthesizer.typeProvider.listType
.substitute4(<DartType>[enumType]);
memberHolder.addField(valuesField);
buildImplicitAccessors(valuesField, memberHolder);
for (UnlinkedEnumValue serializedEnumValue in serializedEnum.values) {
ConstFieldElementImpl valueField =
new ConstFieldElementImpl(serializedEnumValue.name, -1);
valueField.const3 = true;
valueField.static = true;
valueField.type = enumType;
memberHolder.addField(valueField);
buildImplicitAccessors(valueField, memberHolder);
}
classElement.fields = memberHolder.fields;
classElement.accessors = memberHolder.accessors;
classElement.constructors = <ConstructorElement>[];
unitHolder.addEnum(classElement);
}
/**
* Resynthesize an [ExecutableElement] and place it in the given [holder].
*/
void buildExecutable(UnlinkedExecutable serializedExecutable,
[ElementHolder holder]) {
bool isTopLevel = holder == null;
if (holder == null) {
holder = unitHolder;
}
UnlinkedExecutableKind kind = serializedExecutable.kind;
String name = serializedExecutable.name;
if (kind == UnlinkedExecutableKind.setter) {
assert(name.endsWith('='));
name = name.substring(0, name.length - 1);
}
switch (kind) {
case UnlinkedExecutableKind.functionOrMethod:
if (isTopLevel) {
FunctionElementImpl executableElement =
new FunctionElementImpl(name, -1);
buildExecutableCommonParts(executableElement, serializedExecutable);
holder.addFunction(executableElement);
} else {
MethodElementImpl executableElement = new MethodElementImpl(name, -1);
buildExecutableCommonParts(executableElement, serializedExecutable);
executableElement.static = serializedExecutable.isStatic;
holder.addMethod(executableElement);
}
break;
case UnlinkedExecutableKind.getter:
case UnlinkedExecutableKind.setter:
PropertyAccessorElementImpl executableElement =
new PropertyAccessorElementImpl(name, -1);
if (isTopLevel) {
executableElement.static = true;
} else {
executableElement.static = serializedExecutable.isStatic;
}
buildExecutableCommonParts(executableElement, serializedExecutable);
DartType type;
if (kind == UnlinkedExecutableKind.getter) {
executableElement.getter = true;
type = executableElement.returnType;
} else {
executableElement.setter = true;
type = executableElement.parameters[0].type;
}
holder.addAccessor(executableElement);
// TODO(paulberry): consider removing implicit variables from the
// element model; the spec doesn't call for them, and they cause
// trouble when getters/setters exist in different parts.
PropertyInducingElementImpl implicitVariable;
if (isTopLevel) {
implicitVariable = buildImplicitTopLevelVariable(name, kind, holder);
} else {
FieldElementImpl field = buildImplicitField(name, type, kind, holder);
field.static = serializedExecutable.isStatic;
implicitVariable = field;
}
executableElement.variable = implicitVariable;
if (kind == UnlinkedExecutableKind.getter) {
implicitVariable.getter = executableElement;
} else {
implicitVariable.setter = executableElement;
}
// TODO(paulberry): do the right thing when getter and setter are in
// different units.
break;
default:
// The only other executable type is a constructor, and that is handled
// separately (in [buildConstructor]. So this code should be
// unreachable.
assert(false);
}
}
/**
* Handle the parts of an executable element that are common to constructors,
* functions, methods, getters, and setters.
*/
void buildExecutableCommonParts(ExecutableElementImpl executableElement,
UnlinkedExecutable serializedExecutable) {
executableElement.parameters =
serializedExecutable.parameters.map(buildParameter).toList();
if (serializedExecutable.returnType != null) {
executableElement.returnType = buildType(serializedExecutable.returnType);
} else {
executableElement.returnType = VoidTypeImpl.instance;
}
executableElement.type = new FunctionTypeImpl.elementWithNameAndArgs(
executableElement,
null,
currentTypeParameters
?.map((TypeParameterElement e) => e.type)
?.toList());
executableElement.hasImplicitReturnType =
serializedExecutable.hasImplicitReturnType;
executableElement.external = serializedExecutable.isExternal;
}
/**
* Resynthesize an [ExportElement],
*/
ExportElement buildExport(UnlinkedExport serializedExport) {
ExportElementImpl exportElement = new ExportElementImpl(0);
String exportedLibraryUri = summaryResynthesizer.sourceFactory
.resolveUri(librarySource, serializedExport.uri)
.uri
.toString();
exportElement.exportedLibrary = new LibraryElementHandle(
summaryResynthesizer,
new ElementLocationImpl.con3(<String>[exportedLibraryUri]));
exportElement.uri = serializedExport.uri;
exportElement.combinators =
serializedExport.combinators.map(buildCombinator).toList();
return exportElement;
}
/**
* Resynthesize a [FieldElement].
*/
FieldElement buildField(UnlinkedVariable serializedField) {
FieldElementImpl fieldElement =
new FieldElementImpl(serializedField.name, -1);
fieldElement.type = buildType(serializedField.type);
fieldElement.const3 = serializedField.isConst;
return fieldElement;
}
/**
* Build the implicit getter and setter associated with [element], and place
* them in [holder].
*/
void buildImplicitAccessors(
PropertyInducingElementImpl element, ElementHolder holder) {
String name = element.name;
DartType type = element.type;
PropertyAccessorElementImpl getter =
new PropertyAccessorElementImpl(name, -1);
getter.getter = true;
getter.static = element.isStatic;
getter.synthetic = true;
getter.returnType = type;
getter.type = new FunctionTypeImpl(getter);
getter.variable = element;
holder.addAccessor(getter);
element.getter = getter;
if (!(element.isConst || element.isFinal)) {
PropertyAccessorElementImpl setter =
new PropertyAccessorElementImpl(name, -1);
setter.setter = true;
setter.static = element.isStatic;
setter.synthetic = true;
setter.parameters = <ParameterElement>[
new ParameterElementImpl('_$name', -1)
..synthetic = true
..type = type
..parameterKind = ParameterKind.REQUIRED
];
setter.returnType = VoidTypeImpl.instance;
setter.type = new FunctionTypeImpl(setter);
setter.variable = element;
holder.addAccessor(setter);
element.setter = setter;
}
}
/**
* Build the implicit field associated with a getter or setter, and place it
* in [holder].
*/
FieldElementImpl buildImplicitField(String name, DartType type,
UnlinkedExecutableKind kind, ElementHolder holder) {
FieldElementImpl field = holder.getField(name);
if (field == null) {
field = new FieldElementImpl(name, -1);
field.synthetic = true;
field.final2 = kind == UnlinkedExecutableKind.getter;
field.type = type;
holder.addField(field);
return field;
} else {
// TODO(paulberry): what if the getter and setter have a type mismatch?
field.final2 = false;
return field;
}
}
/**
* Build the implicit top level variable associated with a getter or setter,
* and place it in [holder].
*/
PropertyInducingElementImpl buildImplicitTopLevelVariable(
String name, UnlinkedExecutableKind kind, ElementHolder holder) {
if (holder.getTopLevelVariable(name) == null) {
TopLevelVariableElementImpl variable =
new TopLevelVariableElementImpl(name, -1);
variable.synthetic = true;
variable.final2 = kind == UnlinkedExecutableKind.getter;
holder.addTopLevelVariable(variable);
return variable;
} else {
// TODO(paulberry): if adding a setter where there was previously
// only a getter, remove "final" modifier.
// TODO(paulberry): what if the getter and setter have a type mismatch?
throw new UnimplementedError();
}
}
/**
* Resynthesize an [ImportElement].
*/
ImportElement buildImport(UnlinkedImport serializedImport, int dependency) {
bool isSynthetic = serializedImport.isImplicit;
// TODO(paulberry): it seems problematic for the offset to be 0 for
// non-synthetic imports, since it is used to disambiguate location.
ImportElementImpl importElement =
new ImportElementImpl(isSynthetic ? -1 : serializedImport.offset);
String absoluteUri = summaryResynthesizer.sourceFactory
.resolveUri(
librarySource, prelinkedLibrary.dependencies[dependency].uri)
.uri
.toString();
importElement.importedLibrary = new LibraryElementHandle(
summaryResynthesizer,
new ElementLocationImpl.con3(<String>[absoluteUri]));
if (isSynthetic) {
importElement.synthetic = true;
} else {
importElement.uri = serializedImport.uri;
}
if (serializedImport.prefixReference != 0) {
UnlinkedReference serializedPrefix =
unlinkedUnits[0].references[serializedImport.prefixReference];
importElement.prefix = new PrefixElementImpl(serializedPrefix.name, -1);
}
importElement.combinators =
serializedImport.combinators.map(buildCombinator).toList();
return importElement;
}
/**
* Main entry point. Resynthesize the [LibraryElement] and return it.
*/
LibraryElement buildLibrary() {
// TODO(paulberry): is it ok to pass -1 for offset and nameLength?
LibraryElementImpl libraryElement = new LibraryElementImpl(
summaryResynthesizer.context, unlinkedUnits[0].libraryName, -1, -1);
CompilationUnitElementImpl definingCompilationUnit =
new CompilationUnitElementImpl(librarySource.shortName);
libraryElement.definingCompilationUnit = definingCompilationUnit;
definingCompilationUnit.source = librarySource;
definingCompilationUnit.librarySource = librarySource;
List<CompilationUnitElement> parts = <CompilationUnitElement>[];
UnlinkedUnit unlinkedDefiningUnit = unlinkedUnits[0];
assert(unlinkedDefiningUnit.publicNamespace.parts.length + 1 ==
prelinkedLibrary.units.length);
for (int i = 1; i < prelinkedLibrary.units.length; i++) {
CompilationUnitElementImpl part = buildPart(
unlinkedDefiningUnit.publicNamespace.parts[i - 1].uri,
unlinkedUnits[i]);
parts.add(part);
}
libraryElement.parts = parts;
List<ImportElement> imports = <ImportElement>[];
for (int i = 0; i < unlinkedDefiningUnit.imports.length; i++) {
imports.add(buildImport(unlinkedDefiningUnit.imports[i],
prelinkedLibrary.importDependencies[i]));
}
libraryElement.imports = imports;
libraryElement.exports =
unlinkedDefiningUnit.publicNamespace.exports.map(buildExport).toList();
populateUnit(definingCompilationUnit, 0);
for (int i = 0; i < parts.length; i++) {
populateUnit(parts[i], i + 1);
}
if (isCoreLibrary) {
ClassElement objectElement = libraryElement.getType('Object');
assert(objectElement != null);
for (ClassElementImpl classElement in delayedObjectSubclasses) {
classElement.supertype = objectElement.type;
}
}
return libraryElement;
}
/**
* Resynthesize a [ParameterElement].
*/
ParameterElement buildParameter(UnlinkedParam serializedParameter) {
ParameterElementImpl parameterElement =
new ParameterElementImpl(serializedParameter.name, -1);
if (serializedParameter.isFunctionTyped) {
FunctionElementImpl parameterTypeElement =
new FunctionElementImpl('', -1);
parameterTypeElement.synthetic = true;
parameterElement.parameters =
serializedParameter.parameters.map(buildParameter).toList();
parameterTypeElement.enclosingElement = parameterElement;
parameterTypeElement.shareParameters(parameterElement.parameters);
if (serializedParameter.type != null) {
parameterTypeElement.returnType = buildType(serializedParameter.type);
} else {
parameterTypeElement.returnType = VoidTypeImpl.instance;
}
parameterElement.type = new FunctionTypeImpl(parameterTypeElement);
} else {
parameterElement.type = buildType(serializedParameter.type);
parameterElement.hasImplicitType = serializedParameter.hasImplicitType;
}
switch (serializedParameter.kind) {
case UnlinkedParamKind.named:
parameterElement.parameterKind = ParameterKind.NAMED;
break;
case UnlinkedParamKind.positional:
parameterElement.parameterKind = ParameterKind.POSITIONAL;
break;
case UnlinkedParamKind.required:
parameterElement.parameterKind = ParameterKind.REQUIRED;
break;
}
return parameterElement;
}
/**
* Create, but do not populate, the [CompilationUnitElement] for a part other
* than the defining compilation unit.
*/
CompilationUnitElementImpl buildPart(
String uri, UnlinkedUnit serializedPart) {
Source unitSource =
summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri);
CompilationUnitElementImpl partUnit =
new CompilationUnitElementImpl(unitSource.shortName);
partUnit.source = unitSource;
partUnit.librarySource = librarySource;
partUnit.uri = uri;
return partUnit;
}
/**
* Build a [DartType] object based on an [UnlinkedTypeRef]. This [DartType]
* may refer to elements in other libraries than the library being
* deserialized, so handles are used to avoid having to deserialize other
* libraries in the process.
*/
DartType buildType(UnlinkedTypeRef type) {
if (type.paramReference != 0) {
// TODO(paulberry): make this work for generic methods.
return currentTypeParameters[
currentTypeParameters.length - type.paramReference].type;
} else {
// TODO(paulberry): handle references to things other than classes (note:
// this should only occur in the case of erroneous code).
// TODO(paulberry): test reference to something inside a part.
// TODO(paulberry): test reference to something inside a part of the
// current lib.
UnlinkedReference reference = unlinkedUnit.references[type.reference];
PrelinkedReference referenceResolution =
prelinkedUnit.references[type.reference];
String referencedLibraryUri;
String partUri;
if (referenceResolution.dependency != 0) {
PrelinkedDependency dependency =
prelinkedLibrary.dependencies[referenceResolution.dependency];
Source referencedLibrarySource = summaryResynthesizer.sourceFactory
.resolveUri(librarySource, dependency.uri);
referencedLibraryUri = referencedLibrarySource.uri.toString();
// TODO(paulberry): consider changing Location format so that this is
// not necessary (2nd string in location should just be the unit
// number).
if (referenceResolution.unit != 0) {
UnlinkedUnit referencedLibraryDefiningUnit =
summaryResynthesizer.getUnlinkedSummary(referencedLibraryUri);
String uri = referencedLibraryDefiningUnit.publicNamespace.parts[
referenceResolution.unit - 1].uri;
Source partSource = summaryResynthesizer.sourceFactory
.resolveUri(referencedLibrarySource, uri);
partUri = partSource.uri.toString();
} else {
partUri = referencedLibraryUri;
}
} else if (referenceResolution.kind ==
PrelinkedReferenceKind.unresolved) {
return summaryResynthesizer.typeProvider.undefinedType;
} else if (reference.name.isEmpty) {
return summaryResynthesizer.typeProvider.dynamicType;
} else {
referencedLibraryUri = librarySource.uri.toString();
if (referenceResolution.unit != 0) {
String uri = unlinkedUnits[0].publicNamespace.parts[
referenceResolution.unit - 1].uri;
Source partSource =
summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri);
partUri = partSource.uri.toString();
} else {
partUri = referencedLibraryUri;
}
}
ElementLocationImpl location = new ElementLocationImpl.con3(
<String>[referencedLibraryUri, partUri, reference.name]);
List<DartType> typeArguments = const <DartType>[];
if (referenceResolution.numTypeParameters != 0) {
typeArguments = <DartType>[];
for (int i = 0; i < referenceResolution.numTypeParameters; i++) {
if (i < type.typeArguments.length) {
typeArguments.add(buildType(type.typeArguments[i]));
} else {
typeArguments.add(summaryResynthesizer.typeProvider.dynamicType);
}
}
}
switch (referenceResolution.kind) {
case PrelinkedReferenceKind.classOrEnum:
return new InterfaceTypeImpl.elementWithNameAndArgs(
new ClassElementHandle(summaryResynthesizer, location),
reference.name,
typeArguments);
case PrelinkedReferenceKind.typedef:
return new FunctionTypeImpl.elementWithNameAndArgs(
new FunctionTypeAliasElementHandle(
summaryResynthesizer, location),
reference.name,
typeArguments);
default:
// TODO(paulberry): figure out how to handle this case (which should
// only occur in the event of erroneous code).
throw new UnimplementedError();
}
}
}
/**
* Resynthesize a [FunctionTypeAliasElement] and place it in the
* [unitHolder].
*/
void buildTypedef(UnlinkedTypedef serializedTypedef) {
try {
currentTypeParameters =
serializedTypedef.typeParameters.map(buildTypeParameter).toList();
for (int i = 0; i < serializedTypedef.typeParameters.length; i++) {
finishTypeParameter(
serializedTypedef.typeParameters[i], currentTypeParameters[i]);
}
FunctionTypeAliasElementImpl functionTypeAliasElement =
new FunctionTypeAliasElementImpl(serializedTypedef.name, -1);
functionTypeAliasElement.parameters =
serializedTypedef.parameters.map(buildParameter).toList();
if (serializedTypedef.returnType != null) {
functionTypeAliasElement.returnType =
buildType(serializedTypedef.returnType);
} else {
functionTypeAliasElement.returnType = VoidTypeImpl.instance;
}
functionTypeAliasElement.type =
new FunctionTypeImpl.forTypedef(functionTypeAliasElement);
functionTypeAliasElement.typeParameters = currentTypeParameters;
unitHolder.addTypeAlias(functionTypeAliasElement);
} finally {
currentTypeParameters = null;
}
}
/**
* Resynthesize a [TypeParameterElement], handling all parts of its except
* its bound.
*
* The bound is deferred until later since it may refer to other type
* parameters that have not been resynthesized yet. To handle the bound,
* call [finishTypeParameter].
*/
TypeParameterElement buildTypeParameter(
UnlinkedTypeParam serializedTypeParameter) {
TypeParameterElementImpl typeParameterElement =
new TypeParameterElementImpl(serializedTypeParameter.name, -1);
typeParameterElement.type = new TypeParameterTypeImpl(typeParameterElement);
return typeParameterElement;
}
/**
* Resynthesize a [TopLevelVariableElement] or [FieldElement].
*/
void buildVariable(UnlinkedVariable serializedVariable,
[ElementHolder holder]) {
if (holder == null) {
TopLevelVariableElementImpl element =
new TopLevelVariableElementImpl(serializedVariable.name, -1);
buildVariableCommonParts(element, serializedVariable);
unitHolder.addTopLevelVariable(element);
buildImplicitAccessors(element, unitHolder);
} else {
FieldElementImpl element =
new FieldElementImpl(serializedVariable.name, -1);
buildVariableCommonParts(element, serializedVariable);
element.static = serializedVariable.isStatic;
holder.addField(element);
buildImplicitAccessors(element, holder);
}
}
/**
* Handle the parts that are common to top level variables and fields.
*/
void buildVariableCommonParts(PropertyInducingElementImpl element,
UnlinkedVariable serializedVariable) {
element.type = buildType(serializedVariable.type);
element.const3 = serializedVariable.isConst;
}
/**
* Finish creating a [TypeParameterElement] by deserializing its bound.
*/
void finishTypeParameter(UnlinkedTypeParam serializedTypeParameter,
TypeParameterElementImpl typeParameterElement) {
if (serializedTypeParameter.bound != null) {
typeParameterElement.bound = buildType(serializedTypeParameter.bound);
}
}
/**
* Populate a [CompilationUnitElement] by deserializing all the elements
* contained in it.
*/
void populateUnit(CompilationUnitElementImpl unit, int unitNum) {
prelinkedUnit = prelinkedLibrary.units[unitNum];
unlinkedUnit = unlinkedUnits[unitNum];
unitHolder = new ElementHolder();
unlinkedUnit.classes.forEach(buildClass);
unlinkedUnit.enums.forEach(buildEnum);
unlinkedUnit.executables.forEach(buildExecutable);
unlinkedUnit.typedefs.forEach(buildTypedef);
unlinkedUnit.variables.forEach(buildVariable);
String absoluteUri = unit.source.uri.toString();
unit.accessors = unitHolder.accessors;
unit.enums = unitHolder.enums;
unit.functions = unitHolder.functions;
List<FunctionTypeAliasElement> typeAliases = unitHolder.typeAliases;
for (FunctionTypeAliasElementImpl typeAlias in typeAliases) {
if (typeAlias.isSynthetic) {
typeAlias.enclosingElement = unit;
}
}
unit.typeAliases = typeAliases.where((e) => !e.isSynthetic).toList();
unit.types = unitHolder.types;
unit.topLevelVariables = unitHolder.topLevelVariables;
Map<String, Element> elementMap = <String, Element>{};
for (ClassElement cls in unit.types) {
elementMap[cls.name] = cls;
}
for (ClassElement cls in unit.enums) {
elementMap[cls.name] = cls;
}
for (FunctionTypeAliasElement typeAlias in unit.functionTypeAliases) {
elementMap[typeAlias.name] = typeAlias;
}
resummarizedElements[absoluteUri] = elementMap;
unitHolder = null;
prelinkedUnit = null;
unlinkedUnit = null;
}
}