| // 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/ast/ast.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/dart/element/member.dart'; |
| import 'package:analyzer/src/dart/element/type.dart'; |
| import 'package:analyzer/src/dart/element/type_algebra.dart'; |
| import 'package:analyzer/src/dart/resolver/variance.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:analyzer/src/summary2/ast_binary_reader.dart'; |
| import 'package:analyzer/src/summary2/ast_binary_tag.dart'; |
| import 'package:analyzer/src/summary2/data_reader.dart'; |
| import 'package:analyzer/src/summary2/element_flags.dart'; |
| import 'package:analyzer/src/summary2/export.dart'; |
| import 'package:analyzer/src/summary2/informative_data.dart'; |
| import 'package:analyzer/src/summary2/linked_element_factory.dart'; |
| import 'package:analyzer/src/summary2/macro_application_error.dart'; |
| import 'package:analyzer/src/summary2/reference.dart'; |
| import 'package:analyzer/src/task/inference_error.dart'; |
| import 'package:pub_semver/pub_semver.dart'; |
| |
| class BundleReader { |
| final SummaryDataReader _reader; |
| final Map<Uri, Uint8List> _unitsInformativeBytes; |
| |
| final Map<Uri, LibraryReader> libraryMap = {}; |
| |
| BundleReader({ |
| required LinkedElementFactory elementFactory, |
| required Uint8List resolutionBytes, |
| Map<Uri, Uint8List> unitsInformativeBytes = const {}, |
| }) : _reader = SummaryDataReader(resolutionBytes), |
| _unitsInformativeBytes = unitsInformativeBytes { |
| _reader.offset = _reader.bytes.length - 4 * 4; |
| var baseResolutionOffset = _reader.readUInt32(); |
| var librariesOffset = _reader.readUInt32(); |
| var referencesOffset = _reader.readUInt32(); |
| var stringsOffset = _reader.readUInt32(); |
| _reader.createStringTable(stringsOffset); |
| |
| var referenceReader = _ReferenceReader( |
| elementFactory, |
| _reader, |
| referencesOffset, |
| ); |
| |
| _reader.offset = librariesOffset; |
| var libraryHeaderList = _reader.readTypedList(() { |
| return _LibraryHeader( |
| uri: Uri.parse(_reader.readStringReference()), |
| offset: _reader.readUInt30(), |
| classMembersLengths: _reader.readUInt30List(), |
| ); |
| }); |
| |
| for (var libraryHeader in libraryHeaderList) { |
| var uri = libraryHeader.uri; |
| var reference = elementFactory.rootReference.getChild('$uri'); |
| libraryMap[uri] = LibraryReader._( |
| elementFactory: elementFactory, |
| reader: _reader, |
| unitsInformativeBytes: _unitsInformativeBytes, |
| baseResolutionOffset: baseResolutionOffset, |
| referenceReader: referenceReader, |
| reference: reference, |
| offset: libraryHeader.offset, |
| classMembersLengths: libraryHeader.classMembersLengths, |
| ); |
| } |
| } |
| } |
| |
| class ClassElementLinkedData extends ElementLinkedData<ClassElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| void Function()? _readMembers; |
| void Function()? applyInformativeDataToMembers; |
| |
| ClassElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| /// Ensure that all members of the [element] are available. This includes |
| /// being able to ask them for example using [ClassElement.methods], and |
| /// as well access them through their [Reference]s. For a class declaration |
| /// this means reading them, for a named mixin application this means |
| /// computing constructors. |
| void readMembers(ClassElementImpl element) { |
| if (element.isMixinApplication) { |
| element.constructors; |
| } else { |
| _readMembers?.call(); |
| _readMembers = null; |
| |
| applyInformativeDataToMembers?.call(); |
| applyInformativeDataToMembers = null; |
| } |
| } |
| |
| @override |
| void _read(element, reader) { |
| element.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| _readTypeParameters(reader, element.typeParameters); |
| element.supertype = reader._readOptionalInterfaceType(); |
| element.mixins = reader._readInterfaceTypeList(); |
| element.interfaces = reader._readInterfaceTypeList(); |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| class CompilationUnitElementLinkedData |
| extends ElementLinkedData<CompilationUnitElementImpl> { |
| CompilationUnitElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) {} |
| } |
| |
| class ConstructorElementLinkedData |
| extends ElementLinkedData<ConstructorElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| ConstructorElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| _addEnclosingElementTypeParameters(reader, element); |
| |
| element.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| reader._addFormalParameters(element.parameters); |
| _readFormalParameters(reader, element.parameters); |
| element.superConstructor = reader.readElement() as ConstructorElement?; |
| element.redirectedConstructor = reader.readElement() as ConstructorElement?; |
| element.constantInitializers = reader._readNodeList(); |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| /// Lazy reader of resolution information. |
| abstract class ElementLinkedData<E extends ElementImpl> { |
| final Reference reference; |
| final LibraryReader _libraryReader; |
| final CompilationUnitElementImpl unitElement; |
| |
| /// When this object is created, this offset is the offset of the resolution |
| /// information in the [_libraryReader]. After reading is done, this offset |
| /// is set to `-1`. |
| int _offset; |
| |
| ElementLinkedData( |
| this.reference, LibraryReader libraryReader, this.unitElement, int offset) |
| : _libraryReader = libraryReader, |
| _offset = offset; |
| |
| void read(ElementImpl element) { |
| if (_offset == -1) { |
| return; |
| } |
| |
| var dataReader = _libraryReader._reader.fork(_offset); |
| _offset = -1; |
| |
| var reader = ResolutionReader( |
| _libraryReader._elementFactory, |
| _libraryReader._referenceReader, |
| dataReader, |
| ); |
| |
| _read(element as E, reader); |
| } |
| |
| void _addEnclosingElementTypeParameters( |
| ResolutionReader reader, |
| ElementImpl element, |
| ) { |
| var enclosing = element.enclosingElement; |
| if (enclosing is ClassElement) { |
| reader._addTypeParameters(enclosing.typeParameters); |
| } else if (enclosing is CompilationUnitElement) { |
| // Nothing. |
| } else if (enclosing is ExtensionElement) { |
| reader._addTypeParameters(enclosing.typeParameters); |
| } else { |
| throw UnimplementedError('${enclosing.runtimeType}'); |
| } |
| } |
| |
| void _read(E element, ResolutionReader reader); |
| |
| void _readFormalParameters( |
| ResolutionReader reader, |
| List<ParameterElement> parameters, |
| ) { |
| for (var parameter in parameters) { |
| parameter as ParameterElementImpl; |
| parameter.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| _readTypeParameters(reader, parameter.typeParameters); |
| _readFormalParameters(reader, parameter.parameters); |
| parameter.type = reader.readRequiredType(); |
| if (parameter is ConstVariableElement) { |
| var defaultParameter = parameter as ConstVariableElement; |
| var initializer = reader._readOptionalExpression(); |
| if (initializer != null) { |
| defaultParameter.constantInitializer = initializer; |
| } |
| } |
| if (parameter is FieldFormalParameterElementImpl) { |
| parameter.field = reader.readElement() as FieldElement?; |
| } |
| } |
| } |
| |
| void _readTypeParameters( |
| ResolutionReader reader, |
| List<TypeParameterElement> typeParameters, |
| ) { |
| reader._addTypeParameters(typeParameters); |
| for (var typeParameter in typeParameters) { |
| typeParameter as TypeParameterElementImpl; |
| typeParameter.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| typeParameter.bound = reader.readType(); |
| typeParameter.defaultType = reader.readType(); |
| } |
| } |
| } |
| |
| class EnumElementLinkedData extends ElementLinkedData<EnumElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| EnumElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| element.metadata = reader._readAnnotationList( |
| unitElement: element.enclosingElement, |
| ); |
| _readTypeParameters(reader, element.typeParameters); |
| element.supertype = reader._readOptionalInterfaceType(); |
| element.mixins = reader._readInterfaceTypeList(); |
| element.interfaces = reader._readInterfaceTypeList(); |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| class ExtensionElementLinkedData |
| extends ElementLinkedData<ExtensionElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| ExtensionElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| element.metadata = reader._readAnnotationList( |
| unitElement: element.enclosingElement, |
| ); |
| _readTypeParameters(reader, element.typeParameters); |
| element.extendedType = reader.readRequiredType(); |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| class FieldElementLinkedData extends ElementLinkedData<FieldElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| FieldElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| _addEnclosingElementTypeParameters(reader, element); |
| element.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| element.type = reader.readRequiredType(); |
| if (element is ConstFieldElementImpl) { |
| var initializer = reader._readOptionalExpression(); |
| if (initializer != null) { |
| element.constantInitializer = initializer; |
| ConstantContextForExpressionImpl(initializer); |
| } |
| } |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| class FunctionElementLinkedData extends ElementLinkedData<FunctionElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| FunctionElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| element.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| _readTypeParameters(reader, element.typeParameters); |
| element.returnType = reader.readRequiredType(); |
| _readFormalParameters(reader, element.parameters); |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| class LibraryElementLinkedData extends ElementLinkedData<LibraryElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| LibraryElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| LinkedElementFactory get elementFactory { |
| return _libraryReader._elementFactory; |
| } |
| |
| @override |
| void _read(element, reader) { |
| element.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| |
| for (var import in element.imports2) { |
| import as ImportElement2Impl; |
| import.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| final uri = import.uri; |
| if (uri is DirectiveUriWithLibraryImpl) { |
| uri.library = reader.libraryOfUri(uri.source.uri); |
| } |
| } |
| |
| for (var export in element.exports) { |
| export as ExportElementImpl; |
| export.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| export.exportedLibrary = reader.readElement() as LibraryElementImpl?; |
| } |
| |
| for (final part in element.parts2) { |
| part as PartElementImpl; |
| part.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| } |
| |
| element.entryPoint = reader.readElement() as FunctionElement?; |
| |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| class LibraryReader { |
| final LinkedElementFactory _elementFactory; |
| final SummaryDataReader _reader; |
| final Map<Uri, Uint8List> _unitsInformativeBytes; |
| final int _baseResolutionOffset; |
| final _ReferenceReader _referenceReader; |
| final Reference _reference; |
| final int _offset; |
| |
| final Uint32List _classMembersLengths; |
| int _classMembersLengthsIndex = 0; |
| |
| LibraryReader._({ |
| required LinkedElementFactory elementFactory, |
| required SummaryDataReader reader, |
| required Map<Uri, Uint8List> unitsInformativeBytes, |
| required int baseResolutionOffset, |
| required _ReferenceReader referenceReader, |
| required Reference reference, |
| required int offset, |
| required Uint32List classMembersLengths, |
| }) : _elementFactory = elementFactory, |
| _reader = reader, |
| _unitsInformativeBytes = unitsInformativeBytes, |
| _baseResolutionOffset = baseResolutionOffset, |
| _referenceReader = referenceReader, |
| _reference = reference, |
| _offset = offset, |
| _classMembersLengths = classMembersLengths; |
| |
| LibraryElementImpl readElement({required Source librarySource}) { |
| var analysisContext = _elementFactory.analysisContext; |
| var analysisSession = _elementFactory.analysisSession; |
| |
| _reader.offset = _offset; |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| |
| var name = _reader.readStringReference(); |
| var featureSet = _readFeatureSet(); |
| |
| var libraryElement = LibraryElementImpl( |
| analysisContext, analysisSession, name, -1, 0, featureSet); |
| _reference.element = libraryElement; |
| libraryElement.reference = _reference; |
| |
| libraryElement.languageVersion = _readLanguageVersion(); |
| libraryElement.imports2 = _reader.readTypedList(() { |
| return _readImportElement( |
| libraryElement: libraryElement, |
| ); |
| }); |
| libraryElement.exports = _reader.readTypedList(_readExportElement); |
| LibraryElementFlags.read(_reader, libraryElement); |
| |
| for (final import in libraryElement.imports2) { |
| final prefixElement = import.prefix?.element; |
| if (prefixElement is PrefixElementImpl) { |
| libraryElement.encloseElement(prefixElement); |
| } |
| } |
| |
| libraryElement.definingCompilationUnit = _readUnitElement( |
| libraryElement: libraryElement, |
| librarySource: librarySource, |
| unitSource: librarySource, |
| ); |
| |
| libraryElement.parts2 = _reader.readTypedList(() { |
| return _readPartElement( |
| libraryElement: libraryElement, |
| ); |
| }); |
| |
| libraryElement.exportedReferences = _reader.readTypedList( |
| _readExportedReference, |
| ); |
| |
| libraryElement.linkedData = LibraryElementLinkedData( |
| reference: _reference, |
| libraryReader: this, |
| unitElement: libraryElement.definingCompilationUnit, |
| offset: resolutionOffset, |
| ); |
| |
| _declareDartCoreDynamicNever(); |
| |
| InformativeDataApplier(_elementFactory, _unitsInformativeBytes) |
| .applyTo(libraryElement); |
| |
| return libraryElement; |
| } |
| |
| /// These elements are implicitly declared in `dart:core`. |
| void _declareDartCoreDynamicNever() { |
| if (_reference.name == 'dart:core') { |
| _reference.getChild('dynamic').element = DynamicElementImpl.instance; |
| _reference.getChild('Never').element = NeverElementImpl.instance; |
| } |
| } |
| |
| ClassElementImpl _readClassElement( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readStringReference(); |
| var reference = unitReference.getChild('@class').getChild(name); |
| |
| var element = ClassElementImpl(name, -1); |
| |
| var linkedData = ClassElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| ClassElementFlags.read(_reader, element); |
| element.macroApplicationErrors = _reader.readTypedList( |
| () => MacroApplicationError(_reader), |
| ); |
| |
| element.typeParameters = _readTypeParameters(); |
| |
| if (!element.isMixinApplication) { |
| var membersOffset = _reader.offset; |
| linkedData._readMembers = () { |
| _reader.offset = membersOffset; |
| _readClassElementMembers(unitElement, element, reference); |
| }; |
| _reader.offset += _classMembersLengths[_classMembersLengthsIndex++]; |
| } |
| |
| return element; |
| } |
| |
| void _readClassElementMembers( |
| CompilationUnitElementImpl unitElement, |
| ClassElementImpl element, |
| Reference reference, |
| ) { |
| var accessors = <PropertyAccessorElementImpl>[]; |
| var fields = <FieldElement>[]; |
| _readFields(unitElement, element, reference, accessors, fields); |
| _readPropertyAccessors( |
| unitElement, element, reference, accessors, fields, '@field'); |
| element.fields = fields; |
| element.accessors = accessors; |
| |
| element.constructors = _readConstructors(unitElement, element, reference); |
| element.methods = _readMethods(unitElement, element, reference); |
| } |
| |
| void _readClasses( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var length = _reader.readUInt30(); |
| unitElement.classes = List.generate(length, (index) { |
| return _readClassElement(unitElement, unitReference); |
| }); |
| } |
| |
| List<ConstructorElementImpl> _readConstructors( |
| CompilationUnitElementImpl unitElement, |
| AbstractClassElementImpl classElement, |
| Reference classReference, |
| ) { |
| var containerRef = classReference.getChild('@constructor'); |
| var length = _reader.readUInt30(); |
| return List.generate(length, (_) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readStringReference(); |
| var reference = containerRef.getChild(name); |
| var element = ConstructorElementImpl(name, -1); |
| var linkedData = ConstructorElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| ConstructorElementFlags.read(_reader, element); |
| element.parameters = _readParameters(element, reference); |
| return element; |
| }); |
| } |
| |
| DirectiveUri _readDirectiveUri({ |
| required LibraryElementImpl libraryElement, |
| }) { |
| DirectiveUriWithRelativeUriStringImpl readWithRelativeUriString() { |
| final relativeUriString = _reader.readStringReference(); |
| return DirectiveUriWithRelativeUriStringImpl( |
| relativeUriString: relativeUriString, |
| ); |
| } |
| |
| DirectiveUriWithRelativeUriImpl readWithRelativeUri() { |
| final parent = readWithRelativeUriString(); |
| final relativeUri = Uri.parse(_reader.readStringReference()); |
| return DirectiveUriWithRelativeUriImpl( |
| relativeUriString: parent.relativeUriString, |
| relativeUri: relativeUri, |
| ); |
| } |
| |
| DirectiveUriWithSourceImpl readWithSource() { |
| final parent = readWithRelativeUri(); |
| |
| final analysisContext = _elementFactory.analysisContext; |
| final sourceFactory = analysisContext.sourceFactory; |
| |
| final sourceUriStr = _reader.readStringReference(); |
| final sourceUri = Uri.parse(sourceUriStr); |
| final source = sourceFactory.forUri2(sourceUri); |
| |
| // TODO(scheglov) https://github.com/dart-lang/sdk/issues/49431 |
| final fixedSource = source ?? sourceFactory.forUri('dart:math')!; |
| |
| return DirectiveUriWithSourceImpl( |
| relativeUriString: parent.relativeUriString, |
| relativeUri: parent.relativeUri, |
| source: fixedSource, |
| ); |
| } |
| |
| final kindIndex = _reader.readByte(); |
| final kind = DirectiveUriKind.values[kindIndex]; |
| switch (kind) { |
| case DirectiveUriKind.withUnit: |
| final parent = readWithSource(); |
| final unitElement = _readUnitElement( |
| libraryElement: libraryElement, |
| librarySource: libraryElement.source, |
| unitSource: parent.source, |
| ); |
| return DirectiveUriWithUnitImpl( |
| relativeUriString: parent.relativeUriString, |
| relativeUri: parent.relativeUri, |
| unit: unitElement, |
| ); |
| case DirectiveUriKind.withLibrary: |
| final parent = readWithSource(); |
| return DirectiveUriWithLibraryImpl.read( |
| relativeUriString: parent.relativeUriString, |
| relativeUri: parent.relativeUri, |
| source: parent.source, |
| ); |
| case DirectiveUriKind.withSource: |
| return readWithSource(); |
| case DirectiveUriKind.withRelativeUri: |
| return readWithRelativeUri(); |
| case DirectiveUriKind.withRelativeUriString: |
| return readWithRelativeUriString(); |
| case DirectiveUriKind.withNothing: |
| return DirectiveUriImpl(); |
| } |
| } |
| |
| EnumElementImpl _readEnumElement( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readStringReference(); |
| var reference = unitReference.getChild('@enum').getChild(name); |
| |
| var element = EnumElementImpl(name, -1); |
| |
| var linkedData = EnumElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| EnumElementFlags.read(_reader, element); |
| |
| element.typeParameters = _readTypeParameters(); |
| |
| var accessors = <PropertyAccessorElement>[]; |
| var fields = <FieldElement>[]; |
| |
| _readFields(unitElement, element, reference, accessors, fields); |
| _readPropertyAccessors( |
| unitElement, element, reference, accessors, fields, '@field'); |
| element.fields = fields; |
| element.accessors = accessors; |
| |
| element.constructors = _readConstructors(unitElement, element, reference); |
| element.methods = _readMethods(unitElement, element, reference); |
| |
| return element; |
| } |
| |
| void _readEnums( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var count = _reader.readUInt30(); |
| unitElement.enums = List.generate(count, (_) { |
| return _readEnumElement(unitElement, unitReference); |
| }); |
| } |
| |
| ExportedReference _readExportedReference() { |
| final kind = _reader.readByte(); |
| if (kind == 0) { |
| final index = _reader.readUInt30(); |
| final reference = _referenceReader.referenceOfIndex(index); |
| return ExportedReferenceDeclared( |
| reference: reference, |
| ); |
| } else if (kind == 1) { |
| final index = _reader.readUInt30(); |
| final reference = _referenceReader.referenceOfIndex(index); |
| return ExportedReferenceExported( |
| reference: reference, |
| indexes: _reader.readUInt30List(), |
| ); |
| } else { |
| throw StateError('kind: $kind'); |
| } |
| } |
| |
| ExportElementImpl _readExportElement() { |
| var element = ExportElementImpl(-1); |
| element.uri = _reader.readOptionalStringReference(); |
| element.combinators = _reader.readTypedList(_readNamespaceCombinator); |
| return element; |
| } |
| |
| ExtensionElementImpl _readExtensionElement( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readOptionalStringReference(); |
| var refName = _reader.readStringReference(); |
| var reference = unitReference.getChild('@extension').getChild(refName); |
| |
| var element = ExtensionElementImpl(name, -1); |
| element.setLinkedData( |
| reference, |
| ExtensionElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ), |
| ); |
| |
| element.typeParameters = _readTypeParameters(); |
| |
| var accessors = <PropertyAccessorElement>[]; |
| var fields = <FieldElement>[]; |
| _readPropertyAccessors( |
| unitElement, element, reference, accessors, fields, '@field'); |
| _readFields(unitElement, element, reference, accessors, fields); |
| element.accessors = accessors; |
| element.fields = fields; |
| |
| element.methods = _readMethods(unitElement, element, reference); |
| |
| return element; |
| } |
| |
| void _readExtensions( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var count = _reader.readUInt30(); |
| unitElement.extensions = List.generate(count, (_) { |
| return _readExtensionElement(unitElement, unitReference); |
| }); |
| } |
| |
| FeatureSet _readFeatureSet() { |
| var featureSetEncoded = _reader.readUint8List(); |
| return ExperimentStatus.fromStorage(featureSetEncoded); |
| } |
| |
| FieldElementImpl _readFieldElement( |
| CompilationUnitElementImpl unitElement, |
| ElementImpl classElement, |
| Reference classReference, |
| Reference containerRef, |
| ) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readStringReference(); |
| var isConstElement = _reader.readBool(); |
| var reference = containerRef.getChild(name); |
| |
| FieldElementImpl element; |
| if (isConstElement) { |
| element = ConstFieldElementImpl(name, -1); |
| } else { |
| element = FieldElementImpl(name, -1); |
| } |
| |
| var linkedData = FieldElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| |
| FieldElementFlags.read(_reader, element); |
| element.typeInferenceError = _readTopLevelInferenceError(); |
| element.createImplicitAccessors(classReference, name); |
| |
| return element; |
| } |
| |
| void _readFields( |
| CompilationUnitElementImpl unitElement, |
| ElementImpl classElement, |
| Reference classReference, |
| List<PropertyAccessorElement> accessors, |
| List<FieldElement> variables, |
| ) { |
| var containerRef = classReference.getChild('@field'); |
| var createdElements = <FieldElement>[]; |
| var variableElementCount = _reader.readUInt30(); |
| for (var i = 0; i < variableElementCount; i++) { |
| var variable = _readFieldElement( |
| unitElement, classElement, classReference, containerRef); |
| createdElements.add(variable); |
| variables.add(variable); |
| |
| var getter = variable.getter; |
| if (getter is PropertyAccessorElementImpl) { |
| accessors.add(getter); |
| } |
| |
| var setter = variable.setter; |
| if (setter is PropertyAccessorElementImpl) { |
| accessors.add(setter); |
| } |
| } |
| } |
| |
| void _readFunctions( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var count = _reader.readUInt30(); |
| unitElement.functions = List.generate(count, (_) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readStringReference(); |
| var reference = unitReference.getChild('@function').getChild(name); |
| |
| var element = FunctionElementImpl(name, -1); |
| |
| var linkedData = FunctionElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| |
| FunctionElementFlags.read(_reader, element); |
| element.typeParameters = _readTypeParameters(); |
| element.parameters = _readParameters(element, reference); |
| |
| return element; |
| }); |
| } |
| |
| ImportElement2Impl _readImportElement({ |
| required LibraryElementImpl libraryElement, |
| }) { |
| final uri = _readDirectiveUri( |
| libraryElement: libraryElement, |
| ); |
| final prefix = _readImportElementPrefix(); |
| final combinators = _reader.readTypedList(_readNamespaceCombinator); |
| |
| final element = ImportElement2Impl( |
| importKeywordOffset: -1, |
| uri: uri, |
| prefix: prefix, |
| )..combinators = combinators; |
| ImportElementFlags.read(_reader, element); |
| return element; |
| } |
| |
| ImportElementPrefixImpl? _readImportElementPrefix() { |
| PrefixElementImpl buildElement(String name) { |
| final reference = _reference.getChild('@prefix').getChild(name); |
| final existing = reference.element; |
| if (existing is PrefixElementImpl) { |
| return existing; |
| } else { |
| return PrefixElementImpl(name, -1, reference: reference); |
| } |
| } |
| |
| final kindIndex = _reader.readByte(); |
| final kind = ImportElementPrefixKind.values[kindIndex]; |
| switch (kind) { |
| case ImportElementPrefixKind.isDeferred: |
| final name = _reader.readStringReference(); |
| return DeferredImportElementPrefixImpl( |
| element: buildElement(name), |
| ); |
| case ImportElementPrefixKind.isNotDeferred: |
| final name = _reader.readStringReference(); |
| return ImportElementPrefixImpl( |
| element: buildElement(name), |
| ); |
| case ImportElementPrefixKind.isNull: |
| return null; |
| } |
| } |
| |
| LibraryLanguageVersion _readLanguageVersion() { |
| var packageMajor = _reader.readUInt30(); |
| var packageMinor = _reader.readUInt30(); |
| var package = Version(packageMajor, packageMinor, 0); |
| |
| Version? override; |
| if (_reader.readBool()) { |
| var overrideMajor = _reader.readUInt30(); |
| var overrideMinor = _reader.readUInt30(); |
| override = Version(overrideMajor, overrideMinor, 0); |
| } |
| |
| return LibraryLanguageVersion(package: package, override: override); |
| } |
| |
| List<MethodElementImpl> _readMethods( |
| CompilationUnitElementImpl unitElement, |
| ElementImpl enclosingElement, |
| Reference enclosingReference, |
| ) { |
| var containerRef = enclosingReference.getChild('@method'); |
| var length = _reader.readUInt30(); |
| return List.generate(length, (_) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readStringReference(); |
| var reference = containerRef.getChild(name); |
| var element = MethodElementImpl(name, -1); |
| var linkedData = MethodElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| MethodElementFlags.read(_reader, element); |
| element.typeParameters = _readTypeParameters(); |
| element.parameters = _readParameters(element, reference); |
| element.typeInferenceError = _readTopLevelInferenceError(); |
| return element; |
| }); |
| } |
| |
| MixinElementImpl _readMixinElement( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readStringReference(); |
| var reference = unitReference.getChild('@mixin').getChild(name); |
| |
| var element = MixinElementImpl(name, -1); |
| |
| var linkedData = MixinElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| MixinElementFlags.read(_reader, element); |
| |
| element.typeParameters = _readTypeParameters(); |
| |
| var fields = <FieldElement>[]; |
| var accessors = <PropertyAccessorElement>[]; |
| _readFields(unitElement, element, reference, accessors, fields); |
| _readPropertyAccessors( |
| unitElement, element, reference, accessors, fields, '@field'); |
| element.fields = fields; |
| element.accessors = accessors; |
| |
| element.constructors = _readConstructors(unitElement, element, reference); |
| element.methods = _readMethods(unitElement, element, reference); |
| element.superInvokedNames = _reader.readStringReferenceList(); |
| |
| return element; |
| } |
| |
| void _readMixins( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var length = _reader.readUInt30(); |
| unitElement.mixins = List.generate(length, (index) { |
| return _readMixinElement(unitElement, unitReference); |
| }); |
| } |
| |
| NamespaceCombinator _readNamespaceCombinator() { |
| var tag = _reader.readByte(); |
| if (tag == Tag.HideCombinator) { |
| var combinator = HideElementCombinatorImpl(); |
| combinator.hiddenNames = _reader.readStringReferenceList(); |
| return combinator; |
| } else if (tag == Tag.ShowCombinator) { |
| var combinator = ShowElementCombinatorImpl(); |
| combinator.shownNames = _reader.readStringReferenceList(); |
| return combinator; |
| } else { |
| throw UnimplementedError('tag: $tag'); |
| } |
| } |
| |
| List<ParameterElementImpl> _readParameters( |
| ElementImpl enclosingElement, |
| Reference enclosingReference, |
| ) { |
| var containerRef = enclosingReference.getChild('@parameter'); |
| var length = _reader.readUInt30(); |
| return List.generate(length, (_) { |
| var name = _reader.readStringReference(); |
| var isInitializingFormal = _reader.readBool(); |
| var isSuperFormal = _reader.readBool(); |
| var reference = containerRef.getChild(name); |
| |
| var kindIndex = _reader.readByte(); |
| var kind = ResolutionReader._formalParameterKind(kindIndex); |
| |
| ParameterElementImpl element; |
| if (kind.isRequiredPositional) { |
| if (isInitializingFormal) { |
| element = FieldFormalParameterElementImpl( |
| name: name, |
| nameOffset: -1, |
| parameterKind: kind, |
| ); |
| } else if (isSuperFormal) { |
| element = SuperFormalParameterElementImpl( |
| name: name, |
| nameOffset: -1, |
| parameterKind: kind, |
| ); |
| } else { |
| element = ParameterElementImpl( |
| name: name, |
| nameOffset: -1, |
| parameterKind: kind, |
| ); |
| } |
| } else { |
| if (isInitializingFormal) { |
| element = DefaultFieldFormalParameterElementImpl( |
| name: name, |
| nameOffset: -1, |
| parameterKind: kind, |
| ); |
| } else if (isSuperFormal) { |
| element = DefaultSuperFormalParameterElementImpl( |
| name: name, |
| nameOffset: -1, |
| parameterKind: kind, |
| ); |
| } else { |
| element = DefaultParameterElementImpl( |
| name: name, |
| nameOffset: -1, |
| parameterKind: kind, |
| ); |
| } |
| element.reference = reference; |
| reference.element = element; |
| } |
| ParameterElementFlags.read(_reader, element); |
| element.typeParameters = _readTypeParameters(); |
| element.parameters = _readParameters(element, reference); |
| return element; |
| }); |
| } |
| |
| PartElement _readPartElement({ |
| required LibraryElementImpl libraryElement, |
| }) { |
| final uri = _readDirectiveUri( |
| libraryElement: libraryElement, |
| ); |
| |
| return PartElementImpl( |
| uri: uri, |
| ); |
| } |
| |
| PropertyAccessorElementImpl _readPropertyAccessorElement( |
| CompilationUnitElementImpl unitElement, |
| ElementImpl classElement, |
| Reference classReference, |
| ) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| |
| var name = _reader.readStringReference(); |
| |
| var element = PropertyAccessorElementImpl(name, -1); |
| PropertyAccessorElementFlags.read(_reader, element); |
| |
| var reference = classReference |
| .getChild(element.isGetter ? '@getter' : '@setter') |
| .getChild(name); |
| var linkedData = PropertyAccessorElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| |
| element.parameters = _readParameters(element, reference); |
| return element; |
| } |
| |
| void _readPropertyAccessors( |
| CompilationUnitElementImpl unitElement, |
| ElementImpl enclosingElement, |
| Reference enclosingReference, |
| List<PropertyAccessorElement> accessors, |
| List<PropertyInducingElement> properties, |
| String containerRefName, |
| ) { |
| var containerRef = enclosingReference.getChild(containerRefName); |
| |
| var accessorCount = _reader.readUInt30(); |
| for (var i = 0; i < accessorCount; i++) { |
| var accessor = _readPropertyAccessorElement( |
| unitElement, |
| enclosingElement, |
| enclosingReference, |
| ); |
| accessors.add(accessor); |
| |
| var name = accessor.displayName; |
| var isGetter = accessor.isGetter; |
| |
| var reference = containerRef.getChild(name); |
| |
| PropertyInducingElementImpl property; |
| if (enclosingElement is CompilationUnitElementImpl) { |
| var existing = reference.element; |
| if (existing is TopLevelVariableElementImpl) { |
| property = existing; |
| } else { |
| var field = TopLevelVariableElementImpl(name, -1); |
| property = field; |
| } |
| } else { |
| var existing = reference.element; |
| if (existing is FieldElementImpl) { |
| property = existing; |
| } else { |
| var field = FieldElementImpl(name, -1); |
| field.isStatic = accessor.isStatic; |
| property = field; |
| } |
| } |
| |
| if (reference.element == null) { |
| reference.element = property; |
| properties.add(property); |
| |
| property.enclosingElement = enclosingElement; |
| property.isSynthetic = true; |
| } |
| |
| accessor.variable = property; |
| if (isGetter) { |
| property.getter = accessor; |
| } else { |
| property.setter = accessor; |
| if (property.isSynthetic) { |
| property.isFinal = false; |
| } |
| } |
| } |
| } |
| |
| TopLevelInferenceError? _readTopLevelInferenceError() { |
| var kindIndex = _reader.readByte(); |
| var kind = TopLevelInferenceErrorKind.values[kindIndex]; |
| if (kind == TopLevelInferenceErrorKind.none) { |
| return null; |
| } |
| return TopLevelInferenceError( |
| kind: kind, |
| arguments: _reader.readStringReferenceList(), |
| ); |
| } |
| |
| TopLevelVariableElementImpl _readTopLevelVariableElement( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readStringReference(); |
| var isConst = _reader.readBool(); |
| var reference = unitReference.getChild('@variable').getChild(name); |
| |
| TopLevelVariableElementImpl element; |
| if (isConst) { |
| element = ConstTopLevelVariableElementImpl(name, -1); |
| } else { |
| element = TopLevelVariableElementImpl(name, -1); |
| } |
| |
| var linkedData = TopLevelVariableElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| |
| element.isConst = isConst; |
| TopLevelVariableElementFlags.read(_reader, element); |
| element.typeInferenceError = _readTopLevelInferenceError(); |
| element.createImplicitAccessors(unitReference, name); |
| |
| return element; |
| } |
| |
| void _readTopLevelVariables( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| List<PropertyAccessorElementImpl> accessors, |
| List<TopLevelVariableElementImpl> variables, |
| ) { |
| var variableElementCount = _reader.readUInt30(); |
| for (var i = 0; i < variableElementCount; i++) { |
| var variable = _readTopLevelVariableElement(unitElement, unitReference); |
| variables.add(variable); |
| |
| var getter = variable.getter; |
| if (getter is PropertyAccessorElementImpl) { |
| accessors.add(getter); |
| } |
| |
| var setter = variable.setter; |
| if (setter is PropertyAccessorElementImpl) { |
| accessors.add(setter); |
| } |
| } |
| } |
| |
| TypeAliasElementImpl _readTypeAliasElement( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| var name = _reader.readStringReference(); |
| var reference = unitReference.getChild('@typeAlias').getChild(name); |
| |
| var isFunctionTypeAliasBased = _reader.readBool(); |
| |
| TypeAliasElementImpl element; |
| if (isFunctionTypeAliasBased) { |
| element = TypeAliasElementImpl(name, -1); |
| element.isFunctionTypeAliasBased = true; |
| } else { |
| element = TypeAliasElementImpl(name, -1); |
| } |
| |
| var linkedData = TypeAliasElementLinkedData( |
| reference: reference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ); |
| element.setLinkedData(reference, linkedData); |
| |
| element.isFunctionTypeAliasBased = isFunctionTypeAliasBased; |
| TypeAliasElementFlags.read(_reader, element); |
| |
| element.typeParameters = _readTypeParameters(); |
| |
| return element; |
| } |
| |
| void _readTypeAliases( |
| CompilationUnitElementImpl unitElement, |
| Reference unitReference, |
| ) { |
| var length = _reader.readUInt30(); |
| unitElement.typeAliases = List.generate(length, (_) { |
| return _readTypeAliasElement(unitElement, unitReference); |
| }); |
| } |
| |
| List<TypeParameterElementImpl> _readTypeParameters() { |
| var length = _reader.readUInt30(); |
| return List.generate(length, (_) { |
| var name = _reader.readStringReference(); |
| var varianceEncoding = _reader.readByte(); |
| var variance = _decodeVariance(varianceEncoding); |
| var element = TypeParameterElementImpl(name, -1); |
| element.variance = variance; |
| return element; |
| }); |
| } |
| |
| CompilationUnitElementImpl _readUnitElement({ |
| required LibraryElementImpl libraryElement, |
| required Source librarySource, |
| required Source unitSource, |
| }) { |
| var resolutionOffset = _baseResolutionOffset + _reader.readUInt30(); |
| |
| var unitElement = CompilationUnitElementImpl( |
| source: unitSource, |
| librarySource: librarySource, |
| lineInfo: LineInfo([0]), |
| ); |
| |
| final unitContainerRef = _reference.getChild('@unit'); |
| final unitReference = unitContainerRef.getChild('${unitSource.uri}'); |
| unitElement.setLinkedData( |
| unitReference, |
| CompilationUnitElementLinkedData( |
| reference: unitReference, |
| libraryReader: this, |
| unitElement: unitElement, |
| offset: resolutionOffset, |
| ), |
| ); |
| |
| unitElement.uri = _reader.readOptionalStringReference(); |
| unitElement.isSynthetic = _reader.readBool(); |
| |
| _readClasses(unitElement, unitReference); |
| _readEnums(unitElement, unitReference); |
| _readExtensions(unitElement, unitReference); |
| _readFunctions(unitElement, unitReference); |
| _readMixins(unitElement, unitReference); |
| _readTypeAliases(unitElement, unitReference); |
| |
| var accessors = <PropertyAccessorElementImpl>[]; |
| var variables = <TopLevelVariableElementImpl>[]; |
| _readTopLevelVariables(unitElement, unitReference, accessors, variables); |
| _readPropertyAccessors(unitElement, unitElement, unitReference, accessors, |
| variables, '@variable'); |
| unitElement.accessors = accessors; |
| unitElement.topLevelVariables = variables; |
| return unitElement; |
| } |
| |
| static Variance? _decodeVariance(int index) { |
| var tag = TypeParameterVarianceTag.values[index]; |
| switch (tag) { |
| case TypeParameterVarianceTag.legacy: |
| return null; |
| case TypeParameterVarianceTag.unrelated: |
| return Variance.unrelated; |
| case TypeParameterVarianceTag.covariant: |
| return Variance.covariant; |
| case TypeParameterVarianceTag.contravariant: |
| return Variance.contravariant; |
| case TypeParameterVarianceTag.invariant: |
| return Variance.invariant; |
| } |
| } |
| } |
| |
| class MethodElementLinkedData extends ElementLinkedData<MethodElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| MethodElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| _addEnclosingElementTypeParameters(reader, element); |
| element.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| _readTypeParameters(reader, element.typeParameters); |
| _readFormalParameters(reader, element.parameters); |
| element.returnType = reader.readRequiredType(); |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| class MixinElementLinkedData extends ElementLinkedData<MixinElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| MixinElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| element.metadata = reader._readAnnotationList( |
| unitElement: element.enclosingElement, |
| ); |
| _readTypeParameters(reader, element.typeParameters); |
| element.superclassConstraints = reader._readInterfaceTypeList(); |
| element.interfaces = reader._readInterfaceTypeList(); |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| class PropertyAccessorElementLinkedData |
| extends ElementLinkedData<PropertyAccessorElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| PropertyAccessorElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| _addEnclosingElementTypeParameters(reader, element); |
| |
| element.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| |
| element.returnType = reader.readRequiredType(); |
| _readFormalParameters(reader, element.parameters); |
| |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| /// Helper for reading elements and types from their binary encoding. |
| class ResolutionReader { |
| final LinkedElementFactory _elementFactory; |
| final _ReferenceReader _referenceReader; |
| final SummaryDataReader _reader; |
| |
| /// The stack of [TypeParameterElement]s and [ParameterElement] that are |
| /// available in the scope of [readElement] and [readType]. |
| /// |
| /// This stack is shared with the client of the reader, and update mostly |
| /// by the client. However it is also updated during [_readFunctionType]. |
| final List<Element> _localElements = []; |
| |
| ResolutionReader( |
| this._elementFactory, |
| this._referenceReader, |
| this._reader, |
| ); |
| |
| LibraryElementImpl libraryOfUri(Uri uri) { |
| return _elementFactory.libraryOfUri2(uri); |
| } |
| |
| int readByte() { |
| return _reader.readByte(); |
| } |
| |
| double readDouble() { |
| return _reader.readDouble(); |
| } |
| |
| Element? readElement() { |
| var memberFlags = _reader.readByte(); |
| var element = _readRawElement(); |
| |
| if (element == null) { |
| return null; |
| } |
| |
| if (memberFlags == Tag.RawElement) { |
| return element; |
| } |
| |
| if (memberFlags == Tag.MemberLegacyWithTypeArguments || |
| memberFlags == Tag.MemberWithTypeArguments) { |
| var arguments = _readTypeList(); |
| // TODO(scheglov) why to check for empty? If we have this flags. |
| if (arguments.isNotEmpty) { |
| var typeParameters = |
| (element.enclosingElement as TypeParameterizedElement) |
| .typeParameters; |
| var substitution = Substitution.fromPairs(typeParameters, arguments); |
| element = |
| ExecutableMember.from2(element as ExecutableElement, substitution); |
| } |
| } |
| |
| if (memberFlags == Tag.MemberLegacyWithTypeArguments) { |
| return Member.legacy(element); |
| } |
| |
| if (memberFlags == Tag.MemberWithTypeArguments) { |
| return element; |
| } |
| |
| throw UnimplementedError('memberFlags: $memberFlags'); |
| } |
| |
| FunctionType? readOptionalFunctionType() { |
| var type = readType(); |
| return type is FunctionType ? type : null; |
| } |
| |
| List<DartType>? readOptionalTypeList() { |
| if (_reader.readBool()) { |
| return _readTypeList(); |
| } else { |
| return null; |
| } |
| } |
| |
| DartType readRequiredType() { |
| return readType()!; |
| } |
| |
| String readStringReference() { |
| return _reader.readStringReference(); |
| } |
| |
| List<String> readStringReferenceList() { |
| return _reader.readStringReferenceList(); |
| } |
| |
| DartType? readType() { |
| var tag = _reader.readByte(); |
| if (tag == Tag.NullType) { |
| return null; |
| } else if (tag == Tag.DynamicType) { |
| var type = DynamicTypeImpl.instance; |
| return _readAliasElementArguments(type); |
| } else if (tag == Tag.FunctionType) { |
| var type = _readFunctionType(); |
| return _readAliasElementArguments(type); |
| } else if (tag == Tag.InterfaceType) { |
| var element = readElement() as ClassElement; |
| var typeArguments = _readTypeList(); |
| var nullability = _readNullability(); |
| var type = InterfaceTypeImpl( |
| element: element, |
| typeArguments: typeArguments, |
| nullabilitySuffix: nullability, |
| ); |
| return _readAliasElementArguments(type); |
| } else if (tag == Tag.InterfaceType_noTypeArguments_none) { |
| var element = readElement() as ClassElement; |
| var type = InterfaceTypeImpl( |
| element: element, |
| typeArguments: const <DartType>[], |
| nullabilitySuffix: NullabilitySuffix.none, |
| ); |
| return _readAliasElementArguments(type); |
| } else if (tag == Tag.InterfaceType_noTypeArguments_question) { |
| var element = readElement() as ClassElement; |
| var type = InterfaceTypeImpl( |
| element: element, |
| typeArguments: const <DartType>[], |
| nullabilitySuffix: NullabilitySuffix.question, |
| ); |
| return _readAliasElementArguments(type); |
| } else if (tag == Tag.InterfaceType_noTypeArguments_star) { |
| var element = readElement() as ClassElement; |
| var type = InterfaceTypeImpl( |
| element: element, |
| typeArguments: const <DartType>[], |
| nullabilitySuffix: NullabilitySuffix.star, |
| ); |
| return _readAliasElementArguments(type); |
| } else if (tag == Tag.NeverType) { |
| var nullability = _readNullability(); |
| var type = NeverTypeImpl.instance.withNullability(nullability); |
| return _readAliasElementArguments(type); |
| } else if (tag == Tag.TypeParameterType) { |
| var element = readElement() as TypeParameterElement; |
| var nullability = _readNullability(); |
| var type = TypeParameterTypeImpl( |
| element: element, |
| nullabilitySuffix: nullability, |
| ); |
| return _readAliasElementArguments(type); |
| } else if (tag == Tag.VoidType) { |
| var type = VoidTypeImpl.instance; |
| return _readAliasElementArguments(type); |
| } else { |
| throw UnimplementedError('$tag'); |
| } |
| } |
| |
| List<T> readTypedList<T>(T Function() read) { |
| var length = readUInt30(); |
| return List<T>.generate(length, (_) { |
| return read(); |
| }); |
| } |
| |
| int readUInt30() { |
| return _reader.readUInt30(); |
| } |
| |
| int readUInt32() { |
| return _reader.readUInt32(); |
| } |
| |
| void _addFormalParameters(List<ParameterElement> parameters) { |
| for (var parameter in parameters) { |
| _localElements.add(parameter); |
| } |
| } |
| |
| void _addTypeParameters(List<TypeParameterElement> typeParameters) { |
| for (var typeParameter in typeParameters) { |
| _localElements.add(typeParameter); |
| } |
| } |
| |
| ElementImpl? _readAliasedElement(CompilationUnitElementImpl unitElement) { |
| var tag = _reader.readByte(); |
| if (tag == AliasedElementTag.nothing) { |
| return null; |
| } else if (tag == AliasedElementTag.genericFunctionElement) { |
| var typeParameters = _readTypeParameters(unitElement); |
| var formalParameters = _readFormalParameters(unitElement); |
| var returnType = readRequiredType(); |
| |
| _localElements.length -= typeParameters.length; |
| |
| return GenericFunctionTypeElementImpl.forOffset(-1) |
| ..typeParameters = typeParameters |
| ..parameters = formalParameters |
| ..returnType = returnType; |
| } else { |
| throw UnimplementedError('tag: $tag'); |
| } |
| } |
| |
| DartType _readAliasElementArguments(DartType type) { |
| var aliasElement = _readRawElement(); |
| if (aliasElement is TypeAliasElement) { |
| var aliasArguments = _readTypeList(); |
| if (type is DynamicType) { |
| // TODO(scheglov) add support for `dynamic` aliasing |
| return type; |
| } else if (type is FunctionType) { |
| return FunctionTypeImpl( |
| typeFormals: type.typeFormals, |
| parameters: type.parameters, |
| returnType: type.returnType, |
| nullabilitySuffix: type.nullabilitySuffix, |
| alias: InstantiatedTypeAliasElementImpl( |
| element: aliasElement, |
| typeArguments: aliasArguments, |
| ), |
| ); |
| } else if (type is InterfaceType) { |
| return InterfaceTypeImpl( |
| element: type.element, |
| typeArguments: type.typeArguments, |
| nullabilitySuffix: type.nullabilitySuffix, |
| alias: InstantiatedTypeAliasElementImpl( |
| element: aliasElement, |
| typeArguments: aliasArguments, |
| ), |
| ); |
| } else if (type is TypeParameterType) { |
| return TypeParameterTypeImpl( |
| element: type.element, |
| nullabilitySuffix: type.nullabilitySuffix, |
| alias: InstantiatedTypeAliasElementImpl( |
| element: aliasElement, |
| typeArguments: aliasArguments, |
| ), |
| ); |
| } else if (type is VoidType) { |
| // TODO(scheglov) add support for `void` aliasing |
| return type; |
| } else { |
| throw UnimplementedError('${type.runtimeType}'); |
| } |
| } |
| return type; |
| } |
| |
| List<ElementAnnotationImpl> _readAnnotationList({ |
| required CompilationUnitElementImpl unitElement, |
| }) { |
| var length = _reader.readUInt30(); |
| if (length == 0) { |
| return const <ElementAnnotationImpl>[]; |
| } |
| return List.generate(length, (_) { |
| var ast = _readRequiredNode() as Annotation; |
| return ElementAnnotationImpl(unitElement) |
| ..annotationAst = ast |
| ..element = ast.element; |
| }); |
| } |
| |
| List<ParameterElementImpl> _readFormalParameters( |
| CompilationUnitElementImpl? unitElement, |
| ) { |
| var formalParameterCount = _reader.readUInt30(); |
| return List.generate(formalParameterCount, (_) { |
| var kindIndex = _reader.readByte(); |
| var kind = _formalParameterKind(kindIndex); |
| var hasImplicitType = _reader.readBool(); |
| var isInitializingFormal = _reader.readBool(); |
| var typeParameters = _readTypeParameters(unitElement); |
| var type = readRequiredType(); |
| var name = readStringReference(); |
| if (kind.isRequiredPositional) { |
| ParameterElementImpl element; |
| if (isInitializingFormal) { |
| element = FieldFormalParameterElementImpl( |
| name: name, |
| nameOffset: -1, |
| parameterKind: kind, |
| )..type = type; |
| } else { |
| element = ParameterElementImpl( |
| name: name, |
| nameOffset: -1, |
| parameterKind: kind, |
| )..type = type; |
| } |
| element.hasImplicitType = hasImplicitType; |
| element.typeParameters = typeParameters; |
| element.parameters = _readFormalParameters(unitElement); |
| // TODO(scheglov) reuse for formal parameters |
| _localElements.length -= typeParameters.length; |
| if (unitElement != null) { |
| element.metadata = _readAnnotationList(unitElement: unitElement); |
| } |
| return element; |
| } else { |
| var element = DefaultParameterElementImpl( |
| name: name, |
| nameOffset: -1, |
| parameterKind: kind, |
| )..type = type; |
| element.hasImplicitType = hasImplicitType; |
| element.typeParameters = typeParameters; |
| element.parameters = _readFormalParameters(unitElement); |
| // TODO(scheglov) reuse for formal parameters |
| _localElements.length -= typeParameters.length; |
| if (unitElement != null) { |
| element.metadata = _readAnnotationList(unitElement: unitElement); |
| } |
| return element; |
| } |
| }); |
| } |
| |
| /// TODO(scheglov) Optimize for write/read of types without type parameters. |
| FunctionType _readFunctionType() { |
| // TODO(scheglov) reuse for formal parameters |
| var typeParameters = _readTypeParameters(null); |
| var returnType = readRequiredType(); |
| var formalParameters = _readFormalParameters(null); |
| |
| var nullability = _readNullability(); |
| |
| _localElements.length -= typeParameters.length; |
| |
| return FunctionTypeImpl( |
| typeFormals: typeParameters, |
| parameters: formalParameters, |
| returnType: returnType, |
| nullabilitySuffix: nullability, |
| ); |
| } |
| |
| InterfaceType _readInterfaceType() { |
| return readType() as InterfaceType; |
| } |
| |
| List<InterfaceType> _readInterfaceTypeList() { |
| var length = _reader.readUInt30(); |
| if (length == 0) { |
| return const <InterfaceType>[]; |
| } |
| return List.generate(length, (_) => _readInterfaceType()); |
| } |
| |
| List<T> _readNodeList<T>() { |
| var length = _reader.readUInt30(); |
| return List<T>.generate(length, (_) { |
| return _readRequiredNode() as T; |
| }); |
| } |
| |
| NullabilitySuffix _readNullability() { |
| var index = _reader.readByte(); |
| return NullabilitySuffix.values[index]; |
| } |
| |
| ExpressionImpl? _readOptionalExpression() { |
| if (_reader.readBool()) { |
| return _readRequiredNode() as ExpressionImpl; |
| } else { |
| return null; |
| } |
| } |
| |
| InterfaceType? _readOptionalInterfaceType() { |
| return readType() as InterfaceType?; |
| } |
| |
| Element? _readRawElement() { |
| var index = _reader.readUInt30(); |
| |
| if ((index & 0x1) == 0x1) { |
| return _localElements[index >> 1]; |
| } |
| |
| var referenceIndex = index >> 1; |
| var reference = _referenceReader.referenceOfIndex(referenceIndex); |
| |
| return _elementFactory.elementOfReference(reference); |
| } |
| |
| AstNode _readRequiredNode() { |
| var astReader = AstBinaryReader(reader: this); |
| return astReader.readNode(); |
| } |
| |
| List<DartType> _readTypeList() { |
| var types = <DartType>[]; |
| var length = _reader.readUInt30(); |
| for (var i = 0; i < length; i++) { |
| var argument = readType()!; |
| types.add(argument); |
| } |
| return types; |
| } |
| |
| List<TypeParameterElementImpl> _readTypeParameters( |
| CompilationUnitElementImpl? unitElement, |
| ) { |
| var typeParameterCount = _reader.readUInt30(); |
| var typeParameters = List.generate(typeParameterCount, (_) { |
| var name = readStringReference(); |
| var typeParameter = TypeParameterElementImpl(name, -1); |
| _localElements.add(typeParameter); |
| return typeParameter; |
| }); |
| |
| for (var typeParameter in typeParameters) { |
| typeParameter.bound = readType(); |
| if (unitElement != null) { |
| typeParameter.metadata = _readAnnotationList(unitElement: unitElement); |
| } |
| } |
| return typeParameters; |
| } |
| |
| static ParameterKind _formalParameterKind(int encoding) { |
| if (encoding == Tag.ParameterKindRequiredPositional) { |
| return ParameterKind.REQUIRED; |
| } else if (encoding == Tag.ParameterKindOptionalPositional) { |
| return ParameterKind.POSITIONAL; |
| } else if (encoding == Tag.ParameterKindRequiredNamed) { |
| return ParameterKind.NAMED_REQUIRED; |
| } else if (encoding == Tag.ParameterKindOptionalNamed) { |
| return ParameterKind.NAMED; |
| } else { |
| throw StateError('Unexpected parameter kind encoding: $encoding'); |
| } |
| } |
| } |
| |
| class TopLevelVariableElementLinkedData |
| extends ElementLinkedData<TopLevelVariableElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| TopLevelVariableElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| element.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| element.type = reader.readRequiredType(); |
| if (element is ConstTopLevelVariableElementImpl) { |
| var initializer = reader._readOptionalExpression(); |
| if (initializer != null) { |
| element.constantInitializer = initializer; |
| ConstantContextForExpressionImpl(initializer); |
| } |
| } |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| class TypeAliasElementLinkedData |
| extends ElementLinkedData<TypeAliasElementImpl> { |
| ApplyConstantOffsets? applyConstantOffsets; |
| |
| TypeAliasElementLinkedData({ |
| required Reference reference, |
| required LibraryReader libraryReader, |
| required CompilationUnitElementImpl unitElement, |
| required int offset, |
| }) : super(reference, libraryReader, unitElement, offset); |
| |
| @override |
| void _read(element, reader) { |
| element.metadata = reader._readAnnotationList( |
| unitElement: unitElement, |
| ); |
| _readTypeParameters(reader, element.typeParameters); |
| element.aliasedElement = reader._readAliasedElement(unitElement); |
| element.aliasedType = reader.readRequiredType(); |
| applyConstantOffsets?.perform(); |
| } |
| } |
| |
| /// Information that we need to know about each library before reading it, |
| /// and without reading it. |
| /// |
| /// Specifically, the [offset] allows us to know the location of each library, |
| /// so that when we need to read this library, we know where it starts without |
| /// reading previous libraries. |
| class _LibraryHeader { |
| final Uri uri; |
| final int offset; |
| |
| /// We don't read class members when reading libraries, by performance |
| /// reasons - in many cases only some classes of a library are used. But |
| /// we need to know how much data to skip for each class. |
| final Uint32List classMembersLengths; |
| |
| _LibraryHeader({ |
| required this.uri, |
| required this.offset, |
| required this.classMembersLengths, |
| }); |
| } |
| |
| class _ReferenceReader { |
| final LinkedElementFactory elementFactory; |
| final SummaryDataReader _reader; |
| late final Uint32List _parents; |
| late final Uint32List _names; |
| late final List<Reference?> _references; |
| |
| _ReferenceReader(this.elementFactory, this._reader, int offset) { |
| _reader.offset = offset; |
| _parents = _reader.readUInt30List(); |
| _names = _reader.readUInt30List(); |
| assert(_parents.length == _names.length); |
| |
| _references = List.filled(_names.length, null); |
| } |
| |
| Reference referenceOfIndex(int index) { |
| var reference = _references[index]; |
| if (reference != null) { |
| return reference; |
| } |
| |
| if (index == 0) { |
| reference = elementFactory.rootReference; |
| _references[index] = reference; |
| return reference; |
| } |
| |
| var nameIndex = _names[index]; |
| var name = _reader.stringOfIndex(nameIndex); |
| |
| var parentIndex = _parents[index]; |
| var parent = referenceOfIndex(parentIndex); |
| |
| reference = parent.getChild(name); |
| _references[index] = reference; |
| |
| return reference; |
| } |
| } |