blob: 3b3167382a6b038ff3b7e6ab4d0e8f63b08703bf [file] [log] [blame]
// Copyright (c) 2021, 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/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/summary2/bundle_reader.dart';
import 'package:analyzer/src/summary2/data_reader.dart';
import 'package:analyzer/src/summary2/data_writer.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/not_serializable_nodes.dart';
import 'package:analyzer/src/util/collection.dart';
import 'package:analyzer/src/util/comment.dart';
Uint8List writeUnitInformative(CompilationUnit unit) {
var byteSink = ByteSink();
var sink = BufferedSink(byteSink);
_InformativeDataWriter(sink).write(unit);
return sink.flushAndTake();
}
/// We want to have actual offsets for tokens of various constants in the
/// element model, such as metadata and constant initializers. But we read
/// these additional pieces of resolution data later, on demand. So, these
/// offsets are different from `nameOffset` for example, which are applied
/// directly after creating corresponding elements during a library loading.
class ApplyConstantOffsets {
Uint32List? _offsets;
void Function(_OffsetsApplier)? _function;
ApplyConstantOffsets(this._offsets, this._function);
void perform() {
var offsets = _offsets;
var function = _function;
if (offsets != null && function != null) {
var applier = _OffsetsApplier(
_SafeListIterator(offsets),
);
function.call(applier);
// Clear the references to possible closure data.
// TODO(scheglov): We want to null the whole `linkedData` instead.
_offsets = null;
_function = null;
}
}
}
class InformativeDataApplier {
final LinkedElementFactory _elementFactory;
final Map<Uri, Uint8List> _unitsInformativeBytes2;
final InfoDeclarationStore _infoDeclarationStore;
InformativeDataApplier(
this._elementFactory,
this._unitsInformativeBytes2,
this._infoDeclarationStore,
);
void applyTo(LibraryElementImpl libraryElement) {
if (_elementFactory.isApplyingInformativeData) {
throw StateError('Unexpected recursion.');
}
_elementFactory.isApplyingInformativeData = true;
libraryElement.linkedData?.lock();
var unitElements = libraryElement.units;
for (var i = 0; i < unitElements.length; i++) {
var unitElement = unitElements[i];
var unitInfoBytes = _getInfoUnitBytes(unitElement);
if (unitInfoBytes != null) {
applyToUnit(unitElement, unitInfoBytes);
} else {
unitElement.lineInfo = LineInfo([0]);
}
}
libraryElement.linkedData?.unlock();
_elementFactory.isApplyingInformativeData = false;
}
void applyToUnit(
CompilationUnitElementImpl unitElement, Uint8List unitInfoBytes) {
var unitReader = SummaryDataReader(unitInfoBytes);
var unitInfo = _InfoUnit(_infoDeclarationStore, unitReader);
var enclosing = unitElement.enclosingElement;
if (enclosing is LibraryElementImpl) {
if (identical(enclosing.definingCompilationUnit, unitElement)) {
_applyToLibrary(enclosing, unitInfo);
}
} else if (enclosing is LibraryAugmentationElementImpl) {
_applyToAugmentation(enclosing, unitInfo);
}
unitElement.setCodeRange(unitInfo.codeOffset, unitInfo.codeLength);
unitElement.lineInfo = LineInfo(unitInfo.lineStarts);
_applyToAccessors(unitElement.accessors, unitInfo.accessors);
forCorrespondingPairs(
unitElement.classes
.where((element) => !element.isMixinApplication)
.toList(),
unitInfo.classDeclarations,
_applyToClassDeclaration,
);
forCorrespondingPairs(
unitElement.classes
.where((element) => element.isMixinApplication)
.toList(),
unitInfo.classTypeAliases,
_applyToClassTypeAlias,
);
forCorrespondingPairs(
unitElement.enums, unitInfo.enums, _applyToEnumDeclaration);
forCorrespondingPairs(unitElement.extensions, unitInfo.extensions,
_applyToExtensionDeclaration);
forCorrespondingPairs(unitElement.extensionTypes, unitInfo.extensionTypes,
_applyToExtensionTypeDeclaration);
forCorrespondingPairs(
unitElement.functions, unitInfo.functions, _applyToFunctionDeclaration);
forCorrespondingPairs(unitElement.mixins, unitInfo.mixinDeclarations,
_applyToMixinDeclaration);
forCorrespondingPairs(unitElement.topLevelVariables,
unitInfo.topLevelVariable, _applyToTopLevelVariable);
forCorrespondingPairs(
unitElement.typeAliases
.cast<TypeAliasElementImpl>()
.where((e) => e.isFunctionTypeAliasBased)
.toList(),
unitInfo.functionTypeAliases,
_applyToFunctionTypeAlias,
);
forCorrespondingPairs(
unitElement.typeAliases
.cast<TypeAliasElementImpl>()
.where((e) => !e.isFunctionTypeAliasBased)
.toList(),
unitInfo.genericTypeAliases,
_applyToGenericTypeAlias,
);
}
void _applyToAccessors(
List<PropertyAccessorElement> elementList,
List<_InfoMethodDeclaration> infoList,
) {
forCorrespondingPairs<PropertyAccessorElement, _InfoMethodDeclaration>(
elementList.notSynthetic,
infoList,
(element, info) {
element as PropertyAccessorElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToFormalParameters(
element.parameters_unresolved,
info.parameters,
);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
applier.applyToFormalParameters(element.parameters);
},
);
var linkedData = element.linkedData;
if (linkedData is PropertyAccessorElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
},
);
}
void _applyToAugmentation(
LibraryAugmentationElementImpl element,
_InfoUnit info,
) {
if (info.docComment.isNotEmpty) {
element.documentationComment = info.docComment;
}
_applyToImports(element, info);
_applyToExports(element, info);
var applyOffsets = ApplyConstantOffsets(
info.libraryConstantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToImports(element.libraryImports);
applier.applyToExports(element.libraryExports);
applier.applyToAugmentationImports(element.augmentationImports);
},
);
var linkedData = element.linkedData;
if (linkedData is LibraryAugmentationElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
void _applyToClassDeclaration(
ClassElement element,
_InfoClassDeclaration info,
) {
element as ClassElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
},
);
void applyToMembers() {
_applyToConstructors(element.constructors, info.constructors);
_applyToFields(element.fields, info.fields);
_applyToAccessors(element.accessors, info.accessors);
_applyToMethods(element.methods, info.methods);
}
var linkedData = element.linkedData;
if (linkedData is ClassElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
linkedData.applyInformativeDataToMembers = applyToMembers;
} else {
applyOffsets.perform();
applyToMembers();
}
}
void _applyToClassTypeAlias(
ClassElement element,
_InfoClassTypeAlias info,
) {
element as ClassElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
},
);
var linkedData = element.linkedData;
if (linkedData is ClassElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
void _applyToCombinators(
List<NamespaceCombinator> elementList,
List<_InfoCombinator> infoList,
) {
forCorrespondingPairs<NamespaceCombinator, _InfoCombinator>(
elementList,
infoList,
(element, info) {
if (element is ShowElementCombinatorImpl) {
element.offset = info.offset;
element.end = info.end;
}
if (element is HideElementCombinatorImpl) {
element.offset = info.offset;
element.end = info.end;
}
},
);
}
void _applyToConstructors(
List<ConstructorElement> elementList,
List<_InfoConstructorDeclaration> infoList,
) {
forCorrespondingPairs<ConstructorElement, _InfoConstructorDeclaration>(
elementList,
infoList,
(element, info) {
element as ConstructorElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.periodOffset = info.periodOffset;
element.nameOffset = info.nameOffset;
element.nameEnd = info.nameEnd;
element.documentationComment = info.documentationComment;
_applyToFormalParameters(
element.parameters_unresolved,
info.parameters,
);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToFormalParameters(element.parameters);
applier.applyToConstructorInitializers(element);
},
);
var linkedData = element.linkedData;
if (linkedData is ConstructorElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
},
);
}
void _applyToEnumDeclaration(
EnumElement element,
_InfoClassDeclaration info,
) {
element as EnumElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
_applyToConstructors(element.constructors, info.constructors);
_applyToFields(element.fields, info.fields);
_applyToAccessors(element.accessors, info.accessors);
_applyToMethods(element.methods, info.methods);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
},
);
var linkedData = element.linkedData;
if (linkedData is EnumElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
void _applyToExports(
LibraryOrAugmentationElementImpl element,
_InfoUnit info,
) {
forCorrespondingPairs<LibraryExportElement, _InfoExport>(
element.exports_unresolved,
info.exports,
(element, info) {
element as LibraryExportElementImpl;
element.nameOffset = info.nameOffset;
_applyToCombinators(element.combinators, info.combinators);
},
);
}
void _applyToExtensionDeclaration(
ExtensionElement element,
_InfoClassDeclaration info,
) {
element as ExtensionElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
_applyToFields(element.fields, info.fields);
_applyToAccessors(element.accessors, info.accessors);
_applyToMethods(element.methods, info.methods);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
},
);
var linkedData = element.linkedData;
if (linkedData is ExtensionElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
void _applyToExtensionTypeDeclaration(
ExtensionTypeElement element,
_InfoExtensionTypeDeclaration info,
) {
element as ExtensionTypeElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
if (element.isAugmentationChainStart) {
var representationField = element.fields.first;
var infoRep = info.representation;
representationField.nameOffset = infoRep.fieldNameOffset;
representationField.setCodeRange(
infoRep.fieldCodeOffset,
infoRep.fieldCodeLength,
);
var fieldApplyOffsets = ApplyConstantOffsets(
infoRep.fieldConstantOffsets,
(applier) {
applier.applyToMetadata(representationField);
},
);
var fieldLinkedData = representationField.linkedData;
if (fieldLinkedData is FieldElementLinkedData) {
fieldLinkedData.applyConstantOffsets = fieldApplyOffsets;
} else {
fieldApplyOffsets.perform();
}
var primaryConstructor = element.constructors.first;
primaryConstructor.setCodeRange(
infoRep.constructorCodeOffset,
infoRep.constructorCodeLength,
);
primaryConstructor.periodOffset = infoRep.constructorPeriodOffset;
primaryConstructor.nameOffset = infoRep.constructorNameOffset;
primaryConstructor.nameEnd = infoRep.constructorNameEnd;
var primaryConstructorParameter = primaryConstructor
.parameters_unresolved.first as ParameterElementImpl;
primaryConstructorParameter.nameOffset = infoRep.fieldNameOffset;
primaryConstructorParameter.setCodeRange(
infoRep.fieldCodeOffset,
infoRep.fieldCodeLength,
);
var restFields = element.fields.skip(1).toList();
_applyToFields(restFields, info.fields);
var restConstructors = element.constructors.skip(1).toList();
_applyToConstructors(restConstructors, info.constructors);
} else {
_applyToFields(element.fields, info.fields);
_applyToConstructors(element.constructors, info.constructors);
}
_applyToAccessors(element.accessors, info.accessors);
_applyToMethods(element.methods, info.methods);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
},
);
var linkedData = element.linkedData;
if (linkedData is ExtensionTypeElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
void _applyToFields(
List<FieldElement> elementList,
List<_InfoFieldDeclaration> infoList,
) {
forCorrespondingPairs<FieldElement, _InfoFieldDeclaration>(
elementList.notSynthetic,
infoList,
(element, info) {
element as FieldElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToConstantInitializer(element);
},
);
var linkedData = element.linkedData;
if (linkedData is FieldElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
},
);
}
void _applyToFormalParameters(
List<ParameterElement> parameters,
List<_InfoFormalParameter> infoList,
) {
forCorrespondingPairs<ParameterElement, _InfoFormalParameter>(
parameters,
infoList,
(element, info) {
element as ParameterElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
_applyToTypeParameters(element.typeParameters, info.typeParameters);
_applyToFormalParameters(element.parameters, info.parameters);
},
);
}
void _applyToFunctionDeclaration(
FunctionElement element,
_InfoFunctionDeclaration info,
) {
element as FunctionElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
_applyToFormalParameters(
element.parameters_unresolved,
info.parameters,
);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
applier.applyToFormalParameters(element.parameters);
},
);
var linkedData = element.linkedData;
if (linkedData is FunctionElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
void _applyToFunctionTypeAlias(
TypeAliasElement element,
_InfoFunctionTypeAlias info,
) {
element as TypeAliasElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
_setupApplyConstantOffsetsForTypeAlias(
element,
info.constantOffsets,
aliasedFormalParameters: info.parameters,
);
}
void _applyToGenericTypeAlias(
TypeAliasElement element,
_InfoGenericTypeAlias info,
) {
element as TypeAliasElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
_setupApplyConstantOffsetsForTypeAlias(
element,
info.constantOffsets,
aliasedFormalParameters: info.aliasedFormalParameters,
aliasedTypeParameters: info.aliasedTypeParameters,
);
}
void _applyToImports(
LibraryOrAugmentationElementImpl element,
_InfoUnit info,
) {
forCorrespondingPairs<LibraryImportElement, _InfoImport>(
element.imports_unresolved,
info.imports,
(element, info) {
element as LibraryImportElementImpl;
element.nameOffset = info.nameOffset;
var prefixElement = element.prefix?.element;
if (prefixElement is PrefixElementImpl) {
prefixElement.nameOffset = info.prefixOffset;
}
_applyToCombinators(element.combinators, info.combinators);
},
);
}
void _applyToLibrary(LibraryElementImpl element, _InfoUnit info) {
element.nameOffset = info.libraryName.offset;
element.nameLength = info.libraryName.length;
if (info.docComment.isNotEmpty) {
element.documentationComment = info.docComment;
}
_applyToImports(element, info);
_applyToExports(element, info);
forCorrespondingPairs<PartElement, _InfoPart>(
element.parts,
info.parts,
(element, info) {
element as PartElementImpl;
},
);
var applyOffsets = ApplyConstantOffsets(
info.libraryConstantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToImports(element.libraryImports);
applier.applyToExports(element.libraryExports);
applier.applyToAugmentationImports(element.augmentationImports);
applier.applyToPartDirectives(element.parts);
},
);
var linkedData = element.linkedData;
if (linkedData is LibraryElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
void _applyToMethods(
List<MethodElement> elementList,
List<_InfoMethodDeclaration> infoList,
) {
forCorrespondingPairs<MethodElement, _InfoMethodDeclaration>(
elementList,
infoList,
(element, info) {
element as MethodElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
_applyToFormalParameters(
element.parameters_unresolved,
info.parameters,
);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
applier.applyToFormalParameters(element.parameters);
},
);
var linkedData = element.linkedData;
if (linkedData is MethodElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
},
);
}
void _applyToMixinDeclaration(
MixinElement element,
_InfoClassDeclaration info,
) {
element as MixinElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
_applyToConstructors(element.constructors, info.constructors);
_applyToFields(element.fields, info.fields);
_applyToAccessors(element.accessors, info.accessors);
_applyToMethods(element.methods, info.methods);
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
},
);
var linkedData = element.linkedData;
if (linkedData is MixinElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
void _applyToTopLevelVariable(
TopLevelVariableElement element,
_InfoTopLevelVariable info,
) {
element as TopLevelVariableElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
var applyOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToConstantInitializer(element);
},
);
var linkedData = element.linkedData;
if (linkedData is TopLevelVariableElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
void _applyToTypeParameters(
List<TypeParameterElement> elementList,
List<_InfoTypeParameter> infoList,
) {
forCorrespondingPairs<TypeParameterElement, _InfoTypeParameter>(
elementList,
infoList,
(element, info) {
element as TypeParameterElementImpl;
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
},
);
}
Uint8List? _getInfoUnitBytes(CompilationUnitElement element) {
var uri = element.source.uri;
if (_unitsInformativeBytes2[uri] case var bytes?) {
return bytes;
}
switch (element.enclosingElement) {
case LibraryAugmentationElementImpl(:var macroGenerated?):
return macroGenerated.informativeBytes;
}
return null;
}
void _setupApplyConstantOffsetsForTypeAlias(
TypeAliasElementImpl element,
Uint32List constantOffsets, {
List<_InfoFormalParameter>? aliasedFormalParameters,
List<_InfoTypeParameter>? aliasedTypeParameters,
}) {
var applyOffsets = ApplyConstantOffsets(
constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
var aliasedElement = element.aliasedElement;
if (aliasedElement is FunctionTypedElementImpl) {
applier.applyToTypeParameters(aliasedElement.typeParameters);
applier.applyToFormalParameters(aliasedElement.parameters);
if (aliasedTypeParameters != null) {
_applyToTypeParameters(
aliasedElement.typeParameters,
aliasedTypeParameters,
);
}
if (aliasedFormalParameters != null) {
_applyToFormalParameters(
aliasedElement.parameters,
aliasedFormalParameters,
);
}
}
},
);
var linkedData = element.linkedData;
if (linkedData is TypeAliasElementLinkedData) {
linkedData.applyConstantOffsets = applyOffsets;
} else {
applyOffsets.perform();
}
}
}
class _InfoClassDeclaration {
final int codeOffset;
final int codeLength;
final int nameOffset;
final String? documentationComment;
final List<_InfoTypeParameter> typeParameters;
final List<_InfoConstructorDeclaration> constructors;
final List<_InfoFieldDeclaration> fields;
final List<_InfoMethodDeclaration> accessors;
final List<_InfoMethodDeclaration> methods;
final Uint32List constantOffsets;
factory _InfoClassDeclaration(
InfoDeclarationStore cache, SummaryDataReader reader,
{int nameOffsetDelta = 0}) {
// TODO(scheglov): Shared below.
// TODO(jensj): Possibly we could just save the bytes and the
// offset and then only read it when/if needed.
// See https://dart-review.googlesource.com/c/sdk/+/318940.
var initialOffset = reader.offset;
String cacheKey = cache.createKey(reader, initialOffset);
var cached =
cache.get<_InfoClassDeclaration>(reader, cacheKey, initialOffset);
if (cached != null) return cached;
var result = _InfoClassDeclaration._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30() - nameOffsetDelta,
documentationComment: reader.readStringUtf8().nullIfEmpty,
typeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
),
constructors: reader.readTypedList(
() => _InfoConstructorDeclaration(reader),
),
fields: reader.readTypedList(
() => _InfoFieldDeclaration(reader),
),
accessors: reader.readTypedList(
() => _InfoMethodDeclaration(reader),
),
methods: reader.readTypedList(
() => _InfoMethodDeclaration(reader),
),
constantOffsets: reader.readUInt30List(),
);
cache.put(reader, cacheKey, initialOffset, result);
return result;
}
_InfoClassDeclaration._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.documentationComment,
required this.typeParameters,
required this.constructors,
required this.fields,
required this.accessors,
required this.methods,
required this.constantOffsets,
});
}
class _InfoClassTypeAlias {
final int codeOffset;
final int codeLength;
final int nameOffset;
final String? documentationComment;
final List<_InfoTypeParameter> typeParameters;
final Uint32List constantOffsets;
factory _InfoClassTypeAlias(SummaryDataReader reader) {
return _InfoClassTypeAlias._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
typeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
),
constantOffsets: reader.readUInt30List(),
);
}
_InfoClassTypeAlias._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.documentationComment,
required this.typeParameters,
required this.constantOffsets,
});
}
class _InfoCombinator {
final int offset;
final int end;
factory _InfoCombinator(SummaryDataReader reader) {
return _InfoCombinator._(
offset: reader.readUInt30(),
end: reader.readUInt30(),
);
}
_InfoCombinator._({
required this.offset,
required this.end,
});
}
class _InfoConstructorDeclaration {
final int codeOffset;
final int codeLength;
final int? periodOffset;
final int nameOffset;
final int nameEnd;
final String? documentationComment;
final List<_InfoFormalParameter> parameters;
final Uint32List constantOffsets;
factory _InfoConstructorDeclaration(SummaryDataReader reader) {
return _InfoConstructorDeclaration._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
periodOffset: reader.readOptionalUInt30(),
nameOffset: reader.readUInt30(),
nameEnd: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
parameters: reader.readTypedList(
() => _InfoFormalParameter(reader),
),
constantOffsets: reader.readUInt30List(),
);
}
_InfoConstructorDeclaration._({
required this.codeOffset,
required this.codeLength,
required this.periodOffset,
required this.nameOffset,
required this.nameEnd,
required this.documentationComment,
required this.parameters,
required this.constantOffsets,
});
}
class _InfoExport {
final int nameOffset;
final List<_InfoCombinator> combinators;
factory _InfoExport(SummaryDataReader reader) {
return _InfoExport._(
nameOffset: reader.readUInt30(),
combinators: reader.readTypedList(
() => _InfoCombinator(reader),
),
);
}
_InfoExport._({
required this.nameOffset,
required this.combinators,
});
}
class _InfoExtensionTypeDeclaration {
final int codeOffset;
final int codeLength;
final int nameOffset;
final String? documentationComment;
final List<_InfoTypeParameter> typeParameters;
final _InfoExtensionTypeRepresentation representation;
final List<_InfoConstructorDeclaration> constructors;
final List<_InfoFieldDeclaration> fields;
final List<_InfoMethodDeclaration> accessors;
final List<_InfoMethodDeclaration> methods;
final Uint32List constantOffsets;
factory _InfoExtensionTypeDeclaration(SummaryDataReader reader) {
return _InfoExtensionTypeDeclaration._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
typeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
),
representation: _InfoExtensionTypeRepresentation(reader),
constructors: reader.readTypedList(
() => _InfoConstructorDeclaration(reader),
),
fields: reader.readTypedList(
() => _InfoFieldDeclaration(reader),
),
accessors: reader.readTypedList(
() => _InfoMethodDeclaration(reader),
),
methods: reader.readTypedList(
() => _InfoMethodDeclaration(reader),
),
constantOffsets: reader.readUInt30List(),
);
}
_InfoExtensionTypeDeclaration._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.documentationComment,
required this.typeParameters,
required this.representation,
required this.constructors,
required this.fields,
required this.accessors,
required this.methods,
required this.constantOffsets,
});
}
class _InfoExtensionTypeRepresentation {
final int constructorCodeOffset;
final int constructorCodeLength;
final int? constructorPeriodOffset;
final int constructorNameOffset;
final int? constructorNameEnd;
final int fieldCodeOffset;
final int fieldCodeLength;
final int fieldNameOffset;
final Uint32List fieldConstantOffsets;
factory _InfoExtensionTypeRepresentation(SummaryDataReader reader) {
return _InfoExtensionTypeRepresentation._(
constructorCodeOffset: reader.readUInt30(),
constructorCodeLength: reader.readUInt30(),
constructorPeriodOffset: reader.readOptionalUInt30(),
constructorNameOffset: reader.readUInt30(),
constructorNameEnd: reader.readOptionalUInt30(),
fieldCodeOffset: reader.readUInt30(),
fieldCodeLength: reader.readUInt30(),
fieldNameOffset: reader.readUInt30(),
fieldConstantOffsets: reader.readUInt30List(),
);
}
_InfoExtensionTypeRepresentation._({
required this.constructorCodeOffset,
required this.constructorCodeLength,
required this.constructorPeriodOffset,
required this.constructorNameOffset,
required this.constructorNameEnd,
required this.fieldCodeOffset,
required this.fieldCodeLength,
required this.fieldNameOffset,
required this.fieldConstantOffsets,
});
}
class _InfoFieldDeclaration {
final int codeOffset;
final int codeLength;
final int nameOffset;
final String? documentationComment;
final Uint32List constantOffsets;
factory _InfoFieldDeclaration(SummaryDataReader reader) {
return _InfoFieldDeclaration._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
constantOffsets: reader.readUInt30List(),
);
}
_InfoFieldDeclaration._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.documentationComment,
required this.constantOffsets,
});
}
class _InfoFormalParameter {
final int codeOffset;
final int codeLength;
final int nameOffset;
final List<_InfoTypeParameter> typeParameters;
final List<_InfoFormalParameter> parameters;
factory _InfoFormalParameter(SummaryDataReader reader) {
return _InfoFormalParameter._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30() - 1,
typeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
),
parameters: reader.readTypedList(
() => _InfoFormalParameter(reader),
),
);
}
_InfoFormalParameter._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.typeParameters,
required this.parameters,
});
}
class _InfoFunctionDeclaration {
final int codeOffset;
final int codeLength;
final int nameOffset;
final String? documentationComment;
final List<_InfoTypeParameter> typeParameters;
final List<_InfoFormalParameter> parameters;
final Uint32List constantOffsets;
factory _InfoFunctionDeclaration(SummaryDataReader reader) {
return _InfoFunctionDeclaration._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
typeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
),
parameters: reader.readTypedList(
() => _InfoFormalParameter(reader),
),
constantOffsets: reader.readUInt30List(),
);
}
_InfoFunctionDeclaration._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.documentationComment,
required this.typeParameters,
required this.parameters,
required this.constantOffsets,
});
}
class _InfoFunctionTypeAlias {
final int codeOffset;
final int codeLength;
final int nameOffset;
final String? documentationComment;
final List<_InfoTypeParameter> typeParameters;
final List<_InfoFormalParameter> parameters;
final Uint32List constantOffsets;
factory _InfoFunctionTypeAlias(SummaryDataReader reader) {
return _InfoFunctionTypeAlias._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
typeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
),
parameters: reader.readTypedList(
() => _InfoFormalParameter(reader),
),
constantOffsets: reader.readUInt30List(),
);
}
_InfoFunctionTypeAlias._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.documentationComment,
required this.typeParameters,
required this.parameters,
required this.constantOffsets,
});
}
class _InfoGenericTypeAlias {
final int codeOffset;
final int codeLength;
final int nameOffset;
final String? documentationComment;
final List<_InfoTypeParameter> typeParameters;
final List<_InfoTypeParameter> aliasedTypeParameters;
final List<_InfoFormalParameter> aliasedFormalParameters;
final Uint32List constantOffsets;
factory _InfoGenericTypeAlias(SummaryDataReader reader) {
return _InfoGenericTypeAlias._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
typeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
),
aliasedTypeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
),
aliasedFormalParameters: reader.readTypedList(
() => _InfoFormalParameter(reader),
),
constantOffsets: reader.readUInt30List(),
);
}
_InfoGenericTypeAlias._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.documentationComment,
required this.typeParameters,
required this.aliasedTypeParameters,
required this.aliasedFormalParameters,
required this.constantOffsets,
});
}
class _InfoImport {
final int nameOffset;
final int prefixOffset;
final List<_InfoCombinator> combinators;
factory _InfoImport(SummaryDataReader reader) {
return _InfoImport._(
nameOffset: reader.readUInt30(),
prefixOffset: reader.readUInt30() - 1,
combinators: reader.readTypedList(
() => _InfoCombinator(reader),
),
);
}
_InfoImport._({
required this.nameOffset,
required this.prefixOffset,
required this.combinators,
});
}
class _InfoLibraryName {
final int offset;
final int length;
factory _InfoLibraryName(SummaryDataReader reader) {
return _InfoLibraryName._(
offset: reader.readUInt30() - 1,
length: reader.readUInt30(),
);
}
_InfoLibraryName._({
required this.offset,
required this.length,
});
}
class _InfoMethodDeclaration {
final int codeOffset;
final int codeLength;
final int nameOffset;
final String? documentationComment;
final List<_InfoTypeParameter> typeParameters;
final List<_InfoFormalParameter> parameters;
final Uint32List constantOffsets;
factory _InfoMethodDeclaration(SummaryDataReader reader) {
return _InfoMethodDeclaration._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
typeParameters: reader.readTypedList(
() => _InfoTypeParameter(reader),
),
parameters: reader.readTypedList(
() => _InfoFormalParameter(reader),
),
constantOffsets: reader.readUInt30List(),
);
}
_InfoMethodDeclaration._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.documentationComment,
required this.typeParameters,
required this.parameters,
required this.constantOffsets,
});
}
class _InfoPart {
final int nameOffset;
factory _InfoPart(SummaryDataReader reader) {
return _InfoPart._(
nameOffset: reader.readUInt30(),
);
}
_InfoPart._({
required this.nameOffset,
});
}
class _InformativeDataWriter {
final BufferedSink sink;
_InformativeDataWriter(this.sink);
void write(CompilationUnit unit) {
sink.writeUInt30(unit.offset);
sink.writeUInt30(unit.length);
sink.writeUint30List(unit.lineInfo.lineStarts);
_writeLibraryName(unit);
var firstDirective = unit.directives.firstOrNull;
_writeDocumentationCommentNode(firstDirective?.documentationComment);
sink.writeList2<ImportDirective>(unit.directives, (directive) {
sink.writeUInt30(directive.importKeyword.offset);
sink.writeUInt30(1 + (directive.prefix?.offset ?? -1));
_writeCombinators(directive.combinators);
});
sink.writeList2<ExportDirective>(unit.directives, (directive) {
sink.writeUInt30(directive.exportKeyword.offset);
_writeCombinators(directive.combinators);
});
sink.writeList2<PartDirective>(unit.directives, (directive) {
sink.writeUInt30(directive.partKeyword.offset);
});
sink.writeList2<ClassDeclaration>(unit.declarations, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeConstructors(node.members);
_writeFields(node.members);
_writeGettersSetters(node.members);
_writeMethods(node.members);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
);
});
sink.writeList2<ClassTypeAlias>(unit.declarations, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
);
});
sink.writeList2<EnumDeclaration>(unit.declarations, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeConstructors(node.members);
_writeEnumFields(node.constants, node.members);
_writeGettersSetters(node.members);
_writeMethods(node.members);
_writeOffsets(
metadata: node.metadata,
enumConstants: node.constants,
typeParameters: node.typeParameters,
);
});
sink.writeList2<ExtensionDeclaration>(unit.declarations, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(1 + (node.name?.offset ?? -1));
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeConstructors(node.members);
_writeFields(node.members);
_writeGettersSetters(node.members);
_writeMethods(node.members);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
);
});
sink.writeList2<ExtensionTypeDeclaration>(unit.declarations, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeRepresentation(node, node.representation);
_writeConstructors(node.members);
_writeFields(node.members);
_writeGettersSetters(node.members);
_writeMethods(node.members);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
);
});
sink.writeList2<FunctionDeclaration>(
unit.declarations
.whereType<FunctionDeclaration>()
.where((e) => e.isGetter || e.isSetter)
.toList(),
(node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.functionExpression.typeParameters);
_writeFormalParameters(node.functionExpression.parameters);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.functionExpression.typeParameters,
formalParameters: node.functionExpression.parameters,
);
},
);
sink.writeList2<FunctionDeclaration>(
unit.declarations
.whereType<FunctionDeclaration>()
.where((e) => !(e.isGetter || e.isSetter))
.toList(), (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.functionExpression.typeParameters);
_writeFormalParameters(node.functionExpression.parameters);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.functionExpression.typeParameters,
formalParameters: node.functionExpression.parameters,
);
});
sink.writeList2<FunctionTypeAlias>(unit.declarations, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeFormalParameters(node.parameters);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
formalParameters: node.parameters,
);
});
sink.writeList2<GenericTypeAlias>(unit.declarations, (node) {
var aliasedType = node.type;
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
if (aliasedType is GenericFunctionType) {
_writeTypeParameters(aliasedType.typeParameters);
_writeFormalParameters(aliasedType.parameters);
} else {
_writeTypeParameters(null);
_writeFormalParameters(null);
}
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
aliasedType: node.type,
);
});
sink.writeList2<MixinDeclaration>(unit.declarations, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeConstructors(node.members);
_writeFields(node.members);
_writeGettersSetters(node.members);
_writeMethods(node.members);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
);
});
sink.writeList<VariableDeclaration>(
unit.declarations
.whereType<TopLevelVariableDeclaration>()
.expand((declaration) => declaration.variables.variables)
.toList(),
_writeTopLevelVariable,
);
}
int _codeOffsetForVariable(VariableDeclaration node) {
var codeOffset = node.offset;
var variableList = node.parent as VariableDeclarationList;
if (variableList.variables[0] == node) {
codeOffset = variableList.parent!.offset;
}
return codeOffset;
}
void _writeCombinators(List<Combinator> combinators) {
sink.writeList<Combinator>(combinators, (combinator) {
sink.writeUInt30(combinator.offset);
sink.writeUInt30(combinator.end);
});
}
void _writeConstructors(List<ClassMember> members) {
sink.writeList2<ConstructorDeclaration>(members, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeOptionalUInt30(node.period?.offset);
var nameNode = node.name ?? node.returnType;
sink.writeUInt30(nameNode.offset);
sink.writeUInt30(nameNode.end);
_writeDocumentationComment(node);
_writeFormalParameters(node.parameters);
_writeOffsets(
metadata: node.metadata,
formalParameters: node.parameters,
constructorInitializers: node.initializers,
);
});
}
void _writeDocumentationComment(AnnotatedNode node) {
_writeDocumentationCommentNode(node.documentationComment);
}
void _writeDocumentationCommentNode(Comment? commentNode) {
var commentText = getCommentNodeRawText(commentNode);
sink.writeStringUtf8(commentText ?? '');
}
void _writeEnumFields(
List<EnumConstantDeclaration> constants,
List<ClassMember> members,
) {
var fields = members
.whereType<FieldDeclaration>()
.expand((declaration) => declaration.fields.variables)
.toList();
sink.writeUInt30(constants.length + fields.length);
// Write constants in the same format as fields.
for (var node in constants) {
var codeOffset = node.offset;
sink.writeUInt30(codeOffset);
sink.writeUInt30(node.end - codeOffset);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeOffsets(
metadata: node.metadata,
enumConstantArguments: node.arguments,
);
}
for (var field in fields) {
_writeField(field);
}
}
void _writeField(VariableDeclaration node) {
var codeOffset = _codeOffsetForVariable(node);
sink.writeUInt30(codeOffset);
sink.writeUInt30(node.end - codeOffset);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
// TODO(scheglov): Replace with some kind of double-iterating list.
var declaration = node.parent!.parent as FieldDeclaration;
_writeOffsets(
metadata: declaration.metadata,
constantInitializer: node.initializer,
);
}
void _writeFields(List<ClassMember> members) {
sink.writeList<VariableDeclaration>(
members
.whereType<FieldDeclaration>()
.expand((declaration) => declaration.fields.variables)
.toList(),
_writeField,
);
}
void _writeFormalParameters(FormalParameterList? parameterList) {
var parameters = parameterList?.parameters ?? <FormalParameter>[];
sink.writeList<FormalParameter>(parameters, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(1 + (node.name?.offset ?? -1));
var notDefault = node.notDefault;
if (notDefault is FieldFormalParameter) {
_writeTypeParameters(notDefault.typeParameters);
_writeFormalParameters(notDefault.parameters);
} else if (notDefault is FunctionTypedFormalParameter) {
_writeTypeParameters(notDefault.typeParameters);
_writeFormalParameters(notDefault.parameters);
} else if (notDefault is SuperFormalParameter) {
_writeTypeParameters(notDefault.typeParameters);
_writeFormalParameters(notDefault.parameters);
} else {
_writeTypeParameters(null);
_writeFormalParameters(null);
}
});
}
void _writeGettersSetters(List<ClassMember> members) {
sink.writeList<MethodDeclaration>(
members
.whereType<MethodDeclaration>()
.where((e) => e.isGetter || e.isSetter)
.toList(),
(node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeFormalParameters(node.parameters);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
formalParameters: node.parameters,
);
},
);
}
void _writeLibraryName(CompilationUnit unit) {
Directive? firstDirective;
var nameOffset = -1;
var nameLength = 0;
for (var directive in unit.directives) {
firstDirective ??= directive;
if (directive is LibraryDirective) {
var libraryName = directive.name2;
if (libraryName != null) {
nameOffset = libraryName.offset;
nameLength = libraryName.length;
}
break;
}
}
sink.writeUInt30(1 + nameOffset);
sink.writeUInt30(nameLength);
_writeOffsets(
metadata: firstDirective?.metadata,
importDirectives: unit.directives.whereType<ImportDirective>(),
exportDirectives: unit.directives.whereType<ExportDirective>(),
augmentationImportDirectives:
unit.directives.whereType<AugmentationImportDirective>(),
partDirectives: unit.directives.whereType<PartDirective>(),
);
}
void _writeMethods(List<ClassMember> members) {
sink.writeList<MethodDeclaration>(
members
.whereType<MethodDeclaration>()
.where((e) => !(e.isGetter || e.isSetter))
.toList(),
(node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeFormalParameters(node.parameters);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
formalParameters: node.parameters,
);
},
);
}
void _writeOffsets({
NodeList<Annotation>? metadata,
Iterable<ImportDirective>? importDirectives,
Iterable<ExportDirective>? exportDirectives,
Iterable<AugmentationImportDirective>? augmentationImportDirectives,
Iterable<PartDirective>? partDirectives,
TypeParameterList? typeParameters,
FormalParameterList? formalParameters,
Expression? constantInitializer,
NodeList<ConstructorInitializer>? constructorInitializers,
NodeList<EnumConstantDeclaration>? enumConstants,
TypeAnnotation? aliasedType,
EnumConstantArguments? enumConstantArguments,
}) {
var collector = _OffsetsCollector();
void addDirectives(Iterable<Directive>? directives) {
if (directives != null) {
for (var directive in directives) {
directive.metadata.accept(collector);
}
}
}
void addTypeParameters(TypeParameterList? typeParameters) {
if (typeParameters != null) {
for (var typeParameter in typeParameters.typeParameters) {
typeParameter.metadata.accept(collector);
}
}
}
void addFormalParameters(FormalParameterList? formalParameters) {
if (formalParameters != null) {
for (var parameter in formalParameters.parameters) {
parameter.metadata.accept(collector);
addFormalParameters(
parameter is FunctionTypedFormalParameter
? parameter.parameters
: null,
);
if (parameter is DefaultFormalParameter) {
parameter.defaultValue?.accept(collector);
}
}
}
}
metadata?.accept(collector);
addDirectives(importDirectives);
addDirectives(exportDirectives);
addDirectives(augmentationImportDirectives);
addDirectives(partDirectives);
addTypeParameters(typeParameters);
addFormalParameters(formalParameters);
constantInitializer?.accept(collector);
constructorInitializers?.accept(collector);
if (enumConstants != null) {
for (var enumConstant in enumConstants) {
enumConstant.metadata.accept(collector);
}
}
if (aliasedType is GenericFunctionType) {
addTypeParameters(aliasedType.typeParameters);
addFormalParameters(aliasedType.parameters);
}
enumConstantArguments?.typeArguments?.accept(collector);
enumConstantArguments?.argumentList.arguments.accept(collector);
sink.writeUint30List(collector.offsets);
}
void _writeRepresentation(
ExtensionTypeDeclaration declaration, RepresentationDeclaration node) {
// Constructor code range.
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
var constructorName = node.constructorName;
if (constructorName != null) {
sink.writeOptionalUInt30(constructorName.period.offset);
sink.writeUInt30(constructorName.name.offset);
sink.writeOptionalUInt30(constructorName.name.end);
} else {
sink.writeOptionalUInt30(null);
sink.writeUInt30(declaration.name.offset);
sink.writeOptionalUInt30(null);
}
var fieldBeginToken = node.fieldMetadata.beginToken ?? node.fieldType;
var codeOffset = fieldBeginToken.offset;
var codeEnd = node.fieldName.end;
sink.writeUInt30(codeOffset);
sink.writeUInt30(codeEnd - codeOffset);
sink.writeUInt30(node.fieldName.offset);
_writeOffsets(
metadata: node.fieldMetadata,
);
}
void _writeTopLevelVariable(VariableDeclaration node) {
var codeOffset = _codeOffsetForVariable(node);
sink.writeUInt30(codeOffset);
sink.writeUInt30(node.end - codeOffset);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
// TODO(scheglov): Replace with some kind of double-iterating list.
var declaration = node.parent!.parent as TopLevelVariableDeclaration;
_writeOffsets(
metadata: declaration.metadata,
constantInitializer: node.initializer,
);
}
void _writeTypeParameters(TypeParameterList? parameterList) {
var parameters = parameterList?.typeParameters ?? <TypeParameter>[];
sink.writeList<TypeParameter>(parameters, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
});
}
}
class _InfoTopLevelVariable {
final int codeOffset;
final int codeLength;
final int nameOffset;
final String? documentationComment;
final Uint32List constantOffsets;
factory _InfoTopLevelVariable(SummaryDataReader reader) {
return _InfoTopLevelVariable._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30(),
documentationComment: reader.readStringUtf8().nullIfEmpty,
constantOffsets: reader.readUInt30List(),
);
}
_InfoTopLevelVariable._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
required this.documentationComment,
required this.constantOffsets,
});
}
class _InfoTypeParameter {
final int codeOffset;
final int codeLength;
final int nameOffset;
factory _InfoTypeParameter(SummaryDataReader reader) {
return _InfoTypeParameter._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
nameOffset: reader.readUInt30(),
);
}
_InfoTypeParameter._({
required this.codeOffset,
required this.codeLength,
required this.nameOffset,
});
}
class _InfoUnit {
final int codeOffset;
final int codeLength;
final List<int> lineStarts;
final _InfoLibraryName libraryName;
final Uint32List libraryConstantOffsets;
final String docComment;
final List<_InfoImport> imports;
final List<_InfoExport> exports;
final List<_InfoPart> parts;
final List<_InfoClassDeclaration> classDeclarations;
final List<_InfoClassTypeAlias> classTypeAliases;
final List<_InfoClassDeclaration> enums;
final List<_InfoClassDeclaration> extensions;
final List<_InfoExtensionTypeDeclaration> extensionTypes;
final List<_InfoMethodDeclaration> accessors;
final List<_InfoFunctionDeclaration> functions;
final List<_InfoFunctionTypeAlias> functionTypeAliases;
final List<_InfoGenericTypeAlias> genericTypeAliases;
final List<_InfoClassDeclaration> mixinDeclarations;
final List<_InfoTopLevelVariable> topLevelVariable;
factory _InfoUnit(InfoDeclarationStore cache, SummaryDataReader reader) {
return _InfoUnit._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
// Having duplicated line-starts adds up --- deduplicate if possible.
lineStarts: _readUint30ListPossiblyFromCache(cache, reader),
libraryName: _InfoLibraryName(reader),
libraryConstantOffsets: reader.readUInt30List(),
docComment: reader.readStringUtf8(),
imports: reader.readTypedList(
() => _InfoImport(reader),
),
exports: reader.readTypedList(
() => _InfoExport(reader),
),
parts: reader.readTypedList(
() => _InfoPart(reader),
),
classDeclarations: reader.readTypedList(
() => _InfoClassDeclaration(cache, reader),
),
classTypeAliases: reader.readTypedList(
() => _InfoClassTypeAlias(reader),
),
enums: reader.readTypedList(
() => _InfoClassDeclaration(cache, reader),
),
extensions: reader.readTypedList(
() => _InfoClassDeclaration(cache, reader, nameOffsetDelta: 1),
),
extensionTypes: reader.readTypedList(
() => _InfoExtensionTypeDeclaration(reader),
),
accessors: reader.readTypedList(
() => _InfoMethodDeclaration(reader),
),
functions: reader.readTypedList(
() => _InfoFunctionDeclaration(reader),
),
functionTypeAliases: reader.readTypedList(
() => _InfoFunctionTypeAlias(reader),
),
genericTypeAliases: reader.readTypedList(
() => _InfoGenericTypeAlias(reader),
),
mixinDeclarations: reader.readTypedList(
() => _InfoClassDeclaration(cache, reader),
),
topLevelVariable: reader.readTypedList(
() => _InfoTopLevelVariable(reader),
),
);
}
_InfoUnit._({
required this.codeOffset,
required this.codeLength,
required this.lineStarts,
required this.libraryName,
required this.libraryConstantOffsets,
required this.docComment,
required this.imports,
required this.exports,
required this.parts,
required this.classDeclarations,
required this.classTypeAliases,
required this.enums,
required this.extensions,
required this.extensionTypes,
required this.accessors,
required this.functions,
required this.functionTypeAliases,
required this.genericTypeAliases,
required this.mixinDeclarations,
required this.topLevelVariable,
});
static Uint32List _readUint30ListPossiblyFromCache(
InfoDeclarationStore cache, SummaryDataReader reader) {
var initialOffset = reader.offset;
var cacheKey = cache.createKey(reader, initialOffset);
var cachedLineStarts =
cache.get<Uint32List>(reader, cacheKey, initialOffset);
if (cachedLineStarts != null) {
return cachedLineStarts;
} else {
// Add to cache.
var lineStarts = reader.readUInt30List();
cache.put(reader, cacheKey, initialOffset, lineStarts);
return lineStarts;
}
}
}
class _OffsetsApplier extends _OffsetsAstVisitor {
final _SafeListIterator<int> _iterator;
_OffsetsApplier(this._iterator);
void applyToAugmentationImports(List<AugmentationImportElement> elements) {
for (var element in elements) {
applyToMetadata(element);
}
}
void applyToConstantInitializer(Element element) {
if (element is ConstFieldElementImpl && element.isEnumConstant) {
_applyToEnumConstantInitializer(element);
} else if (element is ConstVariableElement) {
element.constantInitializer?.accept(this);
}
}
void applyToConstructorInitializers(ConstructorElementImpl element) {
for (var initializer in element.constantInitializers) {
initializer.accept(this);
}
}
void applyToEnumConstants(List<FieldElement> constants) {
for (var constant in constants) {
applyToMetadata(constant);
}
}
void applyToExports(List<LibraryExportElement> elements) {
for (var element in elements) {
applyToMetadata(element);
}
}
void applyToFormalParameters(List<ParameterElement> formalParameters) {
for (var parameter in formalParameters) {
applyToMetadata(parameter);
applyToFormalParameters(parameter.parameters);
applyToConstantInitializer(parameter);
}
}
void applyToImports(List<LibraryImportElement> elements) {
for (var element in elements) {
applyToMetadata(element);
}
}
void applyToMetadata(Element element) {
for (var annotation in element.metadata) {
var node = (annotation as ElementAnnotationImpl).annotationAst;
node.accept(this);
}
}
void applyToPartDirectives(List<PartElement> elements) {
for (var element in elements) {
applyToMetadata(element);
}
}
void applyToTypeParameters(List<TypeParameterElement> typeParameters) {
for (var typeParameter in typeParameters) {
applyToMetadata(typeParameter);
}
}
@override
void handleToken(Token token) {
var offset = _iterator.take();
if (offset != null) {
token.offset = offset;
}
}
@override
void visitFunctionExpression(FunctionExpression node) {
// We store FunctionExpression(s) as empty stubs: `() {}`.
// We just need it to have right code range, so we apply 2 offsets.
node.parameters?.leftParenthesis.offset = _iterator.take() ?? 0;
var body = node.body;
if (body is BlockFunctionBody) {
body.block.rightBracket.offset = _iterator.take() ?? 0;
}
}
@override
void visitSimpleFormalParameter(SimpleFormalParameter node) {
super.visitSimpleFormalParameter(node);
var element = node.declaredElement;
var identifier = node.name;
if (element is ParameterElementImpl && identifier != null) {
element.nameOffset = identifier.offset;
}
}
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
if (isNotSerializableMarker(node)) {
return;
}
super.visitSimpleIdentifier(node);
}
void _applyToEnumConstantInitializer(ConstFieldElementImpl element) {
var initializer = element.constantInitializer;
if (initializer is InstanceCreationExpressionImpl) {
initializer.constructorName.type.typeArguments?.accept(this);
for (var argument in initializer.argumentList.arguments) {
argument.accept(this);
}
}
}
}
abstract class _OffsetsAstVisitor extends RecursiveAstVisitor<void> {
void handleToken(Token token);
@override
void visitAnnotation(Annotation node) {
_tokenOrNull(node.atSign);
_tokenOrNull(node.period);
super.visitAnnotation(node);
}
@override
void visitArgumentList(ArgumentList node) {
_tokenOrNull(node.leftParenthesis);
_tokenOrNull(node.rightParenthesis);
super.visitArgumentList(node);
}
@override
void visitAsExpression(AsExpression node) {
_tokenOrNull(node.asOperator);
super.visitAsExpression(node);
}
@override
void visitAssertInitializer(AssertInitializer node) {
_tokenOrNull(node.assertKeyword);
_tokenOrNull(node.leftParenthesis);
_tokenOrNull(node.comma);
_tokenOrNull(node.rightParenthesis);
super.visitAssertInitializer(node);
}
@override
void visitAssignmentExpression(AssignmentExpression node) {
_tokenOrNull(node.operator);
super.visitAssignmentExpression(node);
}
@override
void visitBinaryExpression(BinaryExpression node) {
_tokenOrNull(node.operator);
super.visitBinaryExpression(node);
}
@override
void visitBooleanLiteral(BooleanLiteral node) {
_tokenOrNull(node.literal);
}
@override
void visitConditionalExpression(ConditionalExpression node) {
_tokenOrNull(node.question);
_tokenOrNull(node.colon);
super.visitConditionalExpression(node);
}
@override
void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
_tokenOrNull(node.thisKeyword);
_tokenOrNull(node.equals);
super.visitConstructorFieldInitializer(node);
}
@override
void visitConstructorName(ConstructorName node) {
node.type.accept(this);
_tokenOrNull(node.period);
node.name?.accept(this);
}
@override
void visitDoubleLiteral(DoubleLiteral node) {
_tokenOrNull(node.literal);
}
@override
void visitFormalParameterList(FormalParameterList node) {
_tokenOrNull(node.leftParenthesis);
_tokenOrNull(node.leftDelimiter);
_tokenOrNull(node.rightDelimiter);
_tokenOrNull(node.rightParenthesis);
super.visitFormalParameterList(node);
}
@override
void visitGenericFunctionType(GenericFunctionType node) {
_tokenOrNull(node.functionKeyword);
super.visitGenericFunctionType(node);
}
@override
void visitIfElement(IfElement node) {
_tokenOrNull(node.ifKeyword);
_tokenOrNull(node.leftParenthesis);
_tokenOrNull(node.rightParenthesis);
_tokenOrNull(node.elseKeyword);
super.visitIfElement(node);
}
@override
void visitImportPrefixReference(ImportPrefixReference node) {
_tokenOrNull(node.name);
_tokenOrNull(node.period);
}
@override
void visitIndexExpression(IndexExpression node) {
_tokenOrNull(node.leftBracket);
_tokenOrNull(node.rightBracket);
super.visitIndexExpression(node);
}
@override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
_tokenOrNull(node.keyword);
node.constructorName.accept(this);
node.argumentList.accept(this);
}
@override
void visitIntegerLiteral(IntegerLiteral node) {
_tokenOrNull(node.literal);
}
@override
void visitInterpolationExpression(InterpolationExpression node) {
_tokenOrNull(node.leftBracket);
_tokenOrNull(node.rightBracket);
super.visitInterpolationExpression(node);
}
@override
void visitInterpolationString(InterpolationString node) {
_tokenOrNull(node.contents);
}
@override
void visitIsExpression(IsExpression node) {
_tokenOrNull(node.isOperator);
super.visitIsExpression(node);
}
@override
void visitLabel(Label node) {
_tokenOrNull(node.colon);
super.visitLabel(node);
}
@override
void visitListLiteral(ListLiteral node) {
_tokenOrNull(node.constKeyword);
_tokenOrNull(node.leftBracket);
_tokenOrNull(node.rightBracket);
super.visitListLiteral(node);
}
@override
void visitMapLiteralEntry(MapLiteralEntry node) {
_tokenOrNull(node.separator);
super.visitMapLiteralEntry(node);
}
@override
void visitMethodInvocation(MethodInvocation node) {
node.target?.accept(this);
_tokenOrNull(node.operator);
node.methodName.accept(this);
node.typeArguments?.accept(this);
node.argumentList.accept(this);
}
@override
void visitNamedType(NamedType node) {
node.importPrefix?.accept(this);
_tokenOrNull(node.name2);
node.typeArguments?.accept(this);
_tokenOrNull(node.question);
}
@override
void visitNullLiteral(NullLiteral node) {
_tokenOrNull(node.literal);
}
@override
void visitParenthesizedExpression(ParenthesizedExpression node) {
_tokenOrNull(node.leftParenthesis);
_tokenOrNull(node.rightParenthesis);
super.visitParenthesizedExpression(node);
}
@override
void visitPostfixExpression(PostfixExpression node) {
_tokenOrNull(node.operator);
super.visitPostfixExpression(node);
}
@override
void visitPrefixedIdentifier(PrefixedIdentifier node) {
node.prefix.accept(this);
_tokenOrNull(node.period);
node.identifier.accept(this);
}
@override
void visitPrefixExpression(PrefixExpression node) {
_tokenOrNull(node.operator);
super.visitPrefixExpression(node);
}
@override
void visitPropertyAccess(PropertyAccess node) {
node.target?.accept(this);
_tokenOrNull(node.operator);
node.propertyName.accept(this);
}
@override
void visitRecordLiteral(RecordLiteral node) {
_tokenOrNull(node.constKeyword);
_tokenOrNull(node.leftParenthesis);
_tokenOrNull(node.rightParenthesis);
super.visitRecordLiteral(node);
}
@override
void visitRecordTypeAnnotation(RecordTypeAnnotation node) {
_tokenOrNull(node.leftParenthesis);
_tokenOrNull(node.rightParenthesis);
_tokenOrNull(node.question);
super.visitRecordTypeAnnotation(node);
}
@override
void visitRecordTypeAnnotationNamedField(
RecordTypeAnnotationNamedField node,
) {
_tokenOrNull(node.name);
super.visitRecordTypeAnnotationNamedField(node);
}
@override
void visitRecordTypeAnnotationNamedFields(
RecordTypeAnnotationNamedFields node,
) {
_tokenOrNull(node.leftBracket);
_tokenOrNull(node.rightBracket);
super.visitRecordTypeAnnotationNamedFields(node);
}
@override
void visitRecordTypeAnnotationPositionalField(
RecordTypeAnnotationPositionalField node,
) {
_tokenOrNull(node.name);
super.visitRecordTypeAnnotationPositionalField(node);
}
@override
void visitRedirectingConstructorInvocation(
RedirectingConstructorInvocation node) {
_tokenOrNull(node.thisKeyword);
_tokenOrNull(node.period);
super.visitRedirectingConstructorInvocation(node);
}
@override
void visitSetOrMapLiteral(SetOrMapLiteral node) {
_tokenOrNull(node.constKeyword);
_tokenOrNull(node.leftBracket);
_tokenOrNull(node.rightBracket);
super.visitSetOrMapLiteral(node);
}
@override
void visitSimpleFormalParameter(SimpleFormalParameter node) {
_tokenOrNull(node.requiredKeyword);
_tokenOrNull(node.name);
super.visitSimpleFormalParameter(node);
}
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
_tokenOrNull(node.token);
}
@override
void visitSimpleStringLiteral(SimpleStringLiteral node) {
_tokenOrNull(node.literal);
}
@override
void visitSpreadElement(SpreadElement node) {
_tokenOrNull(node.spreadOperator);
super.visitSpreadElement(node);
}
@override
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
_tokenOrNull(node.superKeyword);
_tokenOrNull(node.period);
super.visitSuperConstructorInvocation(node);
}
@override
void visitSuperExpression(SuperExpression node) {
_tokenOrNull(node.superKeyword);
}
@override
void visitSymbolLiteral(SymbolLiteral node) {
_tokenOrNull(node.poundSign);
node.components.forEach(_tokenOrNull);
}
@override
void visitThisExpression(ThisExpression node) {
_tokenOrNull(node.thisKeyword);
}
@override
void visitThrowExpression(ThrowExpression node) {
_tokenOrNull(node.throwKeyword);
super.visitThrowExpression(node);
}
@override
void visitTypeArgumentList(TypeArgumentList node) {
_tokenOrNull(node.leftBracket);
_tokenOrNull(node.rightBracket);
super.visitTypeArgumentList(node);
}
void _tokenOrNull(Token? token) {
if (token != null) {
handleToken(token);
}
}
}
class _OffsetsCollector extends _OffsetsAstVisitor {
final List<int> offsets = [];
@override
void handleToken(Token token) {
offsets.add(token.offset);
}
@override
void visitFunctionExpression(FunctionExpression node) {
offsets.add(node.offset);
offsets.add(node.end - 1);
}
}
class _SafeListIterator<T> {
final List<T> _elements;
int _index = 0;
_SafeListIterator(this._elements);
bool get hasNext {
return _index < _elements.length;
}
T? take() {
if (hasNext) {
return _elements[_index++];
} else {
return null;
}
}
}
extension on String {
String? get nullIfEmpty {
return isNotEmpty ? this : null;
}
}
extension _ListOfElement<T extends Element> on List<T> {
List<T> get notSynthetic {
return where((e) => !e.isSynthetic).toList();
}
}