blob: 6cc91be87aee192c014a6317c963ddeb870ad2fd [file] [log] [blame]
// Copyright (c) 2020, 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.
import 'dart:typed_data';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/resolver/variance.dart';
import 'package:analyzer/src/summary2/ast_binary_tag.dart';
import 'package:analyzer/src/summary2/ast_binary_writer.dart';
import 'package:analyzer/src/summary2/data_writer.dart';
import 'package:analyzer/src/summary2/element_flags.dart';
import 'package:analyzer/src/summary2/reference.dart';
import 'package:analyzer/src/task/inference_error.dart';
import 'package:collection/collection.dart';
class BundleWriter {
late final _BundleWriterReferences _references;
/// The declaration sink - any data that can be read without a need to
/// have any other elements to be available. For example declarations of
/// classes, methods, functions, etc. But not supertypes of classes, or
/// return types of methods - these might reference other classes that we
/// have not read yet. Such resolution data is stored into [_resolutionSink].
///
/// Some resolution data is still written into this sink, if it does not
/// require any other declaration read it later. For example type inference
/// errors, or whether a parameter inherits `covariant`, or a class is
/// simply bounded.
late final _SummaryDataWriter _sink = _SummaryDataWriter(
sink: ByteSink(),
stringIndexer: _stringIndexer,
);
/// The resolution sink - any data that references elements, so can only
/// be read after elements are created and available via its [Reference]s.
late final ResolutionSink _resolutionSink = ResolutionSink(
sink: ByteSink(),
stringIndexer: _stringIndexer,
references: _references,
);
/// [_writeClassElement] remembers the length of data written into [_sink]
/// while writing members. So, when we read, we can skip members initially,
/// and read them later on demand.
List<int> _classMembersLengths = [];
final StringIndexer _stringIndexer = StringIndexer();
final List<_Library> _libraries = [];
BundleWriter(Reference dynamicReference) {
_references = _BundleWriterReferences(dynamicReference);
}
BundleWriterResult finish() {
var baseResolutionOffset = _sink.offset;
_sink.addBytes(_resolutionSink.flushAndTake());
var librariesOffset = _sink.offset;
_sink.writeList<_Library>(_libraries, (library) {
_sink._writeStringReference(library.uriStr);
_sink.writeUInt30(library.offset);
_sink.writeUint30List(library.classMembersOffsets);
});
var referencesOffset = _sink.offset;
_sink.writeUint30List(_references._referenceParents);
_sink._writeStringList(_references._referenceNames);
_references._clearIndexes();
var stringTableOffset = _stringIndexer.write(_sink);
// Write as Uint32 so that we know where it is.
_sink.writeUInt32(baseResolutionOffset);
_sink.writeUInt32(librariesOffset);
_sink.writeUInt32(referencesOffset);
_sink.writeUInt32(stringTableOffset);
var bytes = _sink.flushAndTake();
return BundleWriterResult(
resolutionBytes: bytes,
);
}
void writeLibraryElement(
LibraryElementImpl libraryElement,
List<Reference> exports,
) {
var libraryOffset = _sink.offset;
_classMembersLengths = <int>[];
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(libraryElement.name);
_writeFeatureSet(libraryElement.featureSet);
_writeLanguageVersion(libraryElement.languageVersion);
_resolutionSink._writeAnnotationList(libraryElement.metadata);
_writeList(libraryElement.imports, _writeImportElement);
_writeList(libraryElement.exports, _writeExportElement);
_resolutionSink.writeElement(libraryElement.entryPoint);
LibraryElementFlags.write(_sink, libraryElement);
_sink.writeUInt30(libraryElement.units.length);
for (var unitElement in libraryElement.units) {
_writeUnitElement(unitElement);
}
_writeReferences(exports);
_libraries.add(
_Library(
uriStr: '${libraryElement.source.uri}',
offset: libraryOffset,
classMembersOffsets: _classMembersLengths,
),
);
}
void _writeClassElement(ClassElement element) {
element as ClassElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
ClassElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_writeTypeParameters(element.typeParameters, () {
_resolutionSink.writeType(element.supertype);
_resolutionSink._writeTypeList(element.mixins);
_resolutionSink._writeTypeList(element.interfaces);
if (!element.isMixinApplication) {
var membersOffset = _sink.offset;
_writeList(
element.fields.where((e) => !e.isSynthetic).toList(),
_writeFieldElement,
);
_writeList(
element.accessors.where((e) => !e.isSynthetic).toList(),
_writePropertyAccessorElement,
);
_writeList(element.constructors, _writeConstructorElement);
_writeList(element.methods, _writeMethodElement);
_classMembersLengths.add(_sink.offset - membersOffset);
}
});
}
void _writeConstructorElement(ConstructorElement element) {
element as ConstructorElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
ConstructorElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_resolutionSink.localElements.withElements(element.parameters, () {
_writeList(element.parameters, _writeParameterElement);
_resolutionSink.writeElement(element.superConstructor);
_resolutionSink.writeElement(element.redirectedConstructor);
_resolutionSink._writeNodeList(element.constantInitializers);
});
}
void _writeEnumElement(ClassElement element) {
element as EnumElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
EnumElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_writeTypeParameters(element.typeParameters, () {
_resolutionSink.writeType(element.supertype);
_resolutionSink._writeTypeList(element.mixins);
_resolutionSink._writeTypeList(element.interfaces);
_writeList(
element.fields.where((e) {
return !e.isSynthetic ||
e is FieldElementImpl && e.isSyntheticEnumField;
}).toList(),
_writeFieldElement,
);
_writeList(
element.accessors.where((e) => !e.isSynthetic).toList(),
_writePropertyAccessorElement,
);
_writeList(element.constructors, _writeConstructorElement);
_writeList(element.methods, _writeMethodElement);
});
}
void _writeExportElement(ExportElement element) {
_sink._writeOptionalStringReference(element.uri);
_sink.writeList(element.combinators, _writeNamespaceCombinator);
_resolutionSink._writeAnnotationList(element.metadata);
_resolutionSink.writeElement(element.exportedLibrary);
}
void _writeExtensionElement(ExtensionElement element) {
element as ExtensionElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeOptionalStringReference(element.name);
_sink._writeStringReference(element.reference!.name);
_resolutionSink._writeAnnotationList(element.metadata);
_writeTypeParameters(element.typeParameters, () {
_resolutionSink.writeType(element.extendedType);
_writeList(
element.accessors.where((e) => !e.isSynthetic).toList(),
_writePropertyAccessorElement,
);
_writeList(
element.fields.where((e) => !e.isSynthetic).toList(),
_writeFieldElement,
);
_writeList(element.methods, _writeMethodElement);
});
}
void _writeFeatureSet(FeatureSet featureSet) {
var experimentStatus = featureSet as ExperimentStatus;
var encoded = experimentStatus.toStorage();
_sink.writeUint8List(encoded);
}
void _writeFieldElement(FieldElement element) {
element as FieldElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
_sink.writeBool(element is ConstFieldElementImpl);
FieldElementFlags.write(_sink, element);
_sink._writeTopLevelInferenceError(element.typeInferenceError);
_resolutionSink._writeAnnotationList(element.metadata);
_resolutionSink.writeType(element.type);
_resolutionSink._writeOptionalNode(element.constantInitializer);
}
void _writeFunctionElement(FunctionElement element) {
element as FunctionElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
FunctionElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_writeTypeParameters(element.typeParameters, () {
_resolutionSink.writeType(element.returnType);
_writeList(element.parameters, _writeParameterElement);
});
}
void _writeImportElement(ImportElement element) {
element as ImportElementImpl;
ImportElementFlags.write(_sink, element);
_sink._writeOptionalStringReference(element.uri);
_sink._writeOptionalStringReference(element.prefix?.name);
_sink.writeList(element.combinators, _writeNamespaceCombinator);
_resolutionSink._writeAnnotationList(element.metadata);
_resolutionSink.writeElement(element.importedLibrary);
}
void _writeLanguageVersion(LibraryLanguageVersion version) {
_sink.writeUInt30(version.package.major);
_sink.writeUInt30(version.package.minor);
var override = version.override;
if (override != null) {
_sink.writeBool(true);
_sink.writeUInt30(override.major);
_sink.writeUInt30(override.minor);
} else {
_sink.writeBool(false);
}
}
void _writeList<T>(List<T> elements, void Function(T) writeElement) {
_sink.writeUInt30(elements.length);
for (var element in elements) {
writeElement(element);
}
}
void _writeMethodElement(MethodElement element) {
element as MethodElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
MethodElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_writeTypeParameters(element.typeParameters, () {
_writeList(element.parameters, _writeParameterElement);
_sink._writeTopLevelInferenceError(element.typeInferenceError);
_resolutionSink.writeType(element.returnType);
});
}
void _writeMixinElement(ClassElement element) {
element as MixinElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
MixinElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_writeTypeParameters(element.typeParameters, () {
_resolutionSink._writeTypeList(element.superclassConstraints);
_resolutionSink._writeTypeList(element.interfaces);
_writeList(
element.fields.where((e) => !e.isSynthetic).toList(),
_writeFieldElement,
);
_writeList(
element.accessors.where((e) => !e.isSynthetic).toList(),
_writePropertyAccessorElement,
);
_writeList(element.constructors, _writeConstructorElement);
_writeList(element.methods, _writeMethodElement);
_sink._writeStringList(element.superInvokedNames);
});
}
void _writeNamespaceCombinator(NamespaceCombinator combinator) {
if (combinator is HideElementCombinator) {
_sink.writeByte(Tag.HideCombinator);
_sink.writeList<String>(combinator.hiddenNames, (name) {
_sink._writeStringReference(name);
});
} else if (combinator is ShowElementCombinator) {
_sink.writeByte(Tag.ShowCombinator);
_sink.writeList<String>(combinator.shownNames, (name) {
_sink._writeStringReference(name);
});
} else {
throw UnimplementedError('${combinator.runtimeType}');
}
}
void _writeParameterElement(ParameterElement element) {
element as ParameterElementImpl;
_sink._writeStringReference(element.name);
_sink.writeBool(element.isInitializingFormal);
_sink.writeBool(element.isSuperFormal);
_sink._writeFormalParameterKind(element);
ParameterElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_writeTypeParameters(element.typeParameters, () {
_writeList(element.parameters, _writeParameterElement);
_resolutionSink.writeType(element.type);
if (element is ConstVariableElement) {
var constElement = element as ConstVariableElement;
_resolutionSink._writeOptionalNode(constElement.constantInitializer);
}
if (element is FieldFormalParameterElementImpl) {
_resolutionSink.writeElement(element.field);
}
});
}
void _writePropertyAccessorElement(PropertyAccessorElement element) {
element as PropertyAccessorElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.displayName);
PropertyAccessorElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_resolutionSink.writeType(element.returnType);
_writeList(element.parameters, _writeParameterElement);
}
void _writeReferences(List<Reference> references) {
var length = references.length;
_sink.writeUInt30(length);
for (var reference in references) {
var index = _references._indexOfReference(reference);
_sink.writeUInt30(index);
}
}
void _writeTopLevelVariableElement(TopLevelVariableElement element) {
element as TopLevelVariableElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
_sink.writeBool(element.isConst);
TopLevelVariableElementFlags.write(_sink, element);
_sink._writeTopLevelInferenceError(element.typeInferenceError);
_resolutionSink._writeAnnotationList(element.metadata);
_resolutionSink.writeType(element.type);
_resolutionSink._writeOptionalNode(element.constantInitializer);
}
void _writeTypeAliasElement(TypeAliasElement element) {
element as TypeAliasElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
_sink.writeBool(element.isFunctionTypeAliasBased);
TypeAliasElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_writeTypeParameters(element.typeParameters, () {
_resolutionSink._writeAliasedElement(element.aliasedElement);
_resolutionSink.writeType(element.aliasedType);
});
}
void _writeTypeParameterElement(TypeParameterElement typeParameter) {
typeParameter as TypeParameterElementImpl;
_sink._writeStringReference(typeParameter.name);
_sink.writeByte(_encodeVariance(typeParameter).index);
_resolutionSink._writeAnnotationList(typeParameter.metadata);
_resolutionSink.writeType(typeParameter.bound);
_resolutionSink.writeType(typeParameter.defaultType);
}
/// Add [typeParameters] to the indexing scope, so make them available
/// when writing types that might reference them, and write the elements.
void _writeTypeParameters(
List<TypeParameterElement> typeParameters,
void Function() f,
) {
_resolutionSink.localElements.withElements(typeParameters, () {
_sink.writeList(typeParameters, _writeTypeParameterElement);
f();
});
}
void _writeUnitElement(CompilationUnitElement unitElement) {
unitElement as CompilationUnitElementImpl;
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference('${unitElement.source.uri}');
_sink._writeOptionalStringReference(unitElement.uri);
_sink.writeBool(unitElement.isSynthetic);
_resolutionSink._writeAnnotationList(unitElement.metadata);
_writeList(unitElement.classes, _writeClassElement);
_writeList(unitElement.enums, _writeEnumElement);
_writeList(unitElement.extensions, _writeExtensionElement);
_writeList(unitElement.functions, _writeFunctionElement);
_writeList(unitElement.mixins, _writeMixinElement);
_writeList(unitElement.typeAliases, _writeTypeAliasElement);
_writeList(
unitElement.topLevelVariables
.where((element) => !element.isSynthetic)
.toList(),
_writeTopLevelVariableElement,
);
_writeList(
unitElement.accessors.where((e) => !e.isSynthetic).toList(),
_writePropertyAccessorElement,
);
}
static TypeParameterVarianceTag _encodeVariance(
TypeParameterElementImpl element) {
if (element.isLegacyCovariant) {
return TypeParameterVarianceTag.legacy;
}
var variance = element.variance;
if (variance == Variance.unrelated) {
return TypeParameterVarianceTag.unrelated;
} else if (variance == Variance.covariant) {
return TypeParameterVarianceTag.covariant;
} else if (variance == Variance.contravariant) {
return TypeParameterVarianceTag.contravariant;
} else if (variance == Variance.invariant) {
return TypeParameterVarianceTag.invariant;
} else {
throw UnimplementedError('$variance');
}
}
}
class BundleWriterResult {
final Uint8List resolutionBytes;
BundleWriterResult({
required this.resolutionBytes,
});
}
class ResolutionSink extends _SummaryDataWriter {
final _BundleWriterReferences _references;
final _LocalElementIndexer localElements = _LocalElementIndexer();
ResolutionSink({
required ByteSink sink,
required StringIndexer stringIndexer,
required _BundleWriterReferences references,
}) : _references = references,
super(
sink: sink,
stringIndexer: stringIndexer,
);
/// TODO(scheglov) Triage places where we write elements.
/// Some of then cannot be members, e.g. type names.
void writeElement(Element? element) {
if (element is Member) {
var declaration = element.declaration;
var isLegacy = element.isLegacy;
var typeArguments = _enclosingClassTypeArguments(
declaration,
element.substitution.map,
);
writeByte(
isLegacy
? Tag.MemberLegacyWithTypeArguments
: Tag.MemberWithTypeArguments,
);
_writeElement(declaration);
_writeTypeList(typeArguments);
} else {
writeByte(Tag.RawElement);
_writeElement(element);
}
}
void writeOptionalTypeList(List<DartType>? types) {
if (types != null) {
writeBool(true);
_writeTypeList(types);
} else {
writeBool(false);
}
}
void writeType(DartType? type) {
if (type == null) {
writeByte(Tag.NullType);
} else if (type is DynamicType) {
writeByte(Tag.DynamicType);
_writeTypeAliasElementArguments(type);
} else if (type is FunctionType) {
_writeFunctionType(type);
_writeTypeAliasElementArguments(type);
} else if (type is InterfaceType) {
var typeArguments = type.typeArguments;
var nullabilitySuffix = type.nullabilitySuffix;
if (typeArguments.isEmpty) {
if (nullabilitySuffix == NullabilitySuffix.none) {
writeByte(Tag.InterfaceType_noTypeArguments_none);
} else if (nullabilitySuffix == NullabilitySuffix.question) {
writeByte(Tag.InterfaceType_noTypeArguments_question);
} else if (nullabilitySuffix == NullabilitySuffix.star) {
writeByte(Tag.InterfaceType_noTypeArguments_star);
}
// TODO(scheglov) Write raw
writeElement(type.element);
} else {
writeByte(Tag.InterfaceType);
// TODO(scheglov) Write raw
writeElement(type.element);
writeUInt30(typeArguments.length);
for (var i = 0; i < typeArguments.length; ++i) {
writeType(typeArguments[i]);
}
_writeNullabilitySuffix(nullabilitySuffix);
}
_writeTypeAliasElementArguments(type);
} else if (type is NeverType) {
writeByte(Tag.NeverType);
_writeNullabilitySuffix(type.nullabilitySuffix);
_writeTypeAliasElementArguments(type);
} else if (type is TypeParameterType) {
writeByte(Tag.TypeParameterType);
writeElement(type.element);
_writeNullabilitySuffix(type.nullabilitySuffix);
_writeTypeAliasElementArguments(type);
} else if (type is VoidType) {
writeByte(Tag.VoidType);
_writeTypeAliasElementArguments(type);
} else {
throw UnimplementedError('${type.runtimeType}');
}
}
int _indexOfElement(Element? element) {
if (element == null) return 0;
if (element is MultiplyDefinedElement) return 0;
assert(element is! Member);
// Positional parameters cannot be referenced outside of their scope,
// so don't have a reference, so are stored as local elements.
if (element is ParameterElementImpl && element.reference == null) {
return localElements[element] << 1 | 0x1;
}
// Type parameters cannot be referenced outside of their scope,
// so don't have a reference, so are stored as local elements.
if (element is TypeParameterElement) {
return localElements[element] << 1 | 0x1;
}
if (identical(element, DynamicElementImpl.instance)) {
return _references._indexOfReference(_references.dynamicReference) << 1;
}
var reference = (element as ElementImpl).reference;
return _references._indexOfReference(reference) << 1;
}
void _writeAliasedElement(Element? element) {
if (element == null) {
writeByte(AliasedElementTag.nothing);
} else if (element is GenericFunctionTypeElement) {
writeByte(AliasedElementTag.genericFunctionElement);
_writeTypeParameters(element.typeParameters, () {
_writeFormalParameters(element.parameters, withAnnotations: true);
writeType(element.returnType);
}, withAnnotations: true);
} else {
throw UnimplementedError('${element.runtimeType}');
}
}
void _writeAnnotationList(List<ElementAnnotation> annotations) {
writeUInt30(annotations.length);
for (var annotation in annotations) {
annotation as ElementAnnotationImpl;
_writeNode(annotation.annotationAst);
}
}
void _writeElement(Element? element) {
assert(element is! Member, 'Use writeMemberOrElement()');
var elementIndex = _indexOfElement(element);
writeUInt30(elementIndex);
}
void _writeFormalParameters(
List<ParameterElement> parameters, {
required bool withAnnotations,
}) {
writeUInt30(parameters.length);
for (var parameter in parameters) {
_writeFormalParameterKind(parameter);
writeBool(parameter.hasImplicitType);
writeBool(parameter.isInitializingFormal);
_writeTypeParameters(parameter.typeParameters, () {
writeType(parameter.type);
_writeStringReference(parameter.name);
_writeFormalParameters(
parameter.parameters,
withAnnotations: withAnnotations,
);
}, withAnnotations: withAnnotations);
if (withAnnotations) {
_writeAnnotationList(parameter.metadata);
}
}
}
void _writeFunctionType(FunctionType type) {
type = _toSyntheticFunctionType(type);
writeByte(Tag.FunctionType);
_writeTypeParameters(type.typeFormals, () {
writeType(type.returnType);
_writeFormalParameters(type.parameters, withAnnotations: false);
}, withAnnotations: false);
_writeNullabilitySuffix(type.nullabilitySuffix);
}
void _writeNode(AstNode node) {
var astWriter = AstBinaryWriter(
sink: this,
stringIndexer: _stringIndexer,
);
node.accept(astWriter);
}
void _writeNodeList(List<AstNode> nodes) {
writeUInt30(nodes.length);
for (var node in nodes) {
_writeNode(node);
}
}
void _writeNullabilitySuffix(NullabilitySuffix suffix) {
writeByte(suffix.index);
}
void _writeOptionalNode(Expression? node) {
if (node != null) {
writeBool(true);
_writeNode(node);
} else {
writeBool(false);
}
}
void _writeTypeAliasElementArguments(DartType type) {
var alias = type.alias;
_writeElement(alias?.element);
if (alias != null) {
_writeTypeList(alias.typeArguments);
}
}
void _writeTypeList(List<DartType> types) {
writeUInt30(types.length);
for (var type in types) {
writeType(type);
}
}
void _writeTypeParameters(
List<TypeParameterElement> typeParameters,
void Function() f, {
required bool withAnnotations,
}) {
localElements.withElements(typeParameters, () {
writeUInt30(typeParameters.length);
for (var typeParameter in typeParameters) {
_writeStringReference(typeParameter.name);
}
for (var typeParameter in typeParameters) {
writeType(typeParameter.bound);
if (withAnnotations) {
_writeAnnotationList(typeParameter.metadata);
}
}
f();
});
}
static List<DartType> _enclosingClassTypeArguments(
Element declaration,
Map<TypeParameterElement, DartType> substitution,
) {
// TODO(scheglov) Just keep it null in class Member?
if (substitution.isEmpty) {
return const [];
}
var enclosing = declaration.enclosingElement;
if (enclosing is TypeParameterizedElement) {
if (enclosing is! ClassElement && enclosing is! ExtensionElement) {
return const <DartType>[];
}
var typeParameters = enclosing.typeParameters;
if (typeParameters.isEmpty) {
return const <DartType>[];
}
return typeParameters
.map((typeParameter) => substitution[typeParameter])
.whereNotNull()
.toList(growable: false);
}
return const <DartType>[];
}
static FunctionType _toSyntheticFunctionType(FunctionType type) {
var typeParameters = type.typeFormals;
if (typeParameters.isEmpty) return type;
var fresh = getFreshTypeParameters(typeParameters);
return fresh.applyToFunctionType(type);
}
}
class StringIndexer {
final Map<String, int> _index = {};
int operator [](String string) {
var result = _index[string];
if (result == null) {
result = _index.length;
_index[string] = result;
}
return result;
}
int write(BufferedSink sink) {
var bytesOffset = sink.offset;
var length = _index.length;
var lengths = Uint32List(length);
var lengthsIndex = 0;
for (var key in _index.keys) {
var stringStart = sink.offset;
_writeWtf8(sink, key);
lengths[lengthsIndex++] = sink.offset - stringStart;
}
var resultOffset = sink.offset;
var lengthOfBytes = sink.offset - bytesOffset;
sink.writeUInt30(lengthOfBytes);
sink.writeUint30List(lengths);
return resultOffset;
}
/// Write [source] string into [sink].
static void _writeWtf8(BufferedSink sink, String source) {
var end = source.length;
if (end == 0) {
return;
}
int i = 0;
do {
var codeUnit = source.codeUnitAt(i++);
if (codeUnit < 128) {
// ASCII.
sink.addByte(codeUnit);
} else if (codeUnit < 0x800) {
// Two-byte sequence (11-bit unicode value).
sink.addByte(0xC0 | (codeUnit >> 6));
sink.addByte(0x80 | (codeUnit & 0x3f));
} else if ((codeUnit & 0xFC00) == 0xD800 &&
i < end &&
(source.codeUnitAt(i) & 0xFC00) == 0xDC00) {
// Surrogate pair -> four-byte sequence (non-BMP unicode value).
int codeUnit2 = source.codeUnitAt(i++);
int unicode =
0x10000 + ((codeUnit & 0x3FF) << 10) + (codeUnit2 & 0x3FF);
sink.addByte(0xF0 | (unicode >> 18));
sink.addByte(0x80 | ((unicode >> 12) & 0x3F));
sink.addByte(0x80 | ((unicode >> 6) & 0x3F));
sink.addByte(0x80 | (unicode & 0x3F));
} else {
// Three-byte sequence (16-bit unicode value), including lone
// surrogates.
sink.addByte(0xE0 | (codeUnit >> 12));
sink.addByte(0x80 | ((codeUnit >> 6) & 0x3f));
sink.addByte(0x80 | (codeUnit & 0x3f));
}
} while (i < end);
}
}
class UnitToWriteAst {
final CompilationUnit node;
UnitToWriteAst({
required this.node,
});
}
class _BundleWriterReferences {
/// The `dynamic` class is declared in `dart:core`, but is not a class.
/// Also, it is static, so we cannot set `reference` for it.
/// So, we have to push it in a separate way.
final Reference dynamicReference;
/// References used in all libraries being linked.
/// Element references in nodes are indexes in this list.
/// TODO(scheglov) Do we really use this list?
final List<Reference?> references = [null];
final List<int> _referenceParents = [0];
final List<String> _referenceNames = [''];
_BundleWriterReferences(this.dynamicReference);
/// We need indexes for references during linking, but once we are done,
/// we must clear indexes to make references ready for linking a next bundle.
void _clearIndexes() {
for (var reference in references) {
if (reference != null) {
reference.index = null;
}
}
}
int _indexOfReference(Reference? reference) {
if (reference == null) return 0;
if (reference.parent == null) return 0;
var index = reference.index;
if (index != null) return index;
var parentIndex = _indexOfReference(reference.parent);
_referenceParents.add(parentIndex);
_referenceNames.add(reference.name);
index = references.length;
reference.index = index;
references.add(reference);
return index;
}
}
class _Library {
final String uriStr;
final int offset;
final List<int> classMembersOffsets;
_Library({
required this.uriStr,
required this.offset,
required this.classMembersOffsets,
});
}
class _LocalElementIndexer {
final Map<Element, int> _index = Map.identity();
int _stackHeight = 0;
int operator [](Element element) {
return _index[element] ??
(throw ArgumentError('Unexpectedly not indexed: $element'));
}
void withElements(List<Element> elements, void Function() f) {
for (var element in elements) {
_index[element] = _stackHeight++;
}
f();
_stackHeight -= elements.length;
for (var element in elements) {
_index.remove(element);
}
}
}
class _SummaryDataWriter extends BufferedSink {
final StringIndexer _stringIndexer;
_SummaryDataWriter({
required ByteSink sink,
required StringIndexer stringIndexer,
}) : _stringIndexer = stringIndexer,
super(sink);
void _writeFormalParameterKind(ParameterElement p) {
if (p.isRequiredPositional) {
writeByte(Tag.ParameterKindRequiredPositional);
} else if (p.isOptionalPositional) {
writeByte(Tag.ParameterKindOptionalPositional);
} else if (p.isRequiredNamed) {
writeByte(Tag.ParameterKindRequiredNamed);
} else if (p.isOptionalNamed) {
writeByte(Tag.ParameterKindOptionalNamed);
} else {
throw StateError('Unexpected parameter kind: $p');
}
}
void _writeOptionalStringReference(String? value) {
if (value != null) {
writeBool(true);
_writeStringReference(value);
} else {
writeBool(false);
}
}
void _writeStringList(List<String> values) {
writeUInt30(values.length);
for (var value in values) {
_writeStringReference(value);
}
}
void _writeStringReference(String string) {
var index = _stringIndexer[string];
writeUInt30(index);
}
void _writeTopLevelInferenceError(TopLevelInferenceError? error) {
if (error != null) {
writeByte(error.kind.index);
_writeStringList(error.arguments);
} else {
writeByte(TopLevelInferenceErrorKind.none.index);
}
}
}