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:
Konstantin Shcheglov 2017-06-28 08:28:08 -07:00
parent 9ddb832e10
commit c175f4bf75
6 changed files with 397 additions and 5 deletions

View file

@ -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

View file

@ -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]

View file

@ -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,

View file

@ -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.

View file

@ -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.

View file

@ -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;