Extension type. Tests for type hierarchy.

Change-Id: Ic0e31bb13efd68a3413429d1ff9110bb9b268e2e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/323432
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2023-08-30 21:18:25 +00:00 committed by Commit Queue
parent 5926a7301b
commit bbc3dcbe30
13 changed files with 209 additions and 3 deletions

View file

@ -4307,7 +4307,7 @@ a:focus, a:hover {
An enumeration of the kinds of elements.
</p>
<dl><dt class="value">CLASS</dt><dt class="value">CLASS_TYPE_ALIAS</dt><dt class="value">COMPILATION_UNIT</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">CONSTRUCTOR_INVOCATION</dt><dt class="value">ENUM</dt><dt class="value">ENUM_CONSTANT</dt><dt class="value">EXTENSION</dt><dt class="value">FIELD</dt><dt class="value">FILE</dt><dt class="value">FUNCTION</dt><dt class="value">FUNCTION_INVOCATION</dt><dt class="value">FUNCTION_TYPE_ALIAS</dt><dt class="value">GETTER</dt><dt class="value">LABEL</dt><dt class="value">LIBRARY</dt><dt class="value">LOCAL_VARIABLE</dt><dt class="value">METHOD</dt><dt class="value">MIXIN</dt><dt class="value">PARAMETER</dt><dt class="value">PREFIX</dt><dt class="value">SETTER</dt><dt class="value">TOP_LEVEL_VARIABLE</dt><dt class="value">TYPE_ALIAS</dt><dt class="value">TYPE_PARAMETER</dt><dt class="value">UNIT_TEST_GROUP</dt><dt class="value">UNIT_TEST_TEST</dt><dt class="value">UNKNOWN</dt></dl></dd><dt class="typeDefinition"><a name="type_ExecutableFile">ExecutableFile: object</a></dt><dd>
<dl><dt class="value">CLASS</dt><dt class="value">CLASS_TYPE_ALIAS</dt><dt class="value">COMPILATION_UNIT</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">CONSTRUCTOR_INVOCATION</dt><dt class="value">ENUM</dt><dt class="value">ENUM_CONSTANT</dt><dt class="value">EXTENSION</dt><dt class="value">EXTENSION_TYPE</dt><dt class="value">FIELD</dt><dt class="value">FILE</dt><dt class="value">FUNCTION</dt><dt class="value">FUNCTION_INVOCATION</dt><dt class="value">FUNCTION_TYPE_ALIAS</dt><dt class="value">GETTER</dt><dt class="value">LABEL</dt><dt class="value">LIBRARY</dt><dt class="value">LOCAL_VARIABLE</dt><dt class="value">METHOD</dt><dt class="value">MIXIN</dt><dt class="value">PARAMETER</dt><dt class="value">PREFIX</dt><dt class="value">SETTER</dt><dt class="value">TOP_LEVEL_VARIABLE</dt><dt class="value">TYPE_ALIAS</dt><dt class="value">TYPE_PARAMETER</dt><dt class="value">UNIT_TEST_GROUP</dt><dt class="value">UNIT_TEST_TEST</dt><dt class="value">UNKNOWN</dt></dl></dd><dt class="typeDefinition"><a name="type_ExecutableFile">ExecutableFile: object</a></dt><dd>
<p>
A description of an executable file.
</p>

View file

@ -64,6 +64,9 @@ ElementKind convertElementKind(engine.ElementKind kind) {
if (kind == engine.ElementKind.EXTENSION) {
return ElementKind.EXTENSION;
}
if (kind == engine.ElementKind.EXTENSION_TYPE) {
return ElementKind.EXTENSION_TYPE;
}
if (kind == engine.ElementKind.FIELD) {
return ElementKind.FIELD;
}

View file

@ -184,6 +184,12 @@ class TypeHierarchyComputerHelper {
}
ExecutableElement? findMemberElement(InterfaceElement clazz) {
// Members of extension types don't override anything.
// They redeclare, and resolved statically.
if (pivotClass is ExtensionTypeElement || clazz is ExtensionTypeElement) {
return null;
}
var pivotName = this.pivotName;
if (pivotName == null) {
return null;

View file

@ -442,6 +442,7 @@ final Matcher isElementDeclaration =
/// ENUM
/// ENUM_CONSTANT
/// EXTENSION
/// EXTENSION_TYPE
/// FIELD
/// FILE
/// FUNCTION
@ -472,6 +473,7 @@ final Matcher isElementKind = MatchesEnum('ElementKind', [
'ENUM',
'ENUM_CONSTANT',
'EXTENSION',
'EXTENSION_TYPE',
'FIELD',
'FILE',
'FUNCTION',

View file

@ -524,6 +524,10 @@ class ElementKindTest {
ElementKind.COMPILATION_UNIT);
expect(convertElementKind(engine.ElementKind.CONSTRUCTOR),
ElementKind.CONSTRUCTOR);
expect(convertElementKind(engine.ElementKind.EXTENSION),
ElementKind.EXTENSION);
expect(convertElementKind(engine.ElementKind.EXTENSION_TYPE),
ElementKind.EXTENSION_TYPE);
expect(convertElementKind(engine.ElementKind.FIELD), ElementKind.FIELD);
expect(
convertElementKind(engine.ElementKind.FUNCTION), ElementKind.FUNCTION);
@ -555,6 +559,10 @@ class ElementKindTest {
expect(ElementKind(ElementKind.COMPILATION_UNIT.name),
ElementKind.COMPILATION_UNIT);
expect(ElementKind(ElementKind.CONSTRUCTOR.name), ElementKind.CONSTRUCTOR);
expect(ElementKind(ElementKind.CONSTRUCTOR.name), ElementKind.CONSTRUCTOR);
expect(ElementKind(ElementKind.EXTENSION.name), ElementKind.EXTENSION);
expect(ElementKind(ElementKind.EXTENSION_TYPE.name),
ElementKind.EXTENSION_TYPE);
expect(ElementKind(ElementKind.FIELD.name), ElementKind.FIELD);
expect(ElementKind(ElementKind.FUNCTION.name), ElementKind.FUNCTION);
expect(ElementKind(ElementKind.FUNCTION_TYPE_ALIAS.name),

View file

@ -246,7 +246,6 @@ class EnumTest {
engine.ElementKind.EXPORT: ElementKind.UNKNOWN,
engine.ElementKind.GENERIC_FUNCTION_TYPE: ElementKind.FUNCTION_TYPE_ALIAS,
engine.ElementKind.IMPORT: ElementKind.UNKNOWN,
engine.ElementKind.EXTENSION_TYPE: ElementKind.UNKNOWN,
engine.ElementKind.LIBRARY_AUGMENTATION: ElementKind.UNKNOWN,
engine.ElementKind.NAME: ElementKind.UNKNOWN,
engine.ElementKind.NEVER: ElementKind.UNKNOWN,

View file

@ -1354,6 +1354,177 @@ enum E with M {
]);
}
Future<void> test_extensionType_implements_class() async {
addTestFile('''
class A {}
class B extends A {}
extension type E(B it) implements A {}
''');
var items = await _getTypeHierarchy('E(B it)');
expect(_toJson(items), [
{
'classElement': {
'kind': 'EXTENSION_TYPE',
'name': 'E',
'location': anything,
'flags': 0
},
'interfaces': [1],
'mixins': [],
'subclasses': []
},
{
'classElement': {
'kind': 'CLASS',
'name': 'A',
'location': anything,
'flags': 0
},
'superclass': 2,
'interfaces': [],
'mixins': [],
'subclasses': []
},
{
'classElement': {
'kind': 'CLASS',
'name': 'Object',
'location': anything,
'flags': 0
},
'interfaces': [],
'mixins': [],
'subclasses': []
}
]);
}
Future<void> test_extensionType_implements_class2() async {
addTestFile('''
class A {}
extension type E(A it) implements A {}
''');
var items = await _getTypeHierarchy('A {}');
expect(_toJson(items), [
{
'classElement': {
'kind': 'CLASS',
'name': 'A',
'location': anything,
'flags': 0
},
'superclass': 1,
'interfaces': [],
'mixins': [],
'subclasses': [2]
},
{
'classElement': {
'kind': 'CLASS',
'name': 'Object',
'location': anything,
'flags': 0
},
'interfaces': [],
'mixins': [],
'subclasses': []
},
{
'classElement': {
'kind': 'EXTENSION_TYPE',
'name': 'E',
'location': anything,
'flags': 0
},
'superclass': 0,
'interfaces': [],
'mixins': [],
'subclasses': []
}
]);
}
Future<void> test_extensionType_implements_extensionType() async {
addTestFile('''
class A {}
extension type E1(A it) {}
extension type E2(A it) implements E1 {}
''');
var items = await _getTypeHierarchy('E2(A it)');
expect(_toJson(items), [
{
'classElement': {
'kind': 'EXTENSION_TYPE',
'name': 'E2',
'location': anything,
'flags': 0
},
'interfaces': [1],
'mixins': [],
'subclasses': []
},
{
'classElement': {
'kind': 'EXTENSION_TYPE',
'name': 'E1',
'location': anything,
'flags': 0
},
'interfaces': [2],
'mixins': [],
'subclasses': []
},
{
'classElement': {
'kind': 'CLASS',
'name': 'Object',
'location': anything,
'flags': 0
},
'interfaces': [],
'mixins': [],
'subclasses': []
}
]);
}
Future<void> test_extensionType_member_method() async {
addTestFile('''
class A {
void test() {} // in A
}
extension type E(A it) implements A {
void test() {} // in E
}
''');
var items = await _getTypeHierarchy('test() {} // in E');
var itemE = items[0];
var itemA = items[itemE.interfaces.single];
expect(itemA.classElement.name, 'A');
expect(itemE.classElement.name, 'E');
expect(itemA.memberElement, isNull);
expect(itemE.memberElement, isNull);
}
Future<void> test_extensionType_member_method2() async {
addTestFile('''
class A {
void test() {} // in A
}
extension type E(A it) implements A {
void test() {} // in E
}
''');
var items = await _getTypeHierarchy('test() {} // in A');
var itemA = items[0];
var itemE = items[itemA.subclasses.single];
expect(itemA.classElement.name, 'A');
expect(itemE.classElement.name, 'E');
expect(
itemA.memberElement!.location!.offset, findOffset('test() {} // in A'));
expect(itemE.memberElement, isNull);
}
void _assertMember(TypeHierarchyItem item, String search) {
expect(item.memberElement!.location!.offset, findOffset(search));
}

View file

@ -31,6 +31,8 @@ public class ElementKind {
public static final String EXTENSION = "EXTENSION";
public static final String EXTENSION_TYPE = "EXTENSION_TYPE";
public static final String FIELD = "FIELD";
public static final String FILE = "FILE";

View file

@ -1409,6 +1409,7 @@ class Element implements HasToJson {
/// ENUM
/// ENUM_CONSTANT
/// EXTENSION
/// EXTENSION_TYPE
/// FIELD
/// FILE
/// FUNCTION
@ -1450,6 +1451,8 @@ class ElementKind implements Enum {
static const ElementKind EXTENSION = ElementKind._('EXTENSION');
static const ElementKind EXTENSION_TYPE = ElementKind._('EXTENSION_TYPE');
static const ElementKind FIELD = ElementKind._('FIELD');
static const ElementKind FILE = ElementKind._('FILE');
@ -1503,6 +1506,7 @@ class ElementKind implements Enum {
ENUM,
ENUM_CONSTANT,
EXTENSION,
EXTENSION_TYPE,
FIELD,
FILE,
FUNCTION,
@ -1548,6 +1552,8 @@ class ElementKind implements Enum {
return ENUM_CONSTANT;
case 'EXTENSION':
return EXTENSION;
case 'EXTENSION_TYPE':
return EXTENSION_TYPE;
case 'FIELD':
return FIELD;
case 'FILE':

View file

@ -1355,7 +1355,7 @@ a:focus, a:hover {
An enumeration of the kinds of elements.
</p>
<dl><dt class="value">CLASS</dt><dt class="value">CLASS_TYPE_ALIAS</dt><dt class="value">COMPILATION_UNIT</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">CONSTRUCTOR_INVOCATION</dt><dt class="value">ENUM</dt><dt class="value">ENUM_CONSTANT</dt><dt class="value">EXTENSION</dt><dt class="value">FIELD</dt><dt class="value">FILE</dt><dt class="value">FUNCTION</dt><dt class="value">FUNCTION_INVOCATION</dt><dt class="value">FUNCTION_TYPE_ALIAS</dt><dt class="value">GETTER</dt><dt class="value">LABEL</dt><dt class="value">LIBRARY</dt><dt class="value">LOCAL_VARIABLE</dt><dt class="value">METHOD</dt><dt class="value">MIXIN</dt><dt class="value">PARAMETER</dt><dt class="value">PREFIX</dt><dt class="value">SETTER</dt><dt class="value">TOP_LEVEL_VARIABLE</dt><dt class="value">TYPE_ALIAS</dt><dt class="value">TYPE_PARAMETER</dt><dt class="value">UNIT_TEST_GROUP</dt><dt class="value">UNIT_TEST_TEST</dt><dt class="value">UNKNOWN</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
<dl><dt class="value">CLASS</dt><dt class="value">CLASS_TYPE_ALIAS</dt><dt class="value">COMPILATION_UNIT</dt><dt class="value">CONSTRUCTOR</dt><dt class="value">CONSTRUCTOR_INVOCATION</dt><dt class="value">ENUM</dt><dt class="value">ENUM_CONSTANT</dt><dt class="value">EXTENSION</dt><dt class="value">EXTENSION_TYPE</dt><dt class="value">FIELD</dt><dt class="value">FILE</dt><dt class="value">FUNCTION</dt><dt class="value">FUNCTION_INVOCATION</dt><dt class="value">FUNCTION_TYPE_ALIAS</dt><dt class="value">GETTER</dt><dt class="value">LABEL</dt><dt class="value">LIBRARY</dt><dt class="value">LOCAL_VARIABLE</dt><dt class="value">METHOD</dt><dt class="value">MIXIN</dt><dt class="value">PARAMETER</dt><dt class="value">PREFIX</dt><dt class="value">SETTER</dt><dt class="value">TOP_LEVEL_VARIABLE</dt><dt class="value">TYPE_ALIAS</dt><dt class="value">TYPE_PARAMETER</dt><dt class="value">UNIT_TEST_GROUP</dt><dt class="value">UNIT_TEST_TEST</dt><dt class="value">UNKNOWN</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
<p>
The absolute, normalized path of a file.

View file

@ -1409,6 +1409,7 @@ class Element implements HasToJson {
/// ENUM
/// ENUM_CONSTANT
/// EXTENSION
/// EXTENSION_TYPE
/// FIELD
/// FILE
/// FUNCTION
@ -1450,6 +1451,8 @@ class ElementKind implements Enum {
static const ElementKind EXTENSION = ElementKind._('EXTENSION');
static const ElementKind EXTENSION_TYPE = ElementKind._('EXTENSION_TYPE');
static const ElementKind FIELD = ElementKind._('FIELD');
static const ElementKind FILE = ElementKind._('FILE');
@ -1503,6 +1506,7 @@ class ElementKind implements Enum {
ENUM,
ENUM_CONSTANT,
EXTENSION,
EXTENSION_TYPE,
FIELD,
FILE,
FUNCTION,
@ -1548,6 +1552,8 @@ class ElementKind implements Enum {
return ENUM_CONSTANT;
case 'EXTENSION':
return EXTENSION;
case 'EXTENSION_TYPE':
return EXTENSION_TYPE;
case 'FIELD':
return FIELD;
case 'FILE':

View file

@ -254,6 +254,7 @@ final Matcher isElement = LazyMatcher(() => MatchesJsonObject('Element', {
/// ENUM
/// ENUM_CONSTANT
/// EXTENSION
/// EXTENSION_TYPE
/// FIELD
/// FILE
/// FUNCTION
@ -284,6 +285,7 @@ final Matcher isElementKind = MatchesEnum('ElementKind', [
'ENUM',
'ENUM_CONSTANT',
'EXTENSION',
'EXTENSION_TYPE',
'FIELD',
'FILE',
'FUNCTION',

View file

@ -601,6 +601,7 @@
<value><code>ENUM</code></value>
<value><code>ENUM_CONSTANT</code></value>
<value><code>EXTENSION</code></value>
<value><code>EXTENSION_TYPE</code></value>
<value><code>FIELD</code></value>
<value><code>FILE</code></value>
<value><code>FUNCTION</code></value>