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

Unified Diff: pkg/analyzer/lib/src/summary/resynthesize.dart

Issue 1526243002: Introduce code to resynthesize element models from summaries. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analyzer/lib/src/generated/element_handle.dart ('k') | pkg/analyzer/test/generated/resolver_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/summary/resynthesize.dart
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
new file mode 100644
index 0000000000000000000000000000000000000000..fdb87ca2b3fe672424294271f171025325b9bde9
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -0,0 +1,941 @@
+// 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 summary for a given
+ * URI.
+ */
+typedef PrelinkedLibrary GetSummaryCallback(String uri);
+
+/**
+ * Specialization of [FunctionTypeImpl] used for function types resynthesized
+ * from summaries.
+ */
+class ResynthesizedFunctionTypeImpl extends FunctionTypeImpl
+ with ResynthesizedType {
+ final SummaryResynthesizer summaryResynthesizer;
+
+ ResynthesizedFunctionTypeImpl(
+ FunctionTypeAliasElement element, String name, this.summaryResynthesizer)
+ : super.elementWithName(element, name);
+
+ int get _numTypeParameters {
+ FunctionTypeAliasElement element = this.element;
+ return element.typeParameters.length;
+ }
+}
+
+/**
+ * Specialization of [InterfaceTypeImpl] used for interface types resynthesized
+ * from summaries.
+ */
+class ResynthesizedInterfaceTypeImpl extends InterfaceTypeImpl
+ with ResynthesizedType {
+ final SummaryResynthesizer summaryResynthesizer;
+
+ ResynthesizedInterfaceTypeImpl(
+ ClassElement element, String name, this.summaryResynthesizer)
+ : super.elementWithName(element, name);
+
+ int get _numTypeParameters => element.typeParameters.length;
+}
+
+/**
+ * Common code for types resynthesized from summaries. This code takes care of
+ * filling in the appropriate number of copies of `dynamic` when it is queried
+ * for type parameters on a bare type reference (i.e. it converts `List` to
+ * `List<dynamic>`).
+ */
+abstract class ResynthesizedType implements DartType {
+ /**
+ * The type arguments, if known. Otherwise `null`.
+ */
+ List<DartType> _typeArguments;
+
+ SummaryResynthesizer get summaryResynthesizer;
+
+ List<DartType> get typeArguments {
+ if (_typeArguments == null) {
+ // Default to replicating "dynamic" as many times as the class element
+ // requires.
+ _typeArguments = new List<DartType>.filled(
+ _numTypeParameters, summaryResynthesizer.typeProvider.dynamicType);
+ }
+ return _typeArguments;
+ }
+
+ int get _numTypeParameters;
+}
+
+/**
+ * Implementation of [ElementResynthesizer] used when resynthesizing an element
+ * model from summaries.
+ */
+class SummaryResynthesizer extends ElementResynthesizer {
+ /**
+ * Callback used to obtain the summary for a given URI.
+ */
+ final GetSummaryCallback getSummary;
+
+ /**
+ * 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.
+ *
+ * TODO(paulberry): will this create a chicken-and-egg problem when trying to
+ * resynthesize the core library from summaries?
+ */
+ 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.getSummary, this.sourceFactory)
+ : super(context),
+ typeProvider = context.typeProvider;
+
+ /**
+ * 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);
+ }
+ Element element = libraryMap[location.components[1]]
scheglov 2015/12/16 01:46:49 Can this expression be null?
Paul Berry 2015/12/16 16:34:20 Good point. It could happen, if files are updated
+ [location.components[2]];
+ if (element == null) {
+ throw new Exception('Failed to resynthesize $location');
+ }
+ assert(element != null);
+ 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, () {
+ PrelinkedLibrary serializedLibrary = getSummary(uri);
+ _LibraryResynthesizer libraryResynthesizer =
+ new _LibraryResynthesizer(this, serializedLibrary, _getSource(uri));
+ 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;
+
+ /**
+ * The library to be resynthesized.
+ */
+ final PrelinkedLibrary prelinkedLibrary;
+
+ /**
+ * [Source] object for the library to be resynthesized.
+ */
+ final Source librarySource;
+
+ /**
+ * [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;
+
+ /**
+ * 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,
+ PrelinkedLibrary serializedLibrary, this.librarySource)
+ : prelinkedLibrary = serializedLibrary;
+
+ /**
+ * 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;
+ if (serializedClass.isMixinApplication) {
+ classElement = new ClassElementImpl(serializedClass.name, -1);
+ classElement.setModifier(Modifier.MIXIN_APPLICATION, true);
+ } else {
+ classElement = new ClassElementImpl(serializedClass.name, -1);
Brian Wilkerson 2015/12/16 00:29:07 Unless I'm missing something, this line is inside
Paul Berry 2015/12/16 16:34:20 Oops, you're right. Fixed.
+ }
+ InterfaceTypeImpl correspondingType = new InterfaceTypeImpl(classElement);
+ if (serializedClass.supertype != null) {
+ classElement.supertype = buildType(serializedClass.supertype);
+ } else {
+ // TODO(paulberry): don't make Object point to itself.
+ 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.setModifier(Modifier.SYNTHETIC, true);
+ constructor.returnType = correspondingType;
+ constructor.type = new FunctionTypeImpl(constructor);
+ 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();
+ combinator.shownNames = serializedCombinator.shows
+ .map((UnlinkedCombinatorName n) => n.name)
+ .toList();
+ return combinator;
+ } else {
+ HideElementCombinatorImpl combinator = new HideElementCombinatorImpl();
+ combinator.hiddenNames = serializedCombinator.hides
+ .map((UnlinkedCombinatorName n) => n.name)
+ .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);
+ if (serializedExecutable.isFactory) {
+ constructorElement.setModifier(Modifier.FACTORY, true);
scheglov 2015/12/16 01:46:49 ConstructorElementImpl has a setter "factory". ...
Paul Berry 2015/12/16 16:34:20 Good point. I'll do a follow-up commit that repla
+ }
+ if (serializedExecutable.isConst) {
+ constructorElement.setModifier(Modifier.CONST, true);
+ }
+ holder.addConstructor(constructorElement);
+ }
+
+ /**
+ * Resynthesize the [ClassElement] corresponding to an enum, along with the
+ * associated fields and implicit accessors.
+ */
+ void buildEnum(UnlinkedEnum serializedEnum) {
+ ClassElementImpl classElement =
+ new ClassElementImpl(serializedEnum.name, -1);
Brian Wilkerson 2015/12/16 00:29:07 I assume that we'll get offsets at some point.
Paul Berry 2015/12/16 16:34:20 Yes, that's the plan. I've added a TODO comment t
+ classElement.setModifier(Modifier.ENUM, 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.setModifier(Modifier.FINAL, true);
+ indexField.setModifier(Modifier.SYNTHETIC, true);
+ indexField.type = summaryResynthesizer.typeProvider.intType;
+ memberHolder.addField(indexField);
+ buildImplicitAccessors(indexField, memberHolder);
+ FieldElementImpl valuesField = new ConstFieldElementImpl('values', -1);
+ valuesField.setModifier(Modifier.SYNTHETIC, true);
+ valuesField.setModifier(Modifier.CONST, true);
+ valuesField.setModifier(Modifier.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.setModifier(Modifier.CONST, true);
+ valueField.setModifier(Modifier.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;
+ }
+ String name = serializedExecutable.name;
+ if (name.endsWith('=')) {
+ name = name.substring(0, name.length - 1);
+ }
+ UnlinkedExecutableKind kind = serializedExecutable.kind;
+ 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.setModifier(
+ Modifier.STATIC, serializedExecutable.isStatic);
+ holder.addMethod(executableElement);
+ }
+ break;
+ case UnlinkedExecutableKind.getter:
+ case UnlinkedExecutableKind.setter:
+ PropertyAccessorElementImpl executableElement =
+ new PropertyAccessorElementImpl(name, -1);
+ if (isTopLevel) {
+ executableElement.setModifier(Modifier.STATIC, true);
+ } else {
+ executableElement.setModifier(
+ Modifier.STATIC, serializedExecutable.isStatic);
+ }
+ buildExecutableCommonParts(executableElement, serializedExecutable);
+ DartType type;
+ if (kind == UnlinkedExecutableKind.getter) {
+ executableElement.setModifier(Modifier.GETTER, true);
+ type = executableElement.returnType;
+ } else {
+ executableElement.setModifier(Modifier.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 {
+ implicitVariable = buildImplicitField(name, type, kind, holder);
+ implicitVariable.setModifier(
+ Modifier.STATIC, serializedExecutable.isStatic);
+ }
+ 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(executableElement);
+ if (serializedExecutable.hasImplicitReturnType) {
+ executableElement.setModifier(Modifier.IMPLICIT_TYPE, true);
+ }
+ }
+
+ /**
+ * 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);
+ if (serializedField.isConst) {
+ fieldElement.setModifier(Modifier.CONST, true);
+ }
+ 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.setModifier(Modifier.GETTER, true);
+ getter.setModifier(Modifier.STATIC, element.isStatic);
+ getter.setModifier(Modifier.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.setModifier(Modifier.SETTER, true);
+ setter.setModifier(Modifier.STATIC, element.isStatic);
+ setter.setModifier(Modifier.SYNTHETIC, true);
+ setter.parameters = <ParameterElement>[
+ new ParameterElementImpl('_$name', -1)
+ ..setModifier(Modifier.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].
+ */
+ PropertyInducingElementImpl buildImplicitField(String name, DartType type,
+ UnlinkedExecutableKind kind, ElementHolder holder) {
+ if (holder.getField(name) == null) {
+ FieldElementImpl field = new FieldElementImpl(name, -1);
+ field.setModifier(Modifier.SYNTHETIC, true);
+ if (kind == UnlinkedExecutableKind.getter) {
+ field.setModifier(Modifier.FINAL, true);
+ }
+ field.type = type;
+ holder.addField(field);
+ return field;
+ } 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();
+ }
+ }
+
+ /**
+ * 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.setModifier(Modifier.SYNTHETIC, true);
+ if (kind == UnlinkedExecutableKind.getter) {
+ variable.setModifier(Modifier.FINAL, true);
+ }
+ 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.setModifier(Modifier.SYNTHETIC, true);
+ } else {
+ importElement.uri = serializedImport.uri;
+ }
+ if (serializedImport.prefixReference != 0) {
+ UnlinkedReference serializedPrefix = prelinkedLibrary.units[0]
+ .unlinked
+ .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,
+ prelinkedLibrary.units[0].unlinked.libraryName,
+ -1,
+ -1);
+ CompilationUnitElementImpl definingCompilationUnit =
+ new CompilationUnitElementImpl(librarySource.shortName);
+ libraryElement.definingCompilationUnit = definingCompilationUnit;
+ definingCompilationUnit.source = librarySource;
+ definingCompilationUnit.librarySource = librarySource;
+ List<CompilationUnitElement> parts = <CompilationUnitElement>[];
+ UnlinkedUnit unlinkedDefiningUnit = prelinkedLibrary.units[0].unlinked;
+ assert(
+ unlinkedDefiningUnit.parts.length + 1 == prelinkedLibrary.units.length);
+ for (int i = 1; i < prelinkedLibrary.units.length; i++) {
+ CompilationUnitElementImpl part = buildPart(
+ unlinkedDefiningUnit.parts[i - 1].uri,
+ prelinkedLibrary.units[i].unlinked);
+ 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.exports.map(buildExport).toList();
+ populateUnit(definingCompilationUnit, 0);
+ for (int i = 0; i < parts.length; i++) {
+ populateUnit(parts[i], i + 1);
+ }
+ 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.setModifier(Modifier.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);
+ if (serializedParameter.hasImplicitType) {
+ parameterElement.setModifier(Modifier.IMPLICIT_TYPE, true);
+ }
+ }
+ 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 =
+ prelinkedUnit.unlinked.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();
+ PrelinkedLibrary referencedLibrary =
+ summaryResynthesizer.getSummary(referencedLibraryUri);
+ // 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) {
+ String uri = referencedLibrary.units[0].unlinked.parts[0].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 = prelinkedLibrary.units[0].unlinked.parts[
+ referenceResolution.unit - 1].uri;
+ Source partSource =
+ summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri);
+ partUri = partSource.uri.toString();
+ } else {
+ partUri = referencedLibraryUri;
+ }
+ }
+ ResynthesizedType resynthesizedType;
+ ElementLocationImpl location = new ElementLocationImpl.con3(
+ <String>[referencedLibraryUri, partUri, reference.name]);
+ switch (referenceResolution.kind) {
+ case PrelinkedReferenceKind.classOrEnum:
+ resynthesizedType = new ResynthesizedInterfaceTypeImpl(
+ new ClassElementHandle(summaryResynthesizer, location),
+ reference.name,
+ summaryResynthesizer);
+ break;
+ case PrelinkedReferenceKind.typedef:
+ resynthesizedType = new ResynthesizedFunctionTypeImpl(
+ new FunctionTypeAliasElementHandle(
+ summaryResynthesizer, location),
+ reference.name,
+ summaryResynthesizer);
+ break;
+ default:
+ // TODO(paulberry): figure out how to handle this case (which should
+ // only occur in the event of erroneous code).
+ throw new UnimplementedError();
+ }
+ if (type.typeArguments.isNotEmpty) {
+ resynthesizedType._typeArguments =
+ type.typeArguments.map(buildType).toList();
+ }
+ return resynthesizedType;
+ }
+ }
+
+ /**
+ * 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);
+ 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.setModifier(Modifier.CONST, serializedVariable.isConst);
+ element.setModifier(Modifier.STATIC, serializedVariable.isStatic);
+ }
+
+ /**
+ * 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];
+ unitHolder = new ElementHolder();
+ UnlinkedUnit unlinkedUnit = prelinkedUnit.unlinked;
+ 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;
+ }
+}
« no previous file with comments | « pkg/analyzer/lib/src/generated/element_handle.dart ('k') | pkg/analyzer/test/generated/resolver_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698