ba666c8082
Replace the generic mutable reference tree with typed reference classes for roots, libraries, top-level declarations, member containers, members, and built-in elements. The previous API was shallow. It offered a small primitive, `getChild(String)`, but pushed too much knowledge to every caller: which sentinel names exist, which paths are valid for each declaration kind, which references may contain members, and which references are not real declarations at all. That kept the reference implementation simple by spreading its complexity across the analyzer. Make the reference model deeper instead. Callers now ask for the semantic role they need, such as a library, constructor, method, field, or top-level declaration. The reference layer owns the representation, lookup, creation, and serialization details. This concentrates the complexity behind a narrower interface, makes the common cases clearer, and makes invalid reference shapes harder to construct. This is a strategic cleanup rather than a local simplification. The reference graph is used by element construction, summary reading and writing, scopes, exports, and fine-grained dependency manifests. Giving it explicit concepts reduces the amount of convention each subsystem must remember and preserves a simpler mental model at the call sites. Update summary serialization to write semantic reference rows with a tag, enclosing reference, kind, key, and URI payload. Bump the analyzer data version because this changes the linked summary format. Represent exported declarations as export entries that carry the exported name, reference, and export locations. Use those entries when building scopes, filtering deprecated exports, and updating fine-grained library manifests. Keep import prefixes out of the declaration reference tree. Bind prefix fragments through fragment-local ids so prefixes can be restored and merged without fabricating declaration references. Bug: https://github.com/dart-lang/sdk/issues/63227 Change-Id: If28f8b779faa78bdf023bc69b714555fae57ccb3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/497621 Reviewed-by: Johnni Winther <johnniwinther@google.com> Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
920 lines
26 KiB
Dart
920 lines
26 KiB
Dart
// Copyright (c) 2019, 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/src/binary/binary_reader.dart';
|
|
import 'package:analyzer/src/binary/binary_writer.dart';
|
|
import 'package:analyzer/src/dart/element/element.dart';
|
|
import 'package:analyzer/src/utilities/uri_cache.dart';
|
|
|
|
final class BuiltInReference extends Reference implements ExportableReference {
|
|
final LibraryReference library;
|
|
|
|
final _BuiltInReferenceKind _kind;
|
|
|
|
BuiltInReference._({
|
|
required this.library,
|
|
required _BuiltInReferenceKind kind,
|
|
}) : _kind = kind,
|
|
super._();
|
|
}
|
|
|
|
sealed class DeclarationReference extends Reference {
|
|
/// The stable identity component for this declaration under its enclosing
|
|
/// reference.
|
|
///
|
|
/// This key is internal to reference identity. It is not necessarily the
|
|
/// user-visible name written in source, because unnamed and duplicate
|
|
/// declarations receive generated keys.
|
|
final String _key;
|
|
|
|
DeclarationReference._({required String key}) : _key = key, super._();
|
|
}
|
|
|
|
sealed class ExportableReference implements Reference {}
|
|
|
|
final class LeafTopLevelReference extends TopLevelReference {
|
|
LeafTopLevelReference._({
|
|
required super.library,
|
|
required super.key,
|
|
required super.kind,
|
|
}) : super._();
|
|
}
|
|
|
|
final class LibraryReference extends Reference {
|
|
final String uriString;
|
|
|
|
final List<Map<String, TopLevelReference>?> _topLevelsByKind = List.filled(
|
|
_TopLevelReferenceKind.values.length,
|
|
null,
|
|
);
|
|
List<BuiltInReference?>? _builtInByKind;
|
|
|
|
LibraryReference._({required this.uriString}) : super._();
|
|
|
|
@override
|
|
List<Reference> get children => [
|
|
for (var byKey in _topLevelsByKind) ...?byKey?.values,
|
|
if (_builtInByKind case var builtInByKind?)
|
|
for (var builtIn in builtInByKind) ?builtIn,
|
|
];
|
|
|
|
BuiltInReference get dynamicRef {
|
|
assert(uriString == 'dart:core');
|
|
return _builtIn(_BuiltInReferenceKind.dynamic_);
|
|
}
|
|
|
|
BuiltInReference get neverRef {
|
|
assert(uriString == 'dart:core');
|
|
return _builtIn(_BuiltInReferenceKind.never_);
|
|
}
|
|
|
|
Uri get uri => uriCache.parse(uriString);
|
|
|
|
MemberContainerReference declareClass(String key) {
|
|
return _declareMemberContainer(
|
|
kind: _TopLevelReferenceKind.class_,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
MemberContainerReference declareEnum(String key) {
|
|
return _declareMemberContainer(
|
|
kind: _TopLevelReferenceKind.enum_,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
MemberContainerReference declareExtension(String key) {
|
|
return _declareMemberContainer(
|
|
kind: _TopLevelReferenceKind.extension_,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
MemberContainerReference declareExtensionType(String key) {
|
|
return _declareMemberContainer(
|
|
kind: _TopLevelReferenceKind.extensionType,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
TopLevelReference declareGetter(String key) {
|
|
return _declareTopLevel(kind: _TopLevelReferenceKind.getter, key: key);
|
|
}
|
|
|
|
MemberContainerReference declareMixin(String key) {
|
|
return _declareMemberContainer(
|
|
kind: _TopLevelReferenceKind.mixin_,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
TopLevelReference declareSetter(String key) {
|
|
return _declareTopLevel(kind: _TopLevelReferenceKind.setter, key: key);
|
|
}
|
|
|
|
TopLevelReference declareTopLevelFunction(String key) {
|
|
return _declareTopLevel(kind: _TopLevelReferenceKind.function, key: key);
|
|
}
|
|
|
|
TopLevelReference declareTopLevelVariable(String key) {
|
|
return _declareTopLevel(
|
|
kind: _TopLevelReferenceKind.topLevelVariable,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
TopLevelReference declareTypeAlias(String key) {
|
|
return _declareTopLevel(kind: _TopLevelReferenceKind.typeAlias, key: key);
|
|
}
|
|
|
|
MemberContainerReference getOrCreateClass(String key) {
|
|
return _getOrCreateMemberContainer(
|
|
kind: _TopLevelReferenceKind.class_,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
MemberContainerReference getOrCreateEnum(String key) {
|
|
return _getOrCreateMemberContainer(
|
|
kind: _TopLevelReferenceKind.enum_,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
MemberContainerReference getOrCreateExtension(String key) {
|
|
return _getOrCreateMemberContainer(
|
|
kind: _TopLevelReferenceKind.extension_,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
MemberContainerReference getOrCreateExtensionType(String key) {
|
|
return _getOrCreateMemberContainer(
|
|
kind: _TopLevelReferenceKind.extensionType,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
TopLevelReference getOrCreateGetter(String key) {
|
|
return _getOrCreateTopLevel(kind: _TopLevelReferenceKind.getter, key: key);
|
|
}
|
|
|
|
MemberContainerReference getOrCreateMixin(String key) {
|
|
return _getOrCreateMemberContainer(
|
|
kind: _TopLevelReferenceKind.mixin_,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
TopLevelReference getOrCreateSetter(String key) {
|
|
return _getOrCreateTopLevel(kind: _TopLevelReferenceKind.setter, key: key);
|
|
}
|
|
|
|
TopLevelReference getOrCreateTopLevelFunction(String key) {
|
|
return _getOrCreateTopLevel(
|
|
kind: _TopLevelReferenceKind.function,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
TopLevelReference getOrCreateTopLevelVariable(String key) {
|
|
return _getOrCreateTopLevel(
|
|
kind: _TopLevelReferenceKind.topLevelVariable,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
TopLevelReference getOrCreateTypeAlias(String key) {
|
|
return _getOrCreateTopLevel(
|
|
kind: _TopLevelReferenceKind.typeAlias,
|
|
key: key,
|
|
);
|
|
}
|
|
|
|
BuiltInReference _builtIn(_BuiltInReferenceKind kind) {
|
|
var builtInByKind = _builtInByKind ??= List.filled(
|
|
_BuiltInReferenceKind.values.length,
|
|
null,
|
|
);
|
|
return builtInByKind[kind.index] ??= BuiltInReference._(
|
|
library: this,
|
|
kind: kind,
|
|
);
|
|
}
|
|
|
|
TopLevelReference _createTopLevelReference(
|
|
_TopLevelReferenceKind kind,
|
|
String key,
|
|
) {
|
|
if (kind.hasMembers) {
|
|
return MemberContainerReference._(library: this, key: key, kind: kind);
|
|
}
|
|
return LeafTopLevelReference._(library: this, key: key, kind: kind);
|
|
}
|
|
|
|
MemberContainerReference _declareMemberContainer({
|
|
required _TopLevelReferenceKind kind,
|
|
required String key,
|
|
}) {
|
|
var byKey = _topLevelByKey(kind);
|
|
if (byKey[key] != null) {
|
|
throw StateError('Duplicate reference key: $key');
|
|
}
|
|
|
|
return byKey[key] = MemberContainerReference._(
|
|
library: this,
|
|
key: key,
|
|
kind: kind,
|
|
);
|
|
}
|
|
|
|
TopLevelReference _declareTopLevel({
|
|
required _TopLevelReferenceKind kind,
|
|
required String key,
|
|
}) {
|
|
return Reference._declare(
|
|
byKey: _topLevelByKey(kind),
|
|
key: key,
|
|
create: (key) => _createTopLevelReference(kind, key),
|
|
);
|
|
}
|
|
|
|
MemberContainerReference _getOrCreateMemberContainer({
|
|
required _TopLevelReferenceKind kind,
|
|
required String key,
|
|
}) {
|
|
var byKey = _topLevelByKey(kind);
|
|
if (byKey[key] case MemberContainerReference existing) {
|
|
return existing;
|
|
}
|
|
|
|
var result = MemberContainerReference._(
|
|
library: this,
|
|
key: key,
|
|
kind: kind,
|
|
);
|
|
byKey[key] = result;
|
|
return result;
|
|
}
|
|
|
|
TopLevelReference _getOrCreateTopLevel({
|
|
required _TopLevelReferenceKind kind,
|
|
required String key,
|
|
}) {
|
|
return _topLevelByKey(kind)[key] ??= _createTopLevelReference(kind, key);
|
|
}
|
|
|
|
Map<String, TopLevelReference> _topLevelByKey(_TopLevelReferenceKind kind) {
|
|
return _topLevelsByKind[kind.index] ??= {};
|
|
}
|
|
}
|
|
|
|
final class LibraryReferenceBuilder {
|
|
final LibraryReference reference;
|
|
final Map<Reference, _KeyAllocator> _keyAllocatorByReference = Map.identity();
|
|
|
|
LibraryReferenceBuilder(this.reference);
|
|
|
|
MemberContainerReference declareClass(String? name) {
|
|
return reference.declareClass(
|
|
_allocateTopLevelKey(kind: _TopLevelReferenceKind.class_, name: name),
|
|
);
|
|
}
|
|
|
|
MemberContainerReference declareEnum(String? name) {
|
|
return reference.declareEnum(
|
|
_allocateTopLevelKey(kind: _TopLevelReferenceKind.enum_, name: name),
|
|
);
|
|
}
|
|
|
|
MemberContainerReference declareExtension(String? name) {
|
|
return reference.declareExtension(
|
|
_allocateTopLevelKey(kind: _TopLevelReferenceKind.extension_, name: name),
|
|
);
|
|
}
|
|
|
|
MemberContainerReference declareExtensionType(String? name) {
|
|
return reference.declareExtensionType(
|
|
_allocateTopLevelKey(
|
|
kind: _TopLevelReferenceKind.extensionType,
|
|
name: name,
|
|
),
|
|
);
|
|
}
|
|
|
|
TopLevelReference declareGetter(String? name) {
|
|
return reference.declareGetter(
|
|
_allocateTopLevelKey(kind: _TopLevelReferenceKind.getter, name: name),
|
|
);
|
|
}
|
|
|
|
MemberReference declareMemberConstructor({
|
|
required MemberContainerReference container,
|
|
required String? name,
|
|
}) {
|
|
return container.declareConstructor(
|
|
_allocateMemberKey(
|
|
container: container,
|
|
kind: _MemberReferenceKind.constructor,
|
|
name: name,
|
|
),
|
|
);
|
|
}
|
|
|
|
MemberReference declareMemberField({
|
|
required MemberContainerReference container,
|
|
required String? name,
|
|
}) {
|
|
return container.declareField(
|
|
_allocateMemberKey(
|
|
container: container,
|
|
kind: _MemberReferenceKind.field,
|
|
name: name,
|
|
),
|
|
);
|
|
}
|
|
|
|
MemberReference declareMemberGetter({
|
|
required MemberContainerReference container,
|
|
required String? name,
|
|
}) {
|
|
return container.declareGetter(
|
|
_allocateMemberKey(
|
|
container: container,
|
|
kind: _MemberReferenceKind.getter,
|
|
name: name,
|
|
),
|
|
);
|
|
}
|
|
|
|
MemberReference declareMemberMethod({
|
|
required MemberContainerReference container,
|
|
required String? name,
|
|
}) {
|
|
return container.declareMethod(
|
|
_allocateMemberKey(
|
|
container: container,
|
|
kind: _MemberReferenceKind.method,
|
|
name: name,
|
|
),
|
|
);
|
|
}
|
|
|
|
MemberReference declareMemberSetter({
|
|
required MemberContainerReference container,
|
|
required String? name,
|
|
}) {
|
|
return container.declareSetter(
|
|
_allocateMemberKey(
|
|
container: container,
|
|
kind: _MemberReferenceKind.setter,
|
|
name: name,
|
|
),
|
|
);
|
|
}
|
|
|
|
MemberContainerReference declareMixin(String? name) {
|
|
return reference.declareMixin(
|
|
_allocateTopLevelKey(kind: _TopLevelReferenceKind.mixin_, name: name),
|
|
);
|
|
}
|
|
|
|
TopLevelReference declareSetter(String? name) {
|
|
return reference.declareSetter(
|
|
_allocateTopLevelKey(kind: _TopLevelReferenceKind.setter, name: name),
|
|
);
|
|
}
|
|
|
|
TopLevelReference declareTopLevelFunction(String? name) {
|
|
return reference.declareTopLevelFunction(
|
|
_allocateTopLevelKey(kind: _TopLevelReferenceKind.function, name: name),
|
|
);
|
|
}
|
|
|
|
TopLevelReference declareTopLevelVariable(String? name) {
|
|
return reference.declareTopLevelVariable(
|
|
_allocateTopLevelKey(
|
|
kind: _TopLevelReferenceKind.topLevelVariable,
|
|
name: name,
|
|
),
|
|
);
|
|
}
|
|
|
|
TopLevelReference declareTypeAlias(String? name) {
|
|
return reference.declareTypeAlias(
|
|
_allocateTopLevelKey(kind: _TopLevelReferenceKind.typeAlias, name: name),
|
|
);
|
|
}
|
|
|
|
String _allocateMemberKey({
|
|
required MemberContainerReference container,
|
|
required _MemberReferenceKind kind,
|
|
required String? name,
|
|
}) {
|
|
return (_keyAllocatorByReference[container] ??= _KeyAllocator(
|
|
kindCount: _MemberReferenceKind.values.length,
|
|
)).allocate(kindIndex: kind.index, name: name);
|
|
}
|
|
|
|
String _allocateTopLevelKey({
|
|
required _TopLevelReferenceKind kind,
|
|
required String? name,
|
|
}) {
|
|
return (_keyAllocatorByReference[reference] ??= _KeyAllocator(
|
|
kindCount: _TopLevelReferenceKind.values.length,
|
|
)).allocate(kindIndex: kind.index, name: name);
|
|
}
|
|
}
|
|
|
|
final class MemberContainerReference extends TopLevelReference {
|
|
final List<Map<String, MemberReference>?> _membersByKind = List.filled(
|
|
_MemberReferenceKind.values.length,
|
|
null,
|
|
);
|
|
|
|
MemberContainerReference._({
|
|
required super.library,
|
|
required super.key,
|
|
required super.kind,
|
|
}) : super._();
|
|
|
|
@override
|
|
List<Reference> get children => [
|
|
for (var byKey in _membersByKind) ...?byKey?.values,
|
|
];
|
|
|
|
MemberReference declareConstructor(String key) {
|
|
return _declareMember(kind: _MemberReferenceKind.constructor, key: key);
|
|
}
|
|
|
|
MemberReference declareField(String key) {
|
|
return _declareMember(kind: _MemberReferenceKind.field, key: key);
|
|
}
|
|
|
|
MemberReference declareGetter(String key) {
|
|
return _declareMember(kind: _MemberReferenceKind.getter, key: key);
|
|
}
|
|
|
|
MemberReference declareMethod(String key) {
|
|
return _declareMember(kind: _MemberReferenceKind.method, key: key);
|
|
}
|
|
|
|
MemberReference declareSetter(String key) {
|
|
return _declareMember(kind: _MemberReferenceKind.setter, key: key);
|
|
}
|
|
|
|
MemberReference getOrCreateConstructor(String key) {
|
|
return _getOrCreateMember(kind: _MemberReferenceKind.constructor, key: key);
|
|
}
|
|
|
|
MemberReference getOrCreateField(String key) {
|
|
return _getOrCreateMember(kind: _MemberReferenceKind.field, key: key);
|
|
}
|
|
|
|
MemberReference getOrCreateGetter(String key) {
|
|
return _getOrCreateMember(kind: _MemberReferenceKind.getter, key: key);
|
|
}
|
|
|
|
MemberReference getOrCreateMethod(String key) {
|
|
return _getOrCreateMember(kind: _MemberReferenceKind.method, key: key);
|
|
}
|
|
|
|
MemberReference getOrCreateSetter(String key) {
|
|
return _getOrCreateMember(kind: _MemberReferenceKind.setter, key: key);
|
|
}
|
|
|
|
MemberReference _declareMember({
|
|
required _MemberReferenceKind kind,
|
|
required String key,
|
|
}) {
|
|
return Reference._declare(
|
|
byKey: _memberByKey(kind),
|
|
key: key,
|
|
create: (key) => MemberReference._(container: this, key: key, kind: kind),
|
|
);
|
|
}
|
|
|
|
MemberReference _getOrCreateMember({
|
|
required _MemberReferenceKind kind,
|
|
required String key,
|
|
}) {
|
|
return _memberByKey(kind)[key] ??= MemberReference._(
|
|
container: this,
|
|
key: key,
|
|
kind: kind,
|
|
);
|
|
}
|
|
|
|
Map<String, MemberReference> _memberByKey(_MemberReferenceKind kind) {
|
|
return _membersByKind[kind.index] ??= {};
|
|
}
|
|
}
|
|
|
|
final class MemberReference extends DeclarationReference {
|
|
final MemberContainerReference container;
|
|
final _MemberReferenceKind _kind;
|
|
|
|
MemberReference._({
|
|
required this.container,
|
|
required super.key,
|
|
required _MemberReferenceKind kind,
|
|
}) : _kind = kind,
|
|
super._();
|
|
}
|
|
|
|
/// A canonical identity node for an analyzer element.
|
|
///
|
|
/// References are the lightweight tree that summary reading and writing use to
|
|
/// name elements without requiring the corresponding [ElementImpl] to be built
|
|
/// yet. When an element is materialized, [element] is filled in with that
|
|
/// implementation object.
|
|
///
|
|
/// The tree shape is intentionally small:
|
|
///
|
|
/// - [RootReference] owns libraries.
|
|
/// - [LibraryReference] owns top-level declarations and `dart:core` built-ins.
|
|
/// - [MemberContainerReference] owns members of classes, enums, mixins,
|
|
/// extensions, and extension types.
|
|
/// - [LeafTopLevelReference], [MemberReference], and [BuiltInReference] have no
|
|
/// children.
|
|
///
|
|
/// Declaration references are identified under their enclosing reference by
|
|
/// kind and by an internal key. The key is not always the source name;
|
|
/// generated keys are used for unnamed declarations and duplicate source names.
|
|
sealed class Reference {
|
|
/// The corresponding [ElementImpl], or `null` if not created yet.
|
|
ElementImpl? element;
|
|
|
|
Reference._();
|
|
|
|
List<Reference> get children => const [];
|
|
|
|
/// The reference that must be materialized before this reference, or `null`
|
|
/// if this reference can be materialized directly.
|
|
Reference? get enclosingReference {
|
|
return switch (this) {
|
|
TopLevelReference(:var library) => library,
|
|
MemberReference(:var container) => container,
|
|
BuiltInReference(:var library) => library,
|
|
_ => null,
|
|
};
|
|
}
|
|
|
|
String debugString({String Function(String uriString)? formatLibraryUri}) {
|
|
String recurse(Reference reference) {
|
|
return reference.debugString(formatLibraryUri: formatLibraryUri);
|
|
}
|
|
|
|
switch (this) {
|
|
case RootReference():
|
|
return 'root';
|
|
case LibraryReference ref:
|
|
return formatLibraryUri?.call(ref.uriString) ?? ref.uriString;
|
|
case TopLevelReference ref:
|
|
var libraryStr = recurse(ref.library);
|
|
var kindStr = ref._kind.debugName;
|
|
return '$libraryStr::$kindStr::${ref._key}';
|
|
case MemberReference ref:
|
|
var containerStr = recurse(ref.container);
|
|
var kindStr = ref._kind.debugName;
|
|
return '$containerStr::$kindStr::${ref._key}';
|
|
case BuiltInReference ref:
|
|
var libraryStr = recurse(ref.library);
|
|
return '$libraryStr::${ref._kind.identifier}';
|
|
}
|
|
}
|
|
|
|
@override
|
|
String toString() => debugString();
|
|
|
|
static T _declare<T extends Reference>({
|
|
required Map<String, T> byKey,
|
|
required String key,
|
|
required T Function(String key) create,
|
|
}) {
|
|
if (byKey[key] != null) {
|
|
throw StateError('Duplicate reference key: $key');
|
|
}
|
|
return byKey[key] = create(key);
|
|
}
|
|
}
|
|
|
|
final class ReferenceTableReader {
|
|
final String Function(int index) _stringOfIndex;
|
|
final RootReference _rootReference;
|
|
late final Uint8List _tagIndexes;
|
|
late final Uint32List _parentIndexes;
|
|
late final Uint8List _kindIndexes;
|
|
late final Uint32List _keyStringIndexes;
|
|
late final Uint32List _uriStringIndexes;
|
|
late final List<Reference?> _referenceByIndex;
|
|
|
|
ReferenceTableReader({
|
|
required BinaryReader reader,
|
|
required RootReference rootReference,
|
|
}) : _stringOfIndex = reader.stringOfIndex,
|
|
_rootReference = rootReference {
|
|
_tagIndexes = reader.readUint8List();
|
|
_parentIndexes = reader.readUint30List();
|
|
_kindIndexes = reader.readUint8List();
|
|
_keyStringIndexes = reader.readUint30List();
|
|
_uriStringIndexes = reader.readUint30List();
|
|
assert(_tagIndexes.length == _parentIndexes.length);
|
|
assert(_tagIndexes.length == _kindIndexes.length);
|
|
assert(_tagIndexes.length == _keyStringIndexes.length);
|
|
assert(_tagIndexes.length == _uriStringIndexes.length);
|
|
|
|
_referenceByIndex = List.filled(_tagIndexes.length, null);
|
|
_referenceByIndex[0] = _rootReference;
|
|
}
|
|
|
|
DeclarationReference readDeclarationReference(BinaryReader reader) {
|
|
var index = reader.readUint30();
|
|
return _referenceOfIndex(index) as DeclarationReference;
|
|
}
|
|
|
|
ExportableReference readExportableReference(BinaryReader reader) {
|
|
var index = reader.readUint30();
|
|
return _referenceOfIndex(index) as ExportableReference;
|
|
}
|
|
|
|
LibraryReference readLibraryReference(BinaryReader reader) {
|
|
var index = reader.readUint30();
|
|
return _referenceOfIndex(index) as LibraryReference;
|
|
}
|
|
|
|
MemberContainerReference readMemberContainerReference(BinaryReader reader) {
|
|
var index = reader.readUint30();
|
|
return _referenceOfIndex(index) as MemberContainerReference;
|
|
}
|
|
|
|
MemberReference readMemberReference(BinaryReader reader) {
|
|
var index = reader.readUint30();
|
|
return _referenceOfIndex(index) as MemberReference;
|
|
}
|
|
|
|
Reference readReference(BinaryReader reader) {
|
|
var index = reader.readUint30();
|
|
return _referenceOfIndex(index);
|
|
}
|
|
|
|
TopLevelReference readTopLevelReference(BinaryReader reader) {
|
|
var index = reader.readUint30();
|
|
return _referenceOfIndex(index) as TopLevelReference;
|
|
}
|
|
|
|
LibraryReference _libraryReferenceOfIndex(int index) {
|
|
return _referenceOfIndex(index) as LibraryReference;
|
|
}
|
|
|
|
MemberContainerReference _memberContainerReferenceOfIndex(int index) {
|
|
return _referenceOfIndex(index) as MemberContainerReference;
|
|
}
|
|
|
|
Reference _referenceOfIndex(int index) {
|
|
var reference = _referenceByIndex[index];
|
|
if (reference != null) {
|
|
return reference;
|
|
}
|
|
|
|
var tag = _SerializedReferenceTag.values[_tagIndexes[index]];
|
|
switch (tag) {
|
|
case _SerializedReferenceTag.root:
|
|
reference = _rootReference;
|
|
case _SerializedReferenceTag.library:
|
|
var uriString = _stringOfIndex(_uriStringIndexes[index]);
|
|
reference = _rootReference.getOrCreateLibrary(
|
|
uriCache.parse(uriString),
|
|
);
|
|
case _SerializedReferenceTag.topLevel:
|
|
var library = _libraryReferenceOfIndex(_parentIndexes[index]);
|
|
var kind = _TopLevelReferenceKind.values[_kindIndexes[index]];
|
|
var key = _stringOfIndex(_keyStringIndexes[index]);
|
|
reference = library._getOrCreateTopLevel(kind: kind, key: key);
|
|
case _SerializedReferenceTag.member:
|
|
var container = _memberContainerReferenceOfIndex(_parentIndexes[index]);
|
|
reference = container._getOrCreateMember(
|
|
kind: _MemberReferenceKind.values[_kindIndexes[index]],
|
|
key: _stringOfIndex(_keyStringIndexes[index]),
|
|
);
|
|
case _SerializedReferenceTag.builtIn:
|
|
var library = _libraryReferenceOfIndex(_parentIndexes[index]);
|
|
var kind = _BuiltInReferenceKind.values[_kindIndexes[index]];
|
|
reference = library._builtIn(kind);
|
|
}
|
|
_referenceByIndex[index] = reference;
|
|
|
|
return reference;
|
|
}
|
|
}
|
|
|
|
final class ReferenceTableWriter {
|
|
static const int _rootIndex = 0;
|
|
|
|
final Map<Reference, int> _indexByReference = Map.identity();
|
|
|
|
final List<int> _tagIndexes = [];
|
|
final List<int> _parentIndexes = [];
|
|
final List<int> _kindIndexes = [];
|
|
final List<String> _keyStrings = [];
|
|
final List<String> _uriStrings = [];
|
|
|
|
ReferenceTableWriter() {
|
|
_appendRow(
|
|
reference: null,
|
|
tag: _SerializedReferenceTag.root,
|
|
parentIndex: _rootIndex,
|
|
kindIndex: 0,
|
|
key: '',
|
|
uriString: '',
|
|
);
|
|
}
|
|
|
|
void write(BinaryWriter sink) {
|
|
sink.writeUint8List(Uint8List.fromList(_tagIndexes));
|
|
sink.writeUint30List(_parentIndexes);
|
|
sink.writeUint8List(Uint8List.fromList(_kindIndexes));
|
|
sink.writeStringList(_keyStrings);
|
|
sink.writeStringList(_uriStrings);
|
|
}
|
|
|
|
void writeReference(BinaryWriter sink, Reference reference) {
|
|
var index = _indexOfReference(reference);
|
|
sink.writeUint30(index);
|
|
}
|
|
|
|
int _appendRow({
|
|
required Reference? reference,
|
|
required _SerializedReferenceTag tag,
|
|
required int parentIndex,
|
|
required int kindIndex,
|
|
required String key,
|
|
required String uriString,
|
|
}) {
|
|
assert(tag.index <= 0xFF);
|
|
assert(kindIndex <= 0xFF);
|
|
var index = _tagIndexes.length;
|
|
_tagIndexes.add(tag.index);
|
|
_parentIndexes.add(parentIndex);
|
|
_kindIndexes.add(kindIndex);
|
|
_keyStrings.add(key);
|
|
_uriStrings.add(uriString);
|
|
if (reference != null) {
|
|
_indexByReference[reference] = index;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
int _indexOfReference(Reference reference) {
|
|
var index = _indexByReference[reference];
|
|
if (index != null) return index;
|
|
|
|
switch (reference) {
|
|
case RootReference():
|
|
return _rootIndex;
|
|
case LibraryReference():
|
|
return _appendRow(
|
|
reference: reference,
|
|
tag: _SerializedReferenceTag.library,
|
|
parentIndex: _rootIndex,
|
|
kindIndex: 0,
|
|
key: '',
|
|
uriString: reference.uriString,
|
|
);
|
|
case TopLevelReference():
|
|
return _appendRow(
|
|
reference: reference,
|
|
tag: _SerializedReferenceTag.topLevel,
|
|
parentIndex: _indexOfReference(reference.library),
|
|
kindIndex: reference._kind.index,
|
|
key: reference._key,
|
|
uriString: '',
|
|
);
|
|
case MemberReference():
|
|
return _appendRow(
|
|
reference: reference,
|
|
tag: _SerializedReferenceTag.member,
|
|
parentIndex: _indexOfReference(reference.container),
|
|
kindIndex: reference._kind.index,
|
|
key: reference._key,
|
|
uriString: '',
|
|
);
|
|
case BuiltInReference():
|
|
return _appendRow(
|
|
reference: reference,
|
|
tag: _SerializedReferenceTag.builtIn,
|
|
parentIndex: _indexOfReference(reference.library),
|
|
kindIndex: reference._kind.index,
|
|
key: '',
|
|
uriString: '',
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
final class RootReference extends Reference {
|
|
final Map<String, LibraryReference> _libraries = {};
|
|
|
|
RootReference() : super._();
|
|
|
|
@override
|
|
List<LibraryReference> get children => [..._libraries.values];
|
|
|
|
LibraryReference getOrCreateLibrary(Uri uri) {
|
|
var uriString = '$uri';
|
|
return _libraries[uriString] ??= LibraryReference._(uriString: uriString);
|
|
}
|
|
|
|
LibraryReference? libraryIfExists(Uri uri) {
|
|
var uriString = '$uri';
|
|
return _libraries[uriString];
|
|
}
|
|
|
|
LibraryReference? removeLibrary(Uri uri) {
|
|
var uriString = '$uri';
|
|
return _libraries.remove(uriString);
|
|
}
|
|
}
|
|
|
|
sealed class TopLevelReference extends DeclarationReference
|
|
implements ExportableReference {
|
|
final LibraryReference library;
|
|
final _TopLevelReferenceKind _kind;
|
|
|
|
TopLevelReference._({
|
|
required this.library,
|
|
required super.key,
|
|
required _TopLevelReferenceKind kind,
|
|
}) : _kind = kind,
|
|
super._();
|
|
}
|
|
|
|
enum _BuiltInReferenceKind {
|
|
dynamic_('dynamic'),
|
|
never_('Never');
|
|
|
|
final String identifier;
|
|
|
|
const _BuiltInReferenceKind(this.identifier);
|
|
}
|
|
|
|
final class _KeyAllocator {
|
|
final List<Map<String, int>?> _nextDuplicateIndexByKind;
|
|
int _nextUnnamedIndex = 0;
|
|
|
|
_KeyAllocator({required int kindCount})
|
|
: _nextDuplicateIndexByKind = List.filled(kindCount, null);
|
|
|
|
String allocate({required int kindIndex, required String? name}) {
|
|
var baseName = name ?? _unnamedName(_nextUnnamedIndex++);
|
|
var byBaseName = _nextDuplicateIndexByKind[kindIndex] ??= {};
|
|
var duplicateIndex = byBaseName[baseName] ?? 0;
|
|
byBaseName[baseName] = duplicateIndex + 1;
|
|
|
|
if (duplicateIndex == 0) {
|
|
return baseName;
|
|
}
|
|
return _duplicateName(baseName, duplicateIndex);
|
|
}
|
|
|
|
String _duplicateName(String baseName, int index) => '$baseName#$index';
|
|
|
|
String _unnamedName(int index) => '#$index';
|
|
}
|
|
|
|
enum _MemberReferenceKind {
|
|
constructor('@constructor'),
|
|
field('@field'),
|
|
getter('@getter'),
|
|
setter('@setter'),
|
|
method('@method');
|
|
|
|
final String debugName;
|
|
|
|
const _MemberReferenceKind(this.debugName);
|
|
}
|
|
|
|
enum _SerializedReferenceTag { root, library, topLevel, member, builtIn }
|
|
|
|
enum _TopLevelReferenceKind {
|
|
class_('@class', hasMembers: true),
|
|
enum_('@enum', hasMembers: true),
|
|
extension_('@extension', hasMembers: true),
|
|
extensionType('@extensionType', hasMembers: true),
|
|
mixin_('@mixin', hasMembers: true),
|
|
typeAlias('@typeAlias'),
|
|
function('@function'),
|
|
getter('@getter'),
|
|
setter('@setter'),
|
|
topLevelVariable('@topLevelVariable');
|
|
|
|
final String debugName;
|
|
final bool hasMembers;
|
|
|
|
const _TopLevelReferenceKind(this.debugName, {this.hasMembers = false});
|
|
}
|