mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 21:31:20 +00:00
Index subtypes with supertypes, and names of members they declare.
R=brianwilkerson@google.com BUG= Review-Url: https://codereview.chromium.org/2957203002 .
This commit is contained in:
parent
9ddb832e10
commit
c175f4bf75
|
@ -85,7 +85,7 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
/**
|
||||
* The version of data format, should be incremented on every format change.
|
||||
*/
|
||||
static const int DATA_VERSION = 34;
|
||||
static const int DATA_VERSION = 35;
|
||||
|
||||
/**
|
||||
* The number of exception contexts allowed to write. Once this field is
|
||||
|
|
|
@ -10,8 +10,7 @@ import 'package:analyzer/dart/element/element.dart';
|
|||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/member.dart';
|
||||
import 'package:analyzer/src/generated/utilities_dart.dart';
|
||||
import 'package:analyzer/src/summary/format.dart'
|
||||
show AnalysisDriverUnitIndexBuilder;
|
||||
import 'package:analyzer/src/summary/format.dart';
|
||||
import 'package:analyzer/src/summary/idl.dart';
|
||||
|
||||
/**
|
||||
|
@ -211,6 +210,11 @@ class _IndexAssembler {
|
|||
*/
|
||||
final List<_NameRelationInfo> nameRelations = [];
|
||||
|
||||
/**
|
||||
* All subtypes declared in the unit.
|
||||
*/
|
||||
final List<AnalysisDriverSubtypeBuilder> subtypes = [];
|
||||
|
||||
/**
|
||||
* The [_StringInfo] to use for `null` strings.
|
||||
*/
|
||||
|
@ -293,7 +297,8 @@ class _IndexAssembler {
|
|||
usedNameKinds: nameRelations.map((r) => r.kind).toList(),
|
||||
usedNameOffsets: nameRelations.map((r) => r.offset).toList(),
|
||||
usedNameIsQualifiedFlags:
|
||||
nameRelations.map((r) => r.isQualified).toList());
|
||||
nameRelations.map((r) => r.isQualified).toList(),
|
||||
subtypes: subtypes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -505,6 +510,7 @@ class _IndexContributor extends GeneralizingAstVisitor {
|
|||
|
||||
@override
|
||||
visitClassDeclaration(ClassDeclaration node) {
|
||||
_addSubtype(node);
|
||||
if (node.extendsClause == null) {
|
||||
ClassElement objectElement = resolutionMap
|
||||
.elementDeclaredByClassDeclaration(node)
|
||||
|
@ -719,6 +725,59 @@ class _IndexContributor extends GeneralizingAstVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the given class as a subclass of its direct superclasses.
|
||||
*/
|
||||
void _addSubtype(ClassDeclaration node) {
|
||||
List<String> supertypes = [];
|
||||
List<String> members = [];
|
||||
|
||||
String getClassElementId(ClassElement element) {
|
||||
return element.library.source.uri.toString() +
|
||||
';' +
|
||||
element.source.uri.toString() +
|
||||
';' +
|
||||
element.name;
|
||||
}
|
||||
|
||||
void addSupertype(TypeName type) {
|
||||
Element element = type?.name?.staticElement;
|
||||
if (element is ClassElement) {
|
||||
String id = getClassElementId(element);
|
||||
supertypes.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
addSupertype(node.extendsClause?.superclass);
|
||||
node.withClause?.mixinTypes?.forEach(addSupertype);
|
||||
node.implementsClause?.interfaces?.forEach(addSupertype);
|
||||
|
||||
void addMemberName(SimpleIdentifier identifier) {
|
||||
if (identifier != null) {
|
||||
String name = identifier.name;
|
||||
if (name != null && name.isNotEmpty) {
|
||||
members.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ClassMember member in node.members) {
|
||||
if (member is MethodDeclaration) {
|
||||
addMemberName(member.name);
|
||||
} else if (member is FieldDeclaration) {
|
||||
for (var field in member.fields.variables) {
|
||||
addMemberName(field.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
supertypes.sort();
|
||||
members.sort();
|
||||
|
||||
assembler.subtypes.add(new AnalysisDriverSubtypeBuilder(
|
||||
name: node.name.name, supertypes: supertypes, members: members));
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given [constructor] is a synthetic constructor created for a
|
||||
* [ClassTypeAlias], return the actual constructor of a [ClassDeclaration]
|
||||
|
|
|
@ -669,6 +669,172 @@ abstract class _AnalysisDriverResolvedUnitMixin
|
|||
String toString() => convert.JSON.encode(toJson());
|
||||
}
|
||||
|
||||
class AnalysisDriverSubtypeBuilder extends Object
|
||||
with _AnalysisDriverSubtypeMixin
|
||||
implements idl.AnalysisDriverSubtype {
|
||||
List<String> _members;
|
||||
String _name;
|
||||
List<String> _supertypes;
|
||||
|
||||
@override
|
||||
List<String> get members => _members ??= <String>[];
|
||||
|
||||
/**
|
||||
* The names of defined class members.
|
||||
* The list is sorted in ascending order.
|
||||
*/
|
||||
void set members(List<String> value) {
|
||||
this._members = value;
|
||||
}
|
||||
|
||||
@override
|
||||
String get name => _name ??= '';
|
||||
|
||||
/**
|
||||
* The name of the class.
|
||||
*/
|
||||
void set name(String value) {
|
||||
this._name = value;
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get supertypes => _supertypes ??= <String>[];
|
||||
|
||||
/**
|
||||
* The identifiers of the direct supertypes.
|
||||
* The list is sorted in ascending order.
|
||||
*/
|
||||
void set supertypes(List<String> value) {
|
||||
this._supertypes = value;
|
||||
}
|
||||
|
||||
AnalysisDriverSubtypeBuilder(
|
||||
{List<String> members, String name, List<String> supertypes})
|
||||
: _members = members,
|
||||
_name = name,
|
||||
_supertypes = supertypes;
|
||||
|
||||
/**
|
||||
* Flush [informative] data recursively.
|
||||
*/
|
||||
void flushInformative() {}
|
||||
|
||||
/**
|
||||
* Accumulate non-[informative] data into [signature].
|
||||
*/
|
||||
void collectApiSignature(api_sig.ApiSignature signature) {
|
||||
signature.addString(this._name ?? '');
|
||||
if (this._supertypes == null) {
|
||||
signature.addInt(0);
|
||||
} else {
|
||||
signature.addInt(this._supertypes.length);
|
||||
for (var x in this._supertypes) {
|
||||
signature.addString(x);
|
||||
}
|
||||
}
|
||||
if (this._members == null) {
|
||||
signature.addInt(0);
|
||||
} else {
|
||||
signature.addInt(this._members.length);
|
||||
for (var x in this._members) {
|
||||
signature.addString(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fb.Offset finish(fb.Builder fbBuilder) {
|
||||
fb.Offset offset_members;
|
||||
fb.Offset offset_name;
|
||||
fb.Offset offset_supertypes;
|
||||
if (!(_members == null || _members.isEmpty)) {
|
||||
offset_members = fbBuilder
|
||||
.writeList(_members.map((b) => fbBuilder.writeString(b)).toList());
|
||||
}
|
||||
if (_name != null) {
|
||||
offset_name = fbBuilder.writeString(_name);
|
||||
}
|
||||
if (!(_supertypes == null || _supertypes.isEmpty)) {
|
||||
offset_supertypes = fbBuilder
|
||||
.writeList(_supertypes.map((b) => fbBuilder.writeString(b)).toList());
|
||||
}
|
||||
fbBuilder.startTable();
|
||||
if (offset_members != null) {
|
||||
fbBuilder.addOffset(2, offset_members);
|
||||
}
|
||||
if (offset_name != null) {
|
||||
fbBuilder.addOffset(0, offset_name);
|
||||
}
|
||||
if (offset_supertypes != null) {
|
||||
fbBuilder.addOffset(1, offset_supertypes);
|
||||
}
|
||||
return fbBuilder.endTable();
|
||||
}
|
||||
}
|
||||
|
||||
class _AnalysisDriverSubtypeReader
|
||||
extends fb.TableReader<_AnalysisDriverSubtypeImpl> {
|
||||
const _AnalysisDriverSubtypeReader();
|
||||
|
||||
@override
|
||||
_AnalysisDriverSubtypeImpl createObject(fb.BufferContext bc, int offset) =>
|
||||
new _AnalysisDriverSubtypeImpl(bc, offset);
|
||||
}
|
||||
|
||||
class _AnalysisDriverSubtypeImpl extends Object
|
||||
with _AnalysisDriverSubtypeMixin
|
||||
implements idl.AnalysisDriverSubtype {
|
||||
final fb.BufferContext _bc;
|
||||
final int _bcOffset;
|
||||
|
||||
_AnalysisDriverSubtypeImpl(this._bc, this._bcOffset);
|
||||
|
||||
List<String> _members;
|
||||
String _name;
|
||||
List<String> _supertypes;
|
||||
|
||||
@override
|
||||
List<String> get members {
|
||||
_members ??= const fb.ListReader<String>(const fb.StringReader())
|
||||
.vTableGet(_bc, _bcOffset, 2, const <String>[]);
|
||||
return _members;
|
||||
}
|
||||
|
||||
@override
|
||||
String get name {
|
||||
_name ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 0, '');
|
||||
return _name;
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get supertypes {
|
||||
_supertypes ??= const fb.ListReader<String>(const fb.StringReader())
|
||||
.vTableGet(_bc, _bcOffset, 1, const <String>[]);
|
||||
return _supertypes;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _AnalysisDriverSubtypeMixin
|
||||
implements idl.AnalysisDriverSubtype {
|
||||
@override
|
||||
Map<String, Object> toJson() {
|
||||
Map<String, Object> _result = <String, Object>{};
|
||||
if (members.isNotEmpty) _result["members"] = members;
|
||||
if (name != '') _result["name"] = name;
|
||||
if (supertypes.isNotEmpty) _result["supertypes"] = supertypes;
|
||||
return _result;
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Object> toMap() => {
|
||||
"members": members,
|
||||
"name": name,
|
||||
"supertypes": supertypes,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() => convert.JSON.encode(toJson());
|
||||
}
|
||||
|
||||
class AnalysisDriverUnitErrorBuilder extends Object
|
||||
with _AnalysisDriverUnitErrorMixin
|
||||
implements idl.AnalysisDriverUnitError {
|
||||
|
@ -881,6 +1047,7 @@ class AnalysisDriverUnitIndexBuilder extends Object
|
|||
List<int> _elementUnits;
|
||||
int _nullStringId;
|
||||
List<String> _strings;
|
||||
List<AnalysisDriverSubtypeBuilder> _subtypes;
|
||||
List<int> _unitLibraryUris;
|
||||
List<int> _unitUnitUris;
|
||||
List<bool> _usedElementIsQualifiedFlags;
|
||||
|
@ -985,6 +1152,17 @@ class AnalysisDriverUnitIndexBuilder extends Object
|
|||
this._strings = value;
|
||||
}
|
||||
|
||||
@override
|
||||
List<AnalysisDriverSubtypeBuilder> get subtypes =>
|
||||
_subtypes ??= <AnalysisDriverSubtypeBuilder>[];
|
||||
|
||||
/**
|
||||
* The list of classes declared in the unit.
|
||||
*/
|
||||
void set subtypes(List<AnalysisDriverSubtypeBuilder> value) {
|
||||
this._subtypes = value;
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> get unitLibraryUris => _unitLibraryUris ??= <int>[];
|
||||
|
||||
|
@ -1125,6 +1303,7 @@ class AnalysisDriverUnitIndexBuilder extends Object
|
|||
List<int> elementUnits,
|
||||
int nullStringId,
|
||||
List<String> strings,
|
||||
List<AnalysisDriverSubtypeBuilder> subtypes,
|
||||
List<int> unitLibraryUris,
|
||||
List<int> unitUnitUris,
|
||||
List<bool> usedElementIsQualifiedFlags,
|
||||
|
@ -1143,6 +1322,7 @@ class AnalysisDriverUnitIndexBuilder extends Object
|
|||
_elementUnits = elementUnits,
|
||||
_nullStringId = nullStringId,
|
||||
_strings = strings,
|
||||
_subtypes = subtypes,
|
||||
_unitLibraryUris = unitLibraryUris,
|
||||
_unitUnitUris = unitUnitUris,
|
||||
_usedElementIsQualifiedFlags = usedElementIsQualifiedFlags,
|
||||
|
@ -1158,7 +1338,9 @@ class AnalysisDriverUnitIndexBuilder extends Object
|
|||
/**
|
||||
* Flush [informative] data recursively.
|
||||
*/
|
||||
void flushInformative() {}
|
||||
void flushInformative() {
|
||||
_subtypes?.forEach((b) => b.flushInformative());
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulate non-[informative] data into [signature].
|
||||
|
@ -1301,6 +1483,14 @@ class AnalysisDriverUnitIndexBuilder extends Object
|
|||
signature.addBool(x);
|
||||
}
|
||||
}
|
||||
if (this._subtypes == null) {
|
||||
signature.addInt(0);
|
||||
} else {
|
||||
signature.addInt(this._subtypes.length);
|
||||
for (var x in this._subtypes) {
|
||||
x?.collectApiSignature(signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<int> toBuffer() {
|
||||
|
@ -1315,6 +1505,7 @@ class AnalysisDriverUnitIndexBuilder extends Object
|
|||
fb.Offset offset_elementNameUnitMemberIds;
|
||||
fb.Offset offset_elementUnits;
|
||||
fb.Offset offset_strings;
|
||||
fb.Offset offset_subtypes;
|
||||
fb.Offset offset_unitLibraryUris;
|
||||
fb.Offset offset_unitUnitUris;
|
||||
fb.Offset offset_usedElementIsQualifiedFlags;
|
||||
|
@ -1352,6 +1543,10 @@ class AnalysisDriverUnitIndexBuilder extends Object
|
|||
offset_strings = fbBuilder
|
||||
.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
|
||||
}
|
||||
if (!(_subtypes == null || _subtypes.isEmpty)) {
|
||||
offset_subtypes = fbBuilder
|
||||
.writeList(_subtypes.map((b) => b.finish(fbBuilder)).toList());
|
||||
}
|
||||
if (!(_unitLibraryUris == null || _unitLibraryUris.isEmpty)) {
|
||||
offset_unitLibraryUris = fbBuilder.writeListUint32(_unitLibraryUris);
|
||||
}
|
||||
|
@ -1415,6 +1610,9 @@ class AnalysisDriverUnitIndexBuilder extends Object
|
|||
if (offset_strings != null) {
|
||||
fbBuilder.addOffset(0, offset_strings);
|
||||
}
|
||||
if (offset_subtypes != null) {
|
||||
fbBuilder.addOffset(18, offset_subtypes);
|
||||
}
|
||||
if (offset_unitLibraryUris != null) {
|
||||
fbBuilder.addOffset(2, offset_unitLibraryUris);
|
||||
}
|
||||
|
@ -1481,6 +1679,7 @@ class _AnalysisDriverUnitIndexImpl extends Object
|
|||
List<int> _elementUnits;
|
||||
int _nullStringId;
|
||||
List<String> _strings;
|
||||
List<idl.AnalysisDriverSubtype> _subtypes;
|
||||
List<int> _unitLibraryUris;
|
||||
List<int> _unitUnitUris;
|
||||
List<bool> _usedElementIsQualifiedFlags;
|
||||
|
@ -1542,6 +1741,14 @@ class _AnalysisDriverUnitIndexImpl extends Object
|
|||
return _strings;
|
||||
}
|
||||
|
||||
@override
|
||||
List<idl.AnalysisDriverSubtype> get subtypes {
|
||||
_subtypes ??= const fb.ListReader<idl.AnalysisDriverSubtype>(
|
||||
const _AnalysisDriverSubtypeReader())
|
||||
.vTableGet(_bc, _bcOffset, 18, const <idl.AnalysisDriverSubtype>[]);
|
||||
return _subtypes;
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> get unitLibraryUris {
|
||||
_unitLibraryUris ??=
|
||||
|
@ -1640,6 +1847,8 @@ abstract class _AnalysisDriverUnitIndexMixin
|
|||
if (elementUnits.isNotEmpty) _result["elementUnits"] = elementUnits;
|
||||
if (nullStringId != 0) _result["nullStringId"] = nullStringId;
|
||||
if (strings.isNotEmpty) _result["strings"] = strings;
|
||||
if (subtypes.isNotEmpty)
|
||||
_result["subtypes"] = subtypes.map((_value) => _value.toJson()).toList();
|
||||
if (unitLibraryUris.isNotEmpty)
|
||||
_result["unitLibraryUris"] = unitLibraryUris;
|
||||
if (unitUnitUris.isNotEmpty) _result["unitUnitUris"] = unitUnitUris;
|
||||
|
@ -1675,6 +1884,7 @@ abstract class _AnalysisDriverUnitIndexMixin
|
|||
"elementUnits": elementUnits,
|
||||
"nullStringId": nullStringId,
|
||||
"strings": strings,
|
||||
"subtypes": subtypes,
|
||||
"unitLibraryUris": unitLibraryUris,
|
||||
"unitUnitUris": unitUnitUris,
|
||||
"usedElementIsQualifiedFlags": usedElementIsQualifiedFlags,
|
||||
|
|
|
@ -981,6 +981,28 @@ table AnalysisDriverResolvedUnit {
|
|||
index:AnalysisDriverUnitIndex (id: 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about a subtype of one or more classes.
|
||||
*/
|
||||
table AnalysisDriverSubtype {
|
||||
/**
|
||||
* The names of defined class members.
|
||||
* The list is sorted in ascending order.
|
||||
*/
|
||||
members:[string] (id: 2);
|
||||
|
||||
/**
|
||||
* The name of the class.
|
||||
*/
|
||||
name:string (id: 0);
|
||||
|
||||
/**
|
||||
* The identifiers of the direct supertypes.
|
||||
* The list is sorted in ascending order.
|
||||
*/
|
||||
supertypes:[string] (id: 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about an error in a resolved unit.
|
||||
*/
|
||||
|
@ -1064,6 +1086,11 @@ table AnalysisDriverUnitIndex {
|
|||
*/
|
||||
strings:[string] (id: 0);
|
||||
|
||||
/**
|
||||
* The list of classes declared in the unit.
|
||||
*/
|
||||
subtypes:[AnalysisDriverSubtype] (id: 18);
|
||||
|
||||
/**
|
||||
* Each item of this list corresponds to the library URI of a unique library
|
||||
* specific unit referenced in the index. It is an index into [strings] list.
|
||||
|
|
|
@ -128,6 +128,31 @@ abstract class AnalysisDriverResolvedUnit extends base.SummaryClass {
|
|||
AnalysisDriverUnitIndex get index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about a subtype of one or more classes.
|
||||
*/
|
||||
abstract class AnalysisDriverSubtype extends base.SummaryClass {
|
||||
/**
|
||||
* The names of defined class members.
|
||||
* The list is sorted in ascending order.
|
||||
*/
|
||||
@Id(2)
|
||||
List<String> get members;
|
||||
|
||||
/**
|
||||
* The name of the class.
|
||||
*/
|
||||
@Id(0)
|
||||
String get name;
|
||||
|
||||
/**
|
||||
* The identifiers of the direct supertypes.
|
||||
* The list is sorted in ascending order.
|
||||
*/
|
||||
@Id(1)
|
||||
List<String> get supertypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about an error in a resolved unit.
|
||||
*/
|
||||
|
@ -227,6 +252,12 @@ abstract class AnalysisDriverUnitIndex extends base.SummaryClass {
|
|||
@Id(0)
|
||||
List<String> get strings;
|
||||
|
||||
/**
|
||||
* The list of classes declared in the unit.
|
||||
*/
|
||||
@Id(18)
|
||||
List<AnalysisDriverSubtype> get subtypes;
|
||||
|
||||
/**
|
||||
* Each item of this list corresponds to the library URI of a unique library
|
||||
* specific unit referenced in the index. It is an index into [strings] list.
|
||||
|
|
|
@ -916,6 +916,71 @@ class A {
|
|||
..isWrittenAt('field = 5', true);
|
||||
}
|
||||
|
||||
test_subtypes() async {
|
||||
String libP = 'package:test/lib.dart;package:test/lib.dart';
|
||||
provider.newFile(
|
||||
_p('$testProject/lib.dart'),
|
||||
'''
|
||||
class A {}
|
||||
class B {}
|
||||
class C {}
|
||||
class D {}
|
||||
class E {}
|
||||
''');
|
||||
await _indexTestUnit('''
|
||||
import 'lib.dart';
|
||||
|
||||
class X extends A {
|
||||
int field1, field2;
|
||||
int get getter1 => null;
|
||||
void set setter1(_) {}
|
||||
void method1() {}
|
||||
}
|
||||
|
||||
class Y extends Object with B, C {
|
||||
void methodY() {}
|
||||
}
|
||||
|
||||
class Z implements E, D {
|
||||
void methodZ() {}
|
||||
}
|
||||
''');
|
||||
|
||||
{
|
||||
AnalysisDriverSubtype X =
|
||||
index.subtypes.singleWhere((t) => t.name == 'X');
|
||||
expect(X.supertypes, ['$libP;A']);
|
||||
expect(X.members, ['field1', 'field2', 'getter1', 'method1', 'setter1']);
|
||||
}
|
||||
|
||||
{
|
||||
AnalysisDriverSubtype Y =
|
||||
index.subtypes.singleWhere((t) => t.name == 'Y');
|
||||
expect(
|
||||
Y.supertypes, ['dart:core;dart:core;Object', '$libP;B', '$libP;C']);
|
||||
expect(Y.members, ['methodY']);
|
||||
}
|
||||
|
||||
{
|
||||
AnalysisDriverSubtype Z =
|
||||
index.subtypes.singleWhere((t) => t.name == 'Z');
|
||||
expect(Z.supertypes, ['$libP;D', '$libP;E']);
|
||||
expect(Z.members, ['methodZ']);
|
||||
}
|
||||
}
|
||||
|
||||
test_subtypes_dynamic() async {
|
||||
await _indexTestUnit('''
|
||||
class X extends dynamic {
|
||||
void foo() {}
|
||||
}
|
||||
''');
|
||||
|
||||
AnalysisDriverSubtype X = index.subtypes.singleWhere((t) => t.name == 'X');
|
||||
expect(X.supertypes, isEmpty);
|
||||
expect(X.members, ['foo']);
|
||||
}
|
||||
|
||||
test_usedName_inLibraryIdentifier() async {
|
||||
await _indexTestUnit('''
|
||||
library aaa.bbb.ccc;
|
||||
|
|
Loading…
Reference in a new issue