blob: 00c74bbde2a3b7a79e67c619335bb58bcd8bdec6 [file] [log] [blame]
// Copyright (c) 2018, 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 'package:kernel/ast.dart' as ir;
import 'node_indexer.dart';
/// Helper for looking up object library data from an [ir.Component] node.
class ComponentLookup {
final ir.Component _component;
/// Cache of [LibraryData] for libraries in [_component].
late final Map<Uri, LibraryData> _libraryMap = _initializeLibraryMap();
ComponentLookup(this._component);
Map<Uri, LibraryData> _initializeLibraryMap() {
final libraryMap = <Uri, LibraryData>{};
for (ir.Library library in _component.libraries) {
libraryMap[library.importUri] = LibraryData(library);
}
return libraryMap;
}
/// Returns the [LibraryData] object for the library with the [canonicalUri].
LibraryData getLibraryDataByUri(Uri canonicalUri) {
return _libraryMap[canonicalUri]!;
}
}
/// Returns a name uniquely identifying a member within its enclosing library
/// or class.
String computeMemberName(ir.Member member) {
// This should mostly be empty except when serializing the name of nSM
// forwarders (see dartbug.com/33732).
String libraryPrefix = member.name.isPrivate &&
member.name.libraryName != member.enclosingLibrary.reference
? '${member.name.libraryName?.canonicalName?.name}:'
: '';
String name = member.name.text;
if (member is ir.Constructor) {
name = '.$name';
} else if (member is ir.Procedure) {
if (member.kind == ir.ProcedureKind.Factory) {
name = '.$name';
} else if (member.kind == ir.ProcedureKind.Setter) {
name += "=";
}
}
return '${libraryPrefix}${name}';
}
/// Helper for looking up classes and members from an [ir.Library] node.
class LibraryData {
/// The [ir.Library] that defines the library.
final ir.Library node;
/// Cache of [ClassData] for classes in this library.
Map<String, ClassData>? _classesByName;
Map<ir.Class, ClassData>? _classesByNode;
/// Cache of [ir.Typedef] nodes for typedefs in this library.
late final Map<String, ir.Typedef> _typedefs = _initializeTypedefs();
/// Cache of [MemberData] for members in this library.
Map<String, MemberData>? _membersByName;
Map<ir.Member, MemberData>? _membersByNode;
LibraryData(this.node);
Map<String, ir.Typedef> _initializeTypedefs() {
final typedefs = <String, ir.Typedef>{};
for (ir.Typedef typedef in node.typedefs) {
assert(
!typedefs.containsKey(typedef.name),
"Duplicate typedef '${typedef.name}' in $typedefs "
"trying to add $typedef.");
typedefs[typedef.name] = typedef;
}
return typedefs;
}
void _ensureClasses() {
if (_classesByName == null) {
final classesByName = _classesByName = {};
final classesByNode = _classesByNode = {};
for (ir.Class cls in node.classes) {
assert(
!classesByName.containsKey(cls.name),
"Duplicate class '${cls.name}' in $classesByName "
"trying to add $cls.");
assert(
!classesByNode.containsKey(cls),
"Duplicate class '${cls.name}' in $classesByNode "
"trying to add $cls.");
classesByNode[cls] = classesByName[cls.name] = ClassData(cls);
}
}
}
/// Returns the [ClassData] for the class [name] in this library.
ClassData? lookupClassByName(String name) {
_ensureClasses();
return _classesByName![name];
}
/// Returns the [ClassData] for the class [node] in this library.
ClassData? lookupClassByNode(ir.Class node) {
_ensureClasses();
return _classesByNode![node];
}
ir.Typedef? lookupTypedef(String name) {
return _typedefs[name];
}
void _ensureMembers() {
if (_membersByName == null) {
final membersByName = _membersByName = {};
final membersByNode = _membersByNode = {};
for (ir.Member member in node.members) {
String name = computeMemberName(member);
assert(
!membersByName.containsKey(name),
"Duplicate member '$name' in $membersByName "
"trying to add $member.");
assert(
!membersByNode.containsKey(member),
"Duplicate member '$name' in $membersByNode "
"trying to add $member.");
membersByNode[member] = membersByName[name] = MemberData(member);
}
}
}
/// Returns the [MemberData] for the member uniquely identified by [name] in
/// this library.
MemberData? lookupMemberDataByName(String name) {
_ensureMembers();
return _membersByName![name];
}
/// Returns the [MemberData] for the member [node] in this library.
MemberData? lookupMemberDataByNode(ir.Member node) {
_ensureMembers();
return _membersByNode![node];
}
@override
String toString() => 'LibraryData($node(${identityHashCode(node)}))';
}
/// Helper for looking up members from an [ir.Class] node.
class ClassData {
/// The [ir.Class] that defines the class.
final ir.Class node;
/// Cache of [MemberData] for members in this class.
Map<String, MemberData>? _membersByName;
Map<ir.Member, MemberData>? _membersByNode;
ClassData(this.node);
void _ensureMembers() {
if (_membersByName == null) {
final membersByName = _membersByName = {};
final membersByNode = _membersByNode = {};
for (ir.Member member in node.members) {
String name = computeMemberName(member);
assert(
!membersByName.containsKey(name),
"Duplicate member '$name' in $membersByName "
"trying to add $member.");
assert(
!membersByNode.containsKey(member),
"Duplicate member '$name' in $membersByNode "
"trying to add $member.");
membersByNode[member] = membersByName[name] = MemberData(member);
}
}
}
/// Returns the [MemberData] for the member uniquely identified by [name] in
/// this class.
MemberData? lookupMemberDataByName(String name) {
_ensureMembers();
return _membersByName![name];
}
/// Returns the [MemberData] for the member [node] in this class.
MemberData? lookupMemberDataByNode(ir.Member node) {
_ensureMembers();
return _membersByNode![node];
}
@override
String toString() => 'ClassData($node(${identityHashCode(node)}))';
}
/// Helper for looking up child [ir.TreeNode]s of a [ir.Member] node.
class MemberData {
/// The [ir.Member] that defines the member.
final ir.Member node;
/// Cached index to [ir.TreeNode] map used for deserialization of
/// [ir.TreeNode]s.
Map<int, ir.TreeNode>? _indexToNodeMap;
/// Cached [ir.TreeNode] to index map used for serialization of
/// [ir.TreeNode]s.
Map<ir.TreeNode, int>? _nodeToIndexMap;
/// Cached [ir.ConstantExpression] to [ConstantNodeIndexerVisitor] map used
/// for fast serialization/deserialization of constant references.
late final Map<ir.ConstantExpression, ConstantNodeIndexerVisitor>
_constantIndexMap = {};
MemberData(this.node);
void _ensureMaps() {
if (_indexToNodeMap == null) {
_indexToNodeMap = {};
_nodeToIndexMap = {};
node.accept(TreeNodeIndexerVisitor(_indexToNodeMap!, _nodeToIndexMap!));
}
}
ConstantNodeIndexerVisitor _createConstantIndexer(
ir.ConstantExpression node) {
ConstantNodeIndexerVisitor indexer = ConstantNodeIndexerVisitor();
node.constant.accept(indexer);
return indexer;
}
ir.Constant getConstantByIndex(ir.ConstantExpression node, int index) {
ConstantNodeIndexerVisitor indexer =
_constantIndexMap[node] ??= _createConstantIndexer(node);
return indexer.getConstant(index);
}
int getIndexByConstant(ir.ConstantExpression node, ir.Constant constant) {
ConstantNodeIndexerVisitor indexer =
_constantIndexMap[node] ??= _createConstantIndexer(node);
return indexer.getIndex(constant);
}
/// Returns the [ir.TreeNode] corresponding to [index] in this member.
ir.TreeNode getTreeNodeByIndex(int index) {
_ensureMaps();
return _indexToNodeMap![index]!;
}
/// Returns the index corresponding to [ir.TreeNode] in this member.
int getIndexByTreeNode(ir.TreeNode node) {
_ensureMaps();
return _nodeToIndexMap![node]!;
}
@override
String toString() => 'MemberData($node(${identityHashCode(node)}))';
}