| // 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 serialization.elements; |
| |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/src/dart/element/type.dart'; |
| import 'package:analyzer/src/generated/resolver.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:analyzer/src/summary/format.dart'; |
| import 'package:analyzer/src/summary/name_filter.dart'; |
| |
| /** |
| * Serialize all the elements in [lib] to a summary using [ctx] as the context |
| * for building the summary, and using [typeProvider] to find built-in types. |
| */ |
| LibrarySerializationResult serializeLibrary( |
| LibraryElement lib, TypeProvider typeProvider) { |
| var serializer = new _LibrarySerializer(lib, typeProvider); |
| PrelinkedLibraryBuilder prelinked = serializer.serializeLibrary(); |
| return new LibrarySerializationResult( |
| prelinked, serializer.unlinkedUnits, serializer.unitUris); |
| } |
| |
| /** |
| * Data structure holding the result of serializing a [LibraryElement]. |
| */ |
| class LibrarySerializationResult { |
| /** |
| * Pre-linked information the given library. |
| */ |
| final PrelinkedLibraryBuilder prelinked; |
| |
| /** |
| * Unlinked information for the compilation units constituting the library. |
| * The zeroth entry in the list is the defining compilation unit; the |
| * remaining entries are the parts, in the order listed in the defining |
| * compilation unit's part declarations. |
| */ |
| final List<UnlinkedUnitBuilder> unlinkedUnits; |
| |
| /** |
| * Absolute URI of each compilation unit appearing in the library. |
| */ |
| final List<String> unitUris; |
| |
| LibrarySerializationResult(this.prelinked, this.unlinkedUnits, this.unitUris); |
| } |
| |
| /** |
| * Instances of this class keep track of intermediate state during |
| * serialization of a single library.` |
| */ |
| class _LibrarySerializer { |
| /** |
| * The library to be serialized. |
| */ |
| final LibraryElement libraryElement; |
| |
| /** |
| * The type provider. This is used to locate the library for `dart:core`. |
| */ |
| final TypeProvider typeProvider; |
| |
| /** |
| * List of objects which should be written to [PrelinkedLibrary.units]. |
| */ |
| final List<PrelinkedUnitBuilder> prelinkedUnits = <PrelinkedUnitBuilder>[]; |
| |
| /** |
| * List of unlinked units corresponding to the pre-linked units in |
| * [prelinkedUnits], |
| */ |
| final List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[]; |
| |
| /** |
| * List of absolute URIs of the compilation units in the library. |
| */ |
| final List<String> unitUris = <String>[]; |
| |
| /** |
| * Map from [LibraryElement] to the index of the entry in the "dependency |
| * table" that refers to it. |
| */ |
| final Map<LibraryElement, int> dependencyMap = <LibraryElement, int>{}; |
| |
| /** |
| * The "dependency table". This is the list of objects which should be |
| * written to [PrelinkedLibrary.dependencies]. |
| */ |
| final List<PrelinkedDependencyBuilder> dependencies = |
| <PrelinkedDependencyBuilder>[]; |
| |
| /** |
| * The prelinked portion of the "imports table". This is the list of ints |
| * which should be written to [PrelinkedLibrary.imports]. |
| */ |
| final List<int> prelinkedImports = <int>[]; |
| |
| /** |
| * Map from [Element] to the index of the entry in the "references table" |
| * that refers to it. |
| */ |
| final Map<Element, int> referenceMap = <Element, int>{}; |
| |
| /** |
| * The unlinked portion of the "references table". This is the list of |
| * objects which should be written to [UnlinkedUnit.references]. |
| */ |
| List<UnlinkedReferenceBuilder> unlinkedReferences; |
| |
| /** |
| * The prelinked portion of the "references table". This is the list of |
| * objects which should be written to [PrelinkedUnit.references]. |
| */ |
| List<PrelinkedReferenceBuilder> prelinkedReferences; |
| |
| //final Map<String, int> prefixIndices = <String, int>{}; |
| |
| /** |
| * Index into the "references table" representing an unresolved reference, if |
| * such an index exists. `null` if no such entry has been made in the |
| * references table yet. |
| */ |
| int unresolvedReferenceIndex = null; |
| |
| /** |
| * Set of libraries which have been seen so far while visiting the transitive |
| * closure of exports. |
| */ |
| final Set<LibraryElement> librariesAddedToTransitiveExportClosure = |
| new Set<LibraryElement>(); |
| |
| /** |
| * Map from imported element to the prefix which may be used to refer to that |
| * element; elements for which no prefix is needed are absent from this map. |
| */ |
| final Map<Element, PrefixElement> prefixMap = <Element, PrefixElement>{}; |
| |
| _LibrarySerializer(this.libraryElement, this.typeProvider) { |
| dependencies.add(encodePrelinkedDependency()); |
| dependencyMap[libraryElement] = 0; |
| } |
| |
| /** |
| * Retrieve the library element for `dart:core`. |
| */ |
| LibraryElement get coreLibrary => typeProvider.objectType.element.library; |
| |
| /** |
| * Add all classes, enums, typedefs, executables, and top level variables |
| * from the given compilation unit [element] to the library summary. |
| * [unitNum] indicates the ordinal position of this compilation unit in the |
| * library. |
| */ |
| void addCompilationUnitElements(CompilationUnitElement element, int unitNum) { |
| UnlinkedUnitBuilder b = new UnlinkedUnitBuilder(); |
| referenceMap.clear(); |
| unlinkedReferences = <UnlinkedReferenceBuilder>[encodeUnlinkedReference()]; |
| prelinkedReferences = <PrelinkedReferenceBuilder>[ |
| encodePrelinkedReference(kind: PrelinkedReferenceKind.classOrEnum) |
| ]; |
| List<UnlinkedPublicNameBuilder> names = <UnlinkedPublicNameBuilder>[]; |
| for (PropertyAccessorElement accessor in element.accessors) { |
| if (accessor.isPublic) { |
| names.add(encodeUnlinkedPublicName( |
| kind: PrelinkedReferenceKind.other, |
| name: accessor.name, |
| numTypeParameters: accessor.typeParameters.length)); |
| } |
| } |
| for (ClassElement cls in element.types) { |
| if (cls.isPublic) { |
| names.add(encodeUnlinkedPublicName( |
| kind: PrelinkedReferenceKind.classOrEnum, |
| name: cls.name, |
| numTypeParameters: cls.typeParameters.length)); |
| } |
| } |
| for (ClassElement enm in element.enums) { |
| if (enm.isPublic) { |
| names.add(encodeUnlinkedPublicName( |
| kind: PrelinkedReferenceKind.classOrEnum, name: enm.name)); |
| } |
| } |
| for (FunctionElement function in element.functions) { |
| if (function.isPublic) { |
| names.add(encodeUnlinkedPublicName( |
| kind: PrelinkedReferenceKind.other, |
| name: function.name, |
| numTypeParameters: function.typeParameters.length)); |
| } |
| } |
| for (FunctionTypeAliasElement typedef in element.functionTypeAliases) { |
| if (typedef.isPublic) { |
| names.add(encodeUnlinkedPublicName( |
| kind: PrelinkedReferenceKind.typedef, |
| name: typedef.name, |
| numTypeParameters: typedef.typeParameters.length)); |
| } |
| } |
| if (unitNum == 0) { |
| if (libraryElement.name.isNotEmpty) { |
| b.libraryName = libraryElement.name; |
| b.libraryNameOffset = libraryElement.nameOffset; |
| b.libraryNameLength = libraryElement.nameLength; |
| b.libraryDocumentationComment = serializeDocumentation(libraryElement); |
| } |
| b.publicNamespace = encodeUnlinkedPublicNamespace( |
| exports: libraryElement.exports.map(serializeExportPublic).toList(), |
| parts: libraryElement.parts |
| .map((CompilationUnitElement e) => e.uri) |
| .toList(), |
| names: names); |
| b.exports = libraryElement.exports.map(serializeExportNonPublic).toList(); |
| b.imports = libraryElement.imports.map(serializeImport).toList(); |
| b.parts = libraryElement.parts |
| .map((CompilationUnitElement e) => |
| encodeUnlinkedPart(uriOffset: e.uriOffset, uriEnd: e.uriEnd)) |
| .toList(); |
| } else { |
| // TODO(paulberry): we need to figure out a way to record library, part, |
| // import, and export declarations that appear in non-defining |
| // compilation units (even though such declarations are prohibited by the |
| // language), so that if the user makes code changes that cause a |
| // non-defining compilation unit to become a defining compilation unit, |
| // we can create a correct summary by simply re-linking. |
| b.publicNamespace = encodeUnlinkedPublicNamespace(names: names); |
| } |
| b.classes = element.types.map(serializeClass).toList(); |
| b.enums = element.enums.map(serializeEnum).toList(); |
| b.typedefs = element.functionTypeAliases.map(serializeTypedef).toList(); |
| List<UnlinkedExecutableBuilder> executables = |
| element.functions.map(serializeExecutable).toList(); |
| for (PropertyAccessorElement accessor in element.accessors) { |
| if (!accessor.isSynthetic) { |
| executables.add(serializeExecutable(accessor)); |
| } |
| } |
| b.executables = executables; |
| List<UnlinkedVariableBuilder> variables = <UnlinkedVariableBuilder>[]; |
| for (PropertyAccessorElement accessor in element.accessors) { |
| if (accessor.isSynthetic && accessor.isGetter) { |
| PropertyInducingElement variable = accessor.variable; |
| if (variable != null) { |
| assert(!variable.isSynthetic); |
| variables.add(serializeVariable(variable)); |
| } |
| } |
| } |
| b.variables = variables; |
| b.references = unlinkedReferences; |
| unlinkedUnits.add(b); |
| prelinkedUnits.add(encodePrelinkedUnit(references: prelinkedReferences)); |
| unitUris.add(element.source.uri.toString()); |
| unlinkedReferences = null; |
| prelinkedReferences = null; |
| } |
| |
| /** |
| * Add [exportedLibrary] (and the transitive closure of all libraries it |
| * exports) to the dependency table ([PrelinkedLibrary.dependencies]). |
| */ |
| void addTransitiveExportClosure(LibraryElement exportedLibrary) { |
| if (librariesAddedToTransitiveExportClosure.add(exportedLibrary)) { |
| serializeDependency(exportedLibrary); |
| for (LibraryElement transitiveExport |
| in exportedLibrary.exportedLibraries) { |
| addTransitiveExportClosure(transitiveExport); |
| } |
| } |
| } |
| |
| /** |
| * Fill in [prefixMap] using information from [libraryElement.imports]. |
| */ |
| void computePrefixMap() { |
| for (ImportElement import in libraryElement.imports) { |
| if (import.prefix == null) { |
| continue; |
| } |
| import.importedLibrary.exportNamespace.definedNames |
| .forEach((String name, Element e) { |
| if (new NameFilter.forNamespaceCombinators(import.combinators) |
| .accepts(name)) { |
| prefixMap[e] = import.prefix; |
| } |
| }); |
| } |
| } |
| |
| /** |
| * Compute the appropriate De Bruijn index to represent the given type |
| * parameter [type]. |
| */ |
| int findTypeParameterIndex(TypeParameterType type, Element context) { |
| int index = 0; |
| while (context != null) { |
| List<TypeParameterElement> typeParameters; |
| if (context is ClassElement) { |
| typeParameters = context.typeParameters; |
| } else if (context is FunctionTypeAliasElement) { |
| typeParameters = context.typeParameters; |
| } else if (context is ExecutableElement) { |
| typeParameters = context.typeParameters; |
| } |
| if (typeParameters != null) { |
| for (int i = 0; i < typeParameters.length; i++) { |
| TypeParameterElement param = typeParameters[i]; |
| if (param == type.element) { |
| return index + typeParameters.length - i; |
| } |
| } |
| index += typeParameters.length; |
| } |
| context = context.enclosingElement; |
| } |
| throw new StateError('Unbound type parameter $type'); |
| } |
| |
| /** |
| * Serialize the given [classElement], creating an [UnlinkedClass]. |
| */ |
| UnlinkedClassBuilder serializeClass(ClassElement classElement) { |
| UnlinkedClassBuilder b = new UnlinkedClassBuilder(); |
| b.name = classElement.name; |
| b.nameOffset = classElement.nameOffset; |
| b.typeParameters = |
| classElement.typeParameters.map(serializeTypeParam).toList(); |
| if (classElement.supertype == null) { |
| b.hasNoSupertype = true; |
| } else if (!classElement.supertype.isObject) { |
| b.supertype = serializeTypeRef(classElement.supertype, classElement); |
| } |
| b.mixins = classElement.mixins |
| .map((InterfaceType t) => serializeTypeRef(t, classElement)) |
| .toList(); |
| b.interfaces = classElement.interfaces |
| .map((InterfaceType t) => serializeTypeRef(t, classElement)) |
| .toList(); |
| List<UnlinkedVariableBuilder> fields = <UnlinkedVariableBuilder>[]; |
| List<UnlinkedExecutableBuilder> executables = <UnlinkedExecutableBuilder>[]; |
| for (ConstructorElement executable in classElement.constructors) { |
| if (!executable.isSynthetic) { |
| executables.add(serializeExecutable(executable)); |
| } |
| } |
| for (MethodElement executable in classElement.methods) { |
| executables.add(serializeExecutable(executable)); |
| } |
| for (PropertyAccessorElement accessor in classElement.accessors) { |
| if (!accessor.isSynthetic) { |
| executables.add(serializeExecutable(accessor)); |
| } else if (accessor.isGetter) { |
| PropertyInducingElement field = accessor.variable; |
| if (field != null && !field.isSynthetic) { |
| fields.add(serializeVariable(field)); |
| } |
| } |
| } |
| b.fields = fields; |
| b.executables = executables; |
| b.isAbstract = classElement.isAbstract; |
| b.isMixinApplication = classElement.isMixinApplication; |
| b.documentationComment = serializeDocumentation(classElement); |
| return b; |
| } |
| |
| /** |
| * Serialize the given [combinator] into an [UnlinkedCombinator]. |
| */ |
| UnlinkedCombinatorBuilder serializeCombinator( |
| NamespaceCombinator combinator) { |
| UnlinkedCombinatorBuilder b = new UnlinkedCombinatorBuilder(); |
| if (combinator is ShowElementCombinator) { |
| b.shows = combinator.shownNames; |
| } else if (combinator is HideElementCombinator) { |
| b.hides = combinator.hiddenNames; |
| } |
| return b; |
| } |
| |
| /** |
| * Return the index of the entry in the dependency table |
| * ([PrelinkedLibrary.dependencies]) for the given [dependentLibrary]. A new |
| * entry is added to the table if necessary to satisfy the request. |
| */ |
| int serializeDependency(LibraryElement dependentLibrary) { |
| return dependencyMap.putIfAbsent(dependentLibrary, () { |
| int index = dependencies.length; |
| List<String> parts = dependentLibrary.parts |
| .map((CompilationUnitElement e) => e.source.uri.toString()) |
| .toList(); |
| dependencies.add(encodePrelinkedDependency( |
| uri: dependentLibrary.source.uri.toString(), parts: parts)); |
| return index; |
| }); |
| } |
| |
| /** |
| * Serialize documentation from the given [element], creating an |
| * [UnlinkedDocumentationComment]. |
| * |
| * If [element] has no documentation, `null` is returned. |
| */ |
| UnlinkedDocumentationCommentBuilder serializeDocumentation(Element element) { |
| if (element.documentationComment == null) { |
| return null; |
| } |
| return encodeUnlinkedDocumentationComment( |
| text: element.documentationComment, |
| offset: element.docRange.offset, |
| length: element.docRange.length); |
| } |
| |
| /** |
| * Return the index of the entry in the references table |
| * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references]) |
| * representing the pseudo-type `dynamic`. |
| */ |
| int serializeDynamicReference() => 0; |
| |
| /** |
| * Serialize the given [enumElement], creating an [UnlinkedEnum]. |
| */ |
| UnlinkedEnumBuilder serializeEnum(ClassElement enumElement) { |
| UnlinkedEnumBuilder b = new UnlinkedEnumBuilder(); |
| b.name = enumElement.name; |
| b.nameOffset = enumElement.nameOffset; |
| List<UnlinkedEnumValueBuilder> values = <UnlinkedEnumValueBuilder>[]; |
| for (FieldElement field in enumElement.fields) { |
| if (field.isConst && field.type.element == enumElement) { |
| values.add(encodeUnlinkedEnumValue( |
| name: field.name, |
| nameOffset: field.nameOffset, |
| documentationComment: serializeDocumentation(field))); |
| } |
| } |
| b.values = values; |
| b.documentationComment = serializeDocumentation(enumElement); |
| return b; |
| } |
| |
| /** |
| * Serialize the given [executableElement], creating an [UnlinkedExecutable]. |
| */ |
| UnlinkedExecutableBuilder serializeExecutable( |
| ExecutableElement executableElement) { |
| UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder(); |
| b.name = executableElement.name; |
| b.nameOffset = executableElement.nameOffset; |
| if (executableElement is! ConstructorElement && |
| !executableElement.type.returnType.isVoid) { |
| b.returnType = serializeTypeRef( |
| executableElement.type.returnType, executableElement); |
| } |
| b.typeParameters = |
| executableElement.typeParameters.map(serializeTypeParam).toList(); |
| b.parameters = |
| executableElement.type.parameters.map(serializeParam).toList(); |
| if (executableElement is PropertyAccessorElement) { |
| if (executableElement.isGetter) { |
| b.kind = UnlinkedExecutableKind.getter; |
| } else { |
| b.kind = UnlinkedExecutableKind.setter; |
| } |
| } else if (executableElement is ConstructorElement) { |
| b.kind = UnlinkedExecutableKind.constructor; |
| b.isConst = executableElement.isConst; |
| b.isFactory = executableElement.isFactory; |
| } else { |
| b.kind = UnlinkedExecutableKind.functionOrMethod; |
| } |
| b.isAbstract = executableElement.isAbstract; |
| b.isStatic = executableElement.isStatic && |
| executableElement.enclosingElement is ClassElement; |
| b.hasImplicitReturnType = executableElement.hasImplicitReturnType; |
| b.isExternal = executableElement.isExternal; |
| b.documentationComment = serializeDocumentation(executableElement); |
| return b; |
| } |
| |
| /** |
| * Serialize the given [exportElement] into an [UnlinkedExportNonPublic]. |
| */ |
| UnlinkedExportNonPublicBuilder serializeExportNonPublic( |
| ExportElement exportElement) { |
| UnlinkedExportNonPublicBuilder b = new UnlinkedExportNonPublicBuilder(); |
| b.offset = exportElement.nameOffset; |
| b.uriOffset = exportElement.uriOffset; |
| b.uriEnd = exportElement.uriEnd; |
| return b; |
| } |
| |
| /** |
| * Serialize the given [exportElement] into an [UnlinkedExportPublic]. |
| */ |
| UnlinkedExportPublicBuilder serializeExportPublic( |
| ExportElement exportElement) { |
| UnlinkedExportPublicBuilder b = new UnlinkedExportPublicBuilder(); |
| b.uri = exportElement.uri; |
| b.combinators = exportElement.combinators.map(serializeCombinator).toList(); |
| return b; |
| } |
| |
| /** |
| * Serialize the given [importElement] yielding an [UnlinkedImportBuilder]. |
| * Also, add pre-linked information about it to the [prelinkedImports] list. |
| */ |
| UnlinkedImportBuilder serializeImport(ImportElement importElement) { |
| UnlinkedImportBuilder b = new UnlinkedImportBuilder(); |
| b.isDeferred = importElement.isDeferred; |
| b.offset = importElement.nameOffset; |
| b.combinators = importElement.combinators.map(serializeCombinator).toList(); |
| if (importElement.prefix != null) { |
| b.prefixReference = serializePrefix(importElement.prefix); |
| b.prefixOffset = importElement.prefix.nameOffset; |
| } |
| if (importElement.isSynthetic) { |
| b.isImplicit = true; |
| } else { |
| b.uri = importElement.uri; |
| b.uriOffset = importElement.uriOffset; |
| b.uriEnd = importElement.uriEnd; |
| } |
| addTransitiveExportClosure(importElement.importedLibrary); |
| prelinkedImports.add(serializeDependency(importElement.importedLibrary)); |
| return b; |
| } |
| |
| /** |
| * Serialize the whole library element into a [PrelinkedLibrary]. Should be |
| * called exactly once for each instance of [_LibrarySerializer]. |
| * |
| * The unlinked compilation units are stored in [unlinkedUnits], and their |
| * absolute URIs are stored in [unitUris]. |
| */ |
| PrelinkedLibraryBuilder serializeLibrary() { |
| computePrefixMap(); |
| PrelinkedLibraryBuilder pb = new PrelinkedLibraryBuilder(); |
| addCompilationUnitElements(libraryElement.definingCompilationUnit, 0); |
| for (int i = 0; i < libraryElement.parts.length; i++) { |
| addCompilationUnitElements(libraryElement.parts[i], i + 1); |
| } |
| pb.units = prelinkedUnits; |
| pb.dependencies = dependencies; |
| pb.importDependencies = prelinkedImports; |
| return pb; |
| } |
| |
| /** |
| * Serialize the given [parameter] into an [UnlinkedParam]. |
| */ |
| UnlinkedParamBuilder serializeParam(ParameterElement parameter, |
| [Element context]) { |
| context ??= parameter; |
| UnlinkedParamBuilder b = new UnlinkedParamBuilder(); |
| b.name = parameter.name; |
| b.nameOffset = parameter.nameOffset; |
| switch (parameter.parameterKind) { |
| case ParameterKind.REQUIRED: |
| b.kind = UnlinkedParamKind.required; |
| break; |
| case ParameterKind.POSITIONAL: |
| b.kind = UnlinkedParamKind.positional; |
| break; |
| case ParameterKind.NAMED: |
| b.kind = UnlinkedParamKind.named; |
| break; |
| } |
| b.isInitializingFormal = parameter.isInitializingFormal; |
| DartType type = parameter.type; |
| if (type is FunctionType) { |
| b.isFunctionTyped = true; |
| if (!type.returnType.isVoid) { |
| b.type = serializeTypeRef(type.returnType, parameter); |
| } |
| b.parameters = type.parameters |
| .map((parameter) => serializeParam(parameter, context)) |
| .toList(); |
| } else { |
| b.type = serializeTypeRef(type, context); |
| b.hasImplicitType = parameter.hasImplicitType; |
| } |
| return b; |
| } |
| |
| /** |
| * Serialize the given [prefix] into an index into the references table. |
| */ |
| int serializePrefix(PrefixElement element) { |
| return referenceMap.putIfAbsent(element, () { |
| assert(unlinkedReferences.length == prelinkedReferences.length); |
| int index = unlinkedReferences.length; |
| unlinkedReferences.add(encodeUnlinkedReference(name: element.name)); |
| prelinkedReferences |
| .add(encodePrelinkedReference(kind: PrelinkedReferenceKind.prefix)); |
| return index; |
| }); |
| } |
| |
| /** |
| * Serialize the given [typedefElement], creating an [UnlinkedTypedef]. |
| */ |
| UnlinkedTypedefBuilder serializeTypedef( |
| FunctionTypeAliasElement typedefElement) { |
| UnlinkedTypedefBuilder b = new UnlinkedTypedefBuilder(); |
| b.name = typedefElement.name; |
| b.nameOffset = typedefElement.nameOffset; |
| b.typeParameters = |
| typedefElement.typeParameters.map(serializeTypeParam).toList(); |
| if (!typedefElement.returnType.isVoid) { |
| b.returnType = |
| serializeTypeRef(typedefElement.returnType, typedefElement); |
| } |
| b.parameters = typedefElement.parameters.map(serializeParam).toList(); |
| b.documentationComment = serializeDocumentation(typedefElement); |
| return b; |
| } |
| |
| /** |
| * Serialize the given [typeParameter] into an [UnlinkedTypeParam]. |
| */ |
| UnlinkedTypeParamBuilder serializeTypeParam( |
| TypeParameterElement typeParameter) { |
| UnlinkedTypeParamBuilder b = new UnlinkedTypeParamBuilder(); |
| b.name = typeParameter.name; |
| b.nameOffset = typeParameter.nameOffset; |
| if (typeParameter.bound != null) { |
| b.bound = serializeTypeRef(typeParameter.bound, typeParameter); |
| } |
| return b; |
| } |
| |
| /** |
| * Serialize the given [type] into an [UnlinkedTypeRef]. |
| */ |
| UnlinkedTypeRefBuilder serializeTypeRef(DartType type, Element context) { |
| UnlinkedTypeRefBuilder b = new UnlinkedTypeRefBuilder(); |
| if (type is TypeParameterType) { |
| b.paramReference = findTypeParameterIndex(type, context); |
| } else { |
| Element element = type.element; |
| LibraryElement dependentLibrary = element.library; |
| if (dependentLibrary == null) { |
| assert(type.isDynamic); |
| if (type is UndefinedTypeImpl) { |
| b.reference = serializeUnresolvedReference(); |
| } else { |
| b.reference = serializeDynamicReference(); |
| } |
| } else { |
| b.reference = referenceMap.putIfAbsent(element, () { |
| assert(unlinkedReferences.length == prelinkedReferences.length); |
| CompilationUnitElement unitElement = |
| element.getAncestor((Element e) => e is CompilationUnitElement); |
| int unit = dependentLibrary.units.indexOf(unitElement); |
| assert(unit != -1); |
| int numTypeParameters = 0; |
| if (element is TypeParameterizedElement) { |
| numTypeParameters = element.typeParameters.length; |
| } |
| // Figure out a prefix that may be used to refer to the given type. |
| // TODO(paulberry): to avoid subtle relinking inconsistencies we |
| // should use the actual prefix from the AST (a given type may be |
| // reachable via multiple prefixes), but sadly, this information is |
| // not recorded in the element model. |
| int prefixReference = 0; |
| PrefixElement prefix = prefixMap[element]; |
| if (prefix != null) { |
| prefixReference = serializePrefix(prefix); |
| } |
| int index = unlinkedReferences.length; |
| unlinkedReferences.add(encodeUnlinkedReference( |
| name: element.name, prefixReference: prefixReference)); |
| prelinkedReferences.add(encodePrelinkedReference( |
| dependency: serializeDependency(dependentLibrary), |
| kind: element is FunctionTypeAliasElement |
| ? PrelinkedReferenceKind.typedef |
| : PrelinkedReferenceKind.classOrEnum, |
| unit: unit, |
| numTypeParameters: numTypeParameters)); |
| return index; |
| }); |
| } |
| List<DartType> typeArguments; |
| if (type is InterfaceType) { |
| typeArguments = type.typeArguments; |
| } else if (type is FunctionType) { |
| typeArguments = type.typeArguments; |
| } |
| if (typeArguments != null && |
| typeArguments.any((DartType argument) => !argument.isDynamic)) { |
| b.typeArguments = typeArguments |
| .map((DartType t) => serializeTypeRef(t, context)) |
| .toList(); |
| } |
| } |
| return b; |
| } |
| |
| /** |
| * Return the index of the entry in the references table |
| * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references]) used for |
| * unresolved references. A new entry is added to the table if necessary to |
| * satisfy the request. |
| */ |
| int serializeUnresolvedReference() { |
| // TODO(paulberry): in order for relinking to work, we need to record the |
| // name and prefix of the unresolved symbol. This is not (yet) encoded in |
| // the element model. For the moment we use a name that can't possibly |
| // ever exist. |
| if (unresolvedReferenceIndex == null) { |
| assert(unlinkedReferences.length == prelinkedReferences.length); |
| unresolvedReferenceIndex = unlinkedReferences.length; |
| unlinkedReferences.add(encodeUnlinkedReference(name: '*unresolved*')); |
| prelinkedReferences.add( |
| encodePrelinkedReference(kind: PrelinkedReferenceKind.unresolved)); |
| } |
| return unresolvedReferenceIndex; |
| } |
| |
| /** |
| * Serialize the given [variable], creating an [UnlinkedVariable]. |
| */ |
| UnlinkedVariableBuilder serializeVariable(PropertyInducingElement variable) { |
| UnlinkedVariableBuilder b = new UnlinkedVariableBuilder(); |
| b.name = variable.name; |
| b.nameOffset = variable.nameOffset; |
| b.type = serializeTypeRef(variable.type, variable); |
| b.isStatic = variable.isStatic && variable.enclosingElement is ClassElement; |
| b.isFinal = variable.isFinal; |
| b.isConst = variable.isConst; |
| b.hasImplicitType = variable.hasImplicitType; |
| b.documentationComment = serializeDocumentation(variable); |
| return b; |
| } |
| } |