blob: 0e5c562fc1340392372c47992c9b34b830bbd65b [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 dart2js.serialization.elements;
import '../common.dart';
import '../constants/constructors.dart';
import '../constants/expressions.dart';
import '../elements/resolution_types.dart';
import '../diagnostics/messages.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart'
show
AmbiguousImportX,
DeferredLoaderGetterElementX,
ErroneousElementX,
WarnOnUseElementX,
WrappedMessage;
import 'constant_serialization.dart';
import 'keys.dart';
import 'modelz.dart';
import 'serialization.dart';
import 'serialization_util.dart';
/// Enum kinds used for encoding [Element]s.
enum SerializedElementKind {
ERROR,
LIBRARY,
COMPILATION_UNIT,
CLASS,
ENUM,
NAMED_MIXIN_APPLICATION,
GENERATIVE_CONSTRUCTOR,
DEFAULT_CONSTRUCTOR,
FACTORY_CONSTRUCTOR,
REDIRECTING_FACTORY_CONSTRUCTOR,
FORWARDING_CONSTRUCTOR,
TOPLEVEL_FIELD,
STATIC_FIELD,
INSTANCE_FIELD,
ENUM_CONSTANT,
TOPLEVEL_FUNCTION,
TOPLEVEL_GETTER,
TOPLEVEL_SETTER,
STATIC_FUNCTION,
STATIC_GETTER,
STATIC_SETTER,
INSTANCE_FUNCTION,
INSTANCE_GETTER,
INSTANCE_SETTER,
LOCAL_FUNCTION,
TYPEDEF,
TYPEVARIABLE,
PARAMETER,
INITIALIZING_FORMAL,
IMPORT,
EXPORT,
PREFIX,
DEFERRED_LOAD_LIBRARY,
LOCAL_VARIABLE,
WARN_ON_USE,
AMBIGUOUS,
EXTERNAL_LIBRARY,
EXTERNAL_LIBRARY_MEMBER,
EXTERNAL_CLASS_MEMBER,
EXTERNAL_CONSTRUCTOR,
}
/// Set of serializers used to serialize different kinds of elements by
/// encoding into them into [ObjectEncoder]s.
///
/// This class is called from the [Serializer] when an [Element] needs
/// serialization. The [ObjectEncoder] ensures that any [Element],
/// [ResolutionDartType], and [ConstantExpression] that the serialized [Element]
/// depends upon are also serialized.
const List<ElementSerializer> ELEMENT_SERIALIZERS = const [
const ErrorSerializer(),
const LibrarySerializer(),
const CompilationUnitSerializer(),
const PrefixSerializer(),
const DeferredLoadLibrarySerializer(),
const ClassSerializer(),
const ConstructorSerializer(),
const FieldSerializer(),
const FunctionSerializer(),
const TypedefSerializer(),
const TypeVariableSerializer(),
const ParameterSerializer(),
const ImportSerializer(),
const ExportSerializer(),
const LocalVariableSerializer(),
const WarnOnUseSerializer(),
const AmbiguousSerializer(),
];
/// Interface for a function that can serialize a set of element kinds.
abstract class ElementSerializer {
/// Returns the [SerializedElementKind] for [element] if this serializer
/// supports serialization of [element] or `null` otherwise.
SerializedElementKind getSerializedKind(Element element);
/// Serializes [element] into the [encoder] using the [kind] computed
/// by [getSerializedKind].
void serialize(
Element element, ObjectEncoder encoder, SerializedElementKind kind);
}
class SerializerUtil {
/// Serialize the declared members of [element] into [encoder].
static void serializeMembers(
Iterable<Element> members, ObjectEncoder encoder) {
MapEncoder mapEncoder = encoder.createMap(Key.MEMBERS);
for (Element member in members) {
String name = member.name;
if (member.isSetter) {
name = '$name,=';
}
mapEncoder.setElement(name, member);
}
}
/// Serialize the source position of [element] into [encoder].
static void serializePosition(Element element, ObjectEncoder encoder) {
if (element.sourcePosition != null) {
SourceSpan position = element.sourcePosition;
encoder.setInt(Key.OFFSET, position.begin);
// TODO(johnniwinther): What is the base URI in the case?
if (position.uri != element.compilationUnit.script.resourceUri) {
encoder.setUri(Key.URI, element.library.canonicalUri, position.uri);
}
int length = position.end - position.begin;
if (element.name.length != length) {
encoder.setInt(Key.LENGTH, length);
}
}
}
/// Serialize the metadata of [element] into [encoder].
static void serializeMetadata(Element element, ObjectEncoder encoder) {
ListEncoder list;
void encodeAnnotation(MetadataAnnotation metadata) {
ObjectEncoder object = list.createObject();
object.setElement(Key.ELEMENT, metadata.annotatedElement);
SourceSpan sourcePosition = metadata.sourcePosition;
// TODO(johnniwinther): What is the base URI here?
object.setUri(Key.URI, sourcePosition.uri, sourcePosition.uri);
object.setInt(Key.OFFSET, sourcePosition.begin);
object.setInt(Key.LENGTH, sourcePosition.end - sourcePosition.begin);
object.setConstant(Key.CONSTANT, metadata.constant);
}
if (element.metadata.isNotEmpty) {
list = encoder.createList(Key.METADATA);
element.metadata.forEach(encodeAnnotation);
}
if (element.isPatched && element.implementation.metadata.isNotEmpty) {
list ??= encoder.createList(Key.METADATA);
element.implementation.metadata.forEach(encodeAnnotation);
}
}
/// Serialize the parent relation for [element] into [encoder], i.e library,
/// enclosing class, and compilation unit references.
static void serializeParentRelation(Element element, ObjectEncoder encoder) {
if (element.enclosingClass != null) {
encoder.setElement(Key.CLASS, element.enclosingClass);
if (element.enclosingClass.compilationUnit != element.compilationUnit) {
encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
}
} else {
encoder.setElement(Key.LIBRARY, element.library);
encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
}
}
/// Serialize the parameters of [element] into [encoder].
static void serializeParameters(
FunctionElement element, ObjectEncoder encoder) {
ResolutionFunctionType type = element.type;
encoder.setType(Key.RETURN_TYPE, type.returnType);
encoder.setElements(Key.PARAMETERS, element.parameters);
}
/// Returns a function that adds the underlying declared elements for a
/// particular element into [set].
///
/// For instance, for an [AbstractFieldElement] the getter and setter elements
/// are added, if available.
static flattenElements(Set<Element> set) {
return (Element element) {
if (element.isPatch) return;
// TODO(johnniwinther): Handle ambiguous elements.
if (element.isAmbiguous) return;
if (element.isAbstractField) {
AbstractFieldElement abstractField = element;
if (abstractField.getter != null) {
set.add(abstractField.getter);
}
if (abstractField.setter != null) {
set.add(abstractField.setter);
}
} else {
set.add(element);
}
};
}
}
class ErrorSerializer implements ElementSerializer {
const ErrorSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isError) {
return SerializedElementKind.ERROR;
}
return null;
}
void serialize(ErroneousElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
encoder.setElement(Key.ENCLOSING, element.enclosingElement);
encoder.setString(Key.NAME, element.name);
encoder.setEnum(Key.MESSAGE_KIND, element.messageKind);
serializeMessageArguments(encoder, Key.ARGUMENTS, element.messageArguments);
}
}
class LibrarySerializer implements ElementSerializer {
const LibrarySerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isLibrary) {
return SerializedElementKind.LIBRARY;
}
return null;
}
static List<Element> getMembers(LibraryElement element) {
List<Element> members = <Element>[];
element.implementation.forEachLocalMember((Element member) {
if (!member.isPatch) {
members.add(member);
}
});
return members;
}
static List<CompilationUnitElement> getCompilationUnits(
LibraryElement element) {
List<CompilationUnitElement> compilationUnits = <CompilationUnitElement>[];
compilationUnits.addAll(element.compilationUnits.toList());
if (element.isPatched) {
compilationUnits.addAll(element.implementation.compilationUnits.toList());
}
return compilationUnits;
}
static List<ImportElement> getImports(LibraryElement element) {
List<ImportElement> imports = <ImportElement>[];
imports.addAll(element.imports);
if (element.isPatched) {
imports.addAll(element.implementation.imports);
}
return imports;
}
static List<Element> getImportedElements(LibraryElement element) {
Set<Element> importedElements = new Set<Element>();
element.forEachImport(SerializerUtil.flattenElements(importedElements));
if (element.isPatched) {
element.implementation
.forEachImport(SerializerUtil.flattenElements(importedElements));
}
return importedElements.toList();
}
static List<Element> getExportedElements(LibraryElement element) {
Set<Element> exportedElements = new Set<Element>();
element.forEachExport(SerializerUtil.flattenElements(exportedElements));
return exportedElements.toList();
}
void serialize(LibraryElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
SerializerUtil.serializeMetadata(element, encoder);
encoder.setUri(
Key.CANONICAL_URI, element.canonicalUri, element.canonicalUri);
encoder.setString(Key.LIBRARY_NAME, element.libraryName);
SerializerUtil.serializeMembers(getMembers(element), encoder);
encoder.setElement(Key.COMPILATION_UNIT, element.entryCompilationUnit);
encoder.setElements(Key.COMPILATION_UNITS, getCompilationUnits(element));
encoder.setElements(Key.IMPORTS, getImports(element));
encoder.setElements(Key.EXPORTS, element.exports);
List<Element> importedElements = getImportedElements(element);
encoder.setElements(Key.IMPORT_SCOPE, importedElements);
encoder.setElements(Key.EXPORT_SCOPE, getExportedElements(element));
Map<Element, Iterable<ImportElement>> importsForMap =
<Element, Iterable<ImportElement>>{};
/// Map imports for [importedElement] in importsForMap.
///
/// Imports are mapped to [AbstractFieldElement] which are not serialized
/// so we use getter (or setter if there is no getter) as the key.
void addImportsForElement(Element importedElement) {
Element key = importedElement;
if (importedElement.isDeferredLoaderGetter) {
// Use [importedElement].
} else if (importedElement.isGetter) {
GetterElement getter = importedElement;
importedElement = getter.abstractField;
} else if (importedElement.isSetter) {
SetterElement setter = importedElement;
if (setter.getter != null) {
return;
}
importedElement = setter.abstractField;
}
importsForMap.putIfAbsent(
key, () => element.getImportsFor(importedElement));
}
for (ImportElement import in getImports(element)) {
if (import.prefix != null) {
Set<Element> importedElements = new Set<Element>();
import.prefix.forEachLocalMember(
SerializerUtil.flattenElements(importedElements));
importedElements.forEach(addImportsForElement);
}
}
importedElements.forEach(addImportsForElement);
ListEncoder importsForEncoder = encoder.createList(Key.IMPORTS_FOR);
importsForMap
.forEach((Element importedElement, Iterable<ImportElement> imports) {
ObjectEncoder objectEncoder = importsForEncoder.createObject();
objectEncoder.setElement(Key.ELEMENT, importedElement);
objectEncoder.setElements(Key.IMPORTS, imports);
});
}
}
class CompilationUnitSerializer implements ElementSerializer {
const CompilationUnitSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isCompilationUnit) {
return SerializedElementKind.COMPILATION_UNIT;
}
return null;
}
void serialize(CompilationUnitElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
SerializerUtil.serializeMetadata(element, encoder);
encoder.setElement(Key.LIBRARY, element.library);
encoder.setUri(
Key.URI, element.library.canonicalUri, element.script.resourceUri);
List<Element> elements = <Element>[];
element.forEachLocalMember((e) {
if (!element.isPatch) {
elements.add(e);
}
});
encoder.setElements(Key.ELEMENTS, elements);
}
}
class ClassSerializer implements ElementSerializer {
const ClassSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isClass) {
ClassElement cls = element;
if (cls.isEnumClass) {
return SerializedElementKind.ENUM;
} else if (cls.isMixinApplication) {
if (!cls.isUnnamedMixinApplication) {
return SerializedElementKind.NAMED_MIXIN_APPLICATION;
}
} else {
return SerializedElementKind.CLASS;
}
}
return null;
}
static List<Element> getMembers(ClassElement element) {
List<Element> members = <Element>[];
element.forEachLocalMember(members.add);
if (element.isPatched) {
element.implementation.forEachLocalMember((Element member) {
if (!member.isPatch) {
members.add(member);
}
});
}
return members;
}
void serialize(
ClassElement element, ObjectEncoder encoder, SerializedElementKind kind) {
SerializerUtil.serializeMetadata(element, encoder);
encoder.setElement(Key.LIBRARY, element.library);
encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
encoder.setString(Key.NAME, element.name);
SerializerUtil.serializePosition(element, encoder);
encoder.setTypes(Key.TYPE_VARIABLES, element.typeVariables);
encoder.setBool(Key.IS_ABSTRACT, element.isAbstract);
SerializerUtil.serializeMembers(getMembers(element), encoder);
encoder.setBool(Key.IS_PROXY, element.isProxy);
encoder.setBool(Key.IS_INJECTED, element.isInjected);
if (kind == SerializedElementKind.ENUM) {
EnumClassElement enumClass = element;
encoder.setElements(Key.FIELDS, enumClass.enumValues);
}
if (element.isObject) return;
List<ResolutionInterfaceType> mixins = <ResolutionInterfaceType>[];
ClassElement superclass = element.superclass;
while (superclass.isUnnamedMixinApplication) {
MixinApplicationElement mixinElement = superclass;
mixins.add(element.thisType.asInstanceOf(mixinElement.mixin));
superclass = mixinElement.superclass;
}
mixins = mixins.reversed.toList();
ResolutionInterfaceType supertype =
element.thisType.asInstanceOf(superclass);
encoder.setType(Key.SUPERTYPE, supertype);
encoder.setTypes(Key.MIXINS, mixins);
encoder.setTypes(Key.INTERFACES, element.interfaces.toList());
ResolutionFunctionType callType = element.declaration.callType;
if (callType != null) {
encoder.setType(Key.CALL_TYPE, element.callType);
}
if (element.isMixinApplication) {
MixinApplicationElement mixinElement = element;
encoder.setType(Key.MIXIN, mixinElement.mixinType);
}
}
}
class ConstructorSerializer implements ElementSerializer {
const ConstructorSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isGenerativeConstructor) {
ConstructorElement constructor = element;
if (constructor.enclosingClass.isNamedMixinApplication) {
return SerializedElementKind.FORWARDING_CONSTRUCTOR;
} else if (constructor.definingConstructor != null) {
return SerializedElementKind.DEFAULT_CONSTRUCTOR;
} else {
return SerializedElementKind.GENERATIVE_CONSTRUCTOR;
}
} else if (element.isFactoryConstructor) {
ConstructorElement constructor = element;
if (constructor.isRedirectingFactory) {
return SerializedElementKind.REDIRECTING_FACTORY_CONSTRUCTOR;
} else {
return SerializedElementKind.FACTORY_CONSTRUCTOR;
}
}
return null;
}
void serialize(ConstructorElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
SerializerUtil.serializeParentRelation(element, encoder);
if (kind == SerializedElementKind.FORWARDING_CONSTRUCTOR) {
serializeElementReference(element.enclosingClass, Key.ELEMENT, Key.NAME,
encoder, element.definingConstructor);
} else {
SerializerUtil.serializeMetadata(element, encoder);
encoder.setType(Key.TYPE, element.type);
encoder.setString(Key.NAME, element.name);
SerializerUtil.serializePosition(element, encoder);
SerializerUtil.serializeParameters(element, encoder);
encoder.setBool(Key.IS_CONST, element.isConst);
encoder.setBool(Key.IS_EXTERNAL, element.isExternal);
encoder.setBool(Key.IS_INJECTED, element.isInjected);
if (element.isConst && !element.isFromEnvironmentConstructor) {
ConstantConstructor constantConstructor = element.constantConstructor;
ObjectEncoder constantEncoder = encoder.createObject(Key.CONSTRUCTOR);
const ConstantConstructorSerializer()
.visit(constantConstructor, constantEncoder);
}
if (kind == SerializedElementKind.GENERATIVE_CONSTRUCTOR) {
encoder.setBool(Key.IS_REDIRECTING, element.isRedirectingGenerative);
}
encoder.setElement(Key.EFFECTIVE_TARGET, element.effectiveTarget);
if (kind == SerializedElementKind.REDIRECTING_FACTORY_CONSTRUCTOR) {
encoder.setType(
Key.EFFECTIVE_TARGET_TYPE,
element
.computeEffectiveTargetType(element.enclosingClass.thisType));
encoder.setElement(Key.IMMEDIATE_REDIRECTION_TARGET,
element.immediateRedirectionTarget);
encoder.setBool(Key.EFFECTIVE_TARGET_IS_MALFORMED,
element.isEffectiveTargetMalformed);
if (element.redirectionDeferredPrefix != null) {
encoder.setElement(Key.PREFIX, element.redirectionDeferredPrefix);
}
}
}
}
}
class FieldSerializer implements ElementSerializer {
const FieldSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isField) {
if (element.isTopLevel) return SerializedElementKind.TOPLEVEL_FIELD;
if (element.isStatic) {
if (element is EnumConstantElement) {
return SerializedElementKind.ENUM_CONSTANT;
}
return SerializedElementKind.STATIC_FIELD;
}
if (element.isInstanceMember) return SerializedElementKind.INSTANCE_FIELD;
}
return null;
}
void serialize(
FieldElement element, ObjectEncoder encoder, SerializedElementKind kind) {
encoder.setString(Key.NAME, element.name);
SerializerUtil.serializeMetadata(element, encoder);
SerializerUtil.serializePosition(element, encoder);
encoder.setType(Key.TYPE, element.type);
encoder.setBool(Key.IS_FINAL, element.isFinal);
encoder.setBool(Key.IS_CONST, element.isConst);
encoder.setBool(Key.IS_INJECTED, element.isInjected);
ConstantExpression constant = element.constant;
if (constant != null) {
encoder.setConstant(Key.CONSTANT, constant);
}
SerializerUtil.serializeParentRelation(element, encoder);
if (element is EnumConstantElement) {
EnumConstantElement enumConstant = element;
encoder.setInt(Key.INDEX, enumConstant.index);
}
}
}
class FunctionSerializer implements ElementSerializer {
const FunctionSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isDeferredLoaderGetter) {
return null;
}
if (element.isFunction) {
if (element.isTopLevel) return SerializedElementKind.TOPLEVEL_FUNCTION;
if (element.isStatic) return SerializedElementKind.STATIC_FUNCTION;
if (element.isInstanceMember) {
return SerializedElementKind.INSTANCE_FUNCTION;
}
if (element.isLocal) {
return SerializedElementKind.LOCAL_FUNCTION;
}
}
if (element.isGetter) {
if (element.isTopLevel) return SerializedElementKind.TOPLEVEL_GETTER;
if (element.isStatic) return SerializedElementKind.STATIC_GETTER;
if (element.isInstanceMember) {
return SerializedElementKind.INSTANCE_GETTER;
}
}
if (element.isSetter) {
if (element.isTopLevel) return SerializedElementKind.TOPLEVEL_SETTER;
if (element.isStatic) return SerializedElementKind.STATIC_SETTER;
if (element.isInstanceMember) {
return SerializedElementKind.INSTANCE_SETTER;
}
}
return null;
}
void serialize(FunctionElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
encoder.setString(Key.NAME, element.name);
SerializerUtil.serializeMetadata(element, encoder);
SerializerUtil.serializePosition(element, encoder);
SerializerUtil.serializeParameters(element, encoder);
encoder.setType(Key.TYPE, element.type);
if (element.isFunction) {
encoder.setBool(Key.IS_OPERATOR, element.isOperator);
encoder.setEnum(Key.ASYNC_MARKER, element.asyncMarker);
} else if (element.isGetter) {
encoder.setEnum(Key.ASYNC_MARKER, element.asyncMarker);
}
SerializerUtil.serializeParentRelation(element, encoder);
encoder.setBool(Key.IS_EXTERNAL, element.isExternal);
encoder.setBool(Key.IS_ABSTRACT, element.isAbstract);
encoder.setBool(Key.IS_INJECTED, element.isInjected);
if (element.isLocal) {
LocalFunctionElement localFunction = element;
encoder.setElement(
Key.EXECUTABLE_CONTEXT, localFunction.executableContext);
}
encoder.setTypes(Key.TYPE_VARIABLES, element.typeVariables);
}
}
class TypedefSerializer implements ElementSerializer {
const TypedefSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isTypedef) {
return SerializedElementKind.TYPEDEF;
}
return null;
}
void serialize(TypedefElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
encoder.setString(Key.NAME, element.name);
SerializerUtil.serializeMetadata(element, encoder);
SerializerUtil.serializePosition(element, encoder);
encoder.setType(Key.ALIAS, element.alias);
encoder.setElement(Key.LIBRARY, element.library);
encoder.setTypes(Key.TYPE_VARIABLES, element.typeVariables);
encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
}
}
class TypeVariableSerializer implements ElementSerializer {
const TypeVariableSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isTypeVariable) {
return SerializedElementKind.TYPEVARIABLE;
}
return null;
}
void serialize(TypeVariableElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
encoder.setElement(Key.TYPE_DECLARATION, element.typeDeclaration);
encoder.setString(Key.NAME, element.name);
SerializerUtil.serializeMetadata(element, encoder);
SerializerUtil.serializePosition(element, encoder);
encoder.setType(Key.TYPE, element.type);
encoder.setInt(Key.INDEX, element.index);
encoder.setType(Key.BOUND, element.bound);
}
}
class ParameterSerializer implements ElementSerializer {
const ParameterSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isRegularParameter) {
return SerializedElementKind.PARAMETER;
} else if (element.isInitializingFormal) {
return SerializedElementKind.INITIALIZING_FORMAL;
}
return null;
}
void serialize(ParameterElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
encoder.setElement(Key.FUNCTION, element.functionDeclaration);
encoder.setString(Key.NAME, element.name);
SerializerUtil.serializeMetadata(element, encoder);
SerializerUtil.serializePosition(element, encoder);
encoder.setType(Key.TYPE, element.type);
encoder.setBool(Key.IS_OPTIONAL, element.isOptional);
encoder.setBool(Key.IS_NAMED, element.isNamed);
encoder.setBool(Key.IS_FINAL, element.isFinal);
if (element.isOptional) {
encoder.setConstant(Key.CONSTANT, element.constant);
}
if (element.isInitializingFormal) {
InitializingFormalElement initializingFormal = element;
encoder.setElement(Key.FIELD, initializingFormal.fieldElement);
}
}
}
class LocalVariableSerializer implements ElementSerializer {
const LocalVariableSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isVariable) {
return SerializedElementKind.LOCAL_VARIABLE;
}
return null;
}
void serialize(LocalVariableElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
encoder.setString(Key.NAME, element.name);
SerializerUtil.serializeMetadata(element, encoder);
SerializerUtil.serializePosition(element, encoder);
encoder.setType(Key.TYPE, element.type);
encoder.setBool(Key.IS_FINAL, element.isFinal);
encoder.setBool(Key.IS_CONST, element.isConst);
if (element.isConst) {
ConstantExpression constant = element.constant;
encoder.setConstant(Key.CONSTANT, constant);
}
encoder.setElement(Key.EXECUTABLE_CONTEXT, element.executableContext);
}
}
class ImportSerializer implements ElementSerializer {
const ImportSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isImport) {
return SerializedElementKind.IMPORT;
}
return null;
}
void serialize(ImportElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
SerializerUtil.serializeMetadata(element, encoder);
encoder.setElement(Key.LIBRARY, element.library);
encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
encoder.setElement(Key.LIBRARY_DEPENDENCY, element.importedLibrary);
if (element.prefix != null) {
encoder.setElement(Key.PREFIX, element.prefix);
}
encoder.setBool(Key.IS_DEFERRED, element.isDeferred);
// TODO(johnniwinther): What is the base for the URI?
encoder.setUri(Key.URI, element.uri, element.uri);
}
}
class ExportSerializer implements ElementSerializer {
const ExportSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isExport) {
return SerializedElementKind.EXPORT;
}
return null;
}
void serialize(ExportElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
SerializerUtil.serializeMetadata(element, encoder);
encoder.setElement(Key.LIBRARY, element.library);
encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
encoder.setElement(Key.LIBRARY_DEPENDENCY, element.exportedLibrary);
// TODO(johnniwinther): What is the base for the URI?
encoder.setUri(Key.URI, element.uri, element.uri);
}
}
class PrefixSerializer implements ElementSerializer {
const PrefixSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isPrefix) {
return SerializedElementKind.PREFIX;
}
return null;
}
void serialize(PrefixElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
encoder.setString(Key.NAME, element.name);
encoder.setElement(Key.LIBRARY, element.library);
encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
encoder.setBool(Key.IS_DEFERRED, element.isDeferred);
Set<Element> members = new Set<Element>();
element.forEachLocalMember(SerializerUtil.flattenElements(members));
encoder.setElements(Key.MEMBERS, members);
if (element.isDeferred) {
encoder.setElement(Key.IMPORT, element.deferredImport);
encoder.setElement(Key.GETTER, element.loadLibrary);
}
}
}
class DeferredLoadLibrarySerializer implements ElementSerializer {
const DeferredLoadLibrarySerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isDeferredLoaderGetter) {
return SerializedElementKind.DEFERRED_LOAD_LIBRARY;
}
return null;
}
void serialize(GetterElement element, ObjectEncoder encoder,
SerializedElementKind kind) {
encoder.setElement(Key.PREFIX, element.enclosingElement);
}
}
class WarnOnUseSerializer implements ElementSerializer {
const WarnOnUseSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isWarnOnUse) {
return SerializedElementKind.WARN_ON_USE;
}
return null;
}
void serialize(WarnOnUseElementX element, ObjectEncoder encoder,
SerializedElementKind kind) {
encoder.setElement(Key.ENCLOSING, element.enclosingElement);
encoder.setElement(Key.ELEMENT, element.wrappedElement);
serializeWrappedMessage(encoder, Key.WARNING, element.warning);
serializeWrappedMessage(encoder, Key.INFO, element.info);
}
}
class AmbiguousSerializer implements ElementSerializer {
const AmbiguousSerializer();
SerializedElementKind getSerializedKind(Element element) {
if (element.isAmbiguous) {
return SerializedElementKind.AMBIGUOUS;
}
return null;
}
void serialize(AmbiguousImportX element, ObjectEncoder encoder,
SerializedElementKind kind) {
// TODO(johnniwinther): Also support [DuplicateElementX] if serialization
// of code with compile-time errors is supported.
encoder.setElement(Key.ENCLOSING, element.enclosingElement);
encoder.setElement(Key.EXISTING, element.existingElement);
encoder.setElement(Key.NEW, element.newElement);
encoder.setEnum(Key.MESSAGE_KIND, element.messageKind);
serializeMessageArguments(encoder, Key.ARGUMENTS, element.messageArguments);
}
}
/// Utility class for deserializing [Element]s.
///
/// This is used by the [Deserializer].
class ElementDeserializer {
/// Deserializes an [Element] from an [ObjectDecoder].
///
/// The class is called from the [Deserializer] when an [Element]
/// needs deserialization. The [ObjectDecoder] ensures that any [Element],
/// [ResolutionDartType], and [ConstantExpression] that the deserialized
/// [Element] depends upon are available.
static Element deserialize(
ObjectDecoder decoder, SerializedElementKind elementKind) {
switch (elementKind) {
case SerializedElementKind.ERROR:
Element enclosing = decoder.getElement(Key.ENCLOSING);
String name = decoder.getString(Key.NAME);
MessageKind messageKind =
decoder.getEnum(Key.MESSAGE_KIND, MessageKind.values);
Map<String, String> arguments =
deserializeMessageArguments(decoder, Key.ARGUMENTS);
return new ErroneousElementX(messageKind, arguments, name, enclosing);
case SerializedElementKind.LIBRARY:
return new LibraryElementZ(decoder);
case SerializedElementKind.COMPILATION_UNIT:
return new CompilationUnitElementZ(decoder);
case SerializedElementKind.CLASS:
return new ClassElementZ(decoder);
case SerializedElementKind.ENUM:
return new EnumClassElementZ(decoder);
case SerializedElementKind.NAMED_MIXIN_APPLICATION:
return new NamedMixinApplicationElementZ(decoder);
case SerializedElementKind.TOPLEVEL_FIELD:
return new TopLevelFieldElementZ(decoder);
case SerializedElementKind.STATIC_FIELD:
return new StaticFieldElementZ(decoder);
case SerializedElementKind.ENUM_CONSTANT:
return new EnumConstantElementZ(decoder);
case SerializedElementKind.INSTANCE_FIELD:
return new InstanceFieldElementZ(decoder);
case SerializedElementKind.GENERATIVE_CONSTRUCTOR:
return new GenerativeConstructorElementZ(decoder);
case SerializedElementKind.DEFAULT_CONSTRUCTOR:
return new DefaultConstructorElementZ(decoder);
case SerializedElementKind.FACTORY_CONSTRUCTOR:
return new FactoryConstructorElementZ(decoder);
case SerializedElementKind.REDIRECTING_FACTORY_CONSTRUCTOR:
return new RedirectingFactoryConstructorElementZ(decoder);
case SerializedElementKind.FORWARDING_CONSTRUCTOR:
ClassElement cls = decoder.getElement(Key.CLASS);
Element definingConstructor =
deserializeElementReference(cls, Key.ELEMENT, Key.NAME, decoder);
return new ForwardingConstructorElementZ(cls, definingConstructor);
case SerializedElementKind.TOPLEVEL_FUNCTION:
return new TopLevelFunctionElementZ(decoder);
case SerializedElementKind.STATIC_FUNCTION:
return new StaticFunctionElementZ(decoder);
case SerializedElementKind.INSTANCE_FUNCTION:
return new InstanceFunctionElementZ(decoder);
case SerializedElementKind.LOCAL_FUNCTION:
return new LocalFunctionElementZ(decoder);
case SerializedElementKind.TOPLEVEL_GETTER:
return new TopLevelGetterElementZ(decoder);
case SerializedElementKind.STATIC_GETTER:
return new StaticGetterElementZ(decoder);
case SerializedElementKind.INSTANCE_GETTER:
return new InstanceGetterElementZ(decoder);
case SerializedElementKind.TOPLEVEL_SETTER:
return new TopLevelSetterElementZ(decoder);
case SerializedElementKind.STATIC_SETTER:
return new StaticSetterElementZ(decoder);
case SerializedElementKind.INSTANCE_SETTER:
return new InstanceSetterElementZ(decoder);
case SerializedElementKind.TYPEDEF:
return new TypedefElementZ(decoder);
case SerializedElementKind.TYPEVARIABLE:
return new TypeVariableElementZ(decoder);
case SerializedElementKind.PARAMETER:
return new LocalParameterElementZ(decoder);
case SerializedElementKind.INITIALIZING_FORMAL:
return new InitializingFormalElementZ(decoder);
case SerializedElementKind.IMPORT:
return new ImportElementZ(decoder);
case SerializedElementKind.EXPORT:
return new ExportElementZ(decoder);
case SerializedElementKind.PREFIX:
return new PrefixElementZ(decoder);
case SerializedElementKind.DEFERRED_LOAD_LIBRARY:
return new DeferredLoaderGetterElementX(decoder.getElement(Key.PREFIX));
case SerializedElementKind.LOCAL_VARIABLE:
return new LocalVariableElementZ(decoder);
case SerializedElementKind.WARN_ON_USE:
Element enclosing = decoder.getElement(Key.ENCLOSING);
Element element = decoder.getElement(Key.ELEMENT);
WrappedMessage warning =
deserializeWrappedMessage(decoder, Key.WARNING);
WrappedMessage info = deserializeWrappedMessage(decoder, Key.INFO);
return new WarnOnUseElementX(warning, info, enclosing, element);
case SerializedElementKind.AMBIGUOUS:
Element enclosingElement = decoder.getElement(Key.ENCLOSING);
Element existingElement = decoder.getElement(Key.EXISTING);
Element newElement = decoder.getElement(Key.NEW);
MessageKind messageKind =
decoder.getEnum(Key.MESSAGE_KIND, MessageKind.values);
Map messageArguments =
deserializeMessageArguments(decoder, Key.ARGUMENTS);
return new AmbiguousImportX(messageKind, messageArguments,
enclosingElement, existingElement, newElement);
case SerializedElementKind.EXTERNAL_LIBRARY:
case SerializedElementKind.EXTERNAL_LIBRARY_MEMBER:
case SerializedElementKind.EXTERNAL_CLASS_MEMBER:
case SerializedElementKind.EXTERNAL_CONSTRUCTOR:
break;
}
throw new UnsupportedError("Unexpected element kind '${elementKind}.");
}
}