From bbc3dcbe302538d988d4ee9a71cdbc7943a1cedb Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Wed, 30 Aug 2023 21:18:25 +0000 Subject: [PATCH] Extension type. Tests for type hierarchy. Change-Id: Ic0e31bb13efd68a3413429d1ff9110bb9b268e2e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/323432 Reviewed-by: Brian Wilkerson Commit-Queue: Konstantin Shcheglov --- pkg/analysis_server/doc/api.html | 2 +- .../lib/plugin/protocol/protocol_dart.dart | 3 + .../lib/src/search/type_hierarchy.dart | 6 + .../support/protocol_matchers.dart | 2 + .../test/plugin/protocol_dart_test.dart | 8 + .../test/protocol_server_test.dart | 1 - .../test/search/type_hierarchy_test.dart | 171 ++++++++++++++++++ .../generated/java/types/ElementKind.java | 2 + .../lib/src/protocol/protocol_common.dart | 6 + pkg/analyzer_plugin/doc/api.html | 2 +- .../lib/protocol/protocol_common.dart | 6 + .../support/protocol_matchers.dart | 2 + .../tool/spec/common_types_spec.html | 1 + 13 files changed, 209 insertions(+), 3 deletions(-) diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html index d86890ce38a..3baa89791eb 100644 --- a/pkg/analysis_server/doc/api.html +++ b/pkg/analysis_server/doc/api.html @@ -4307,7 +4307,7 @@ a:focus, a:hover { An enumeration of the kinds of elements.

-
CLASS
CLASS_TYPE_ALIAS
COMPILATION_UNIT
CONSTRUCTOR
CONSTRUCTOR_INVOCATION
ENUM
ENUM_CONSTANT
EXTENSION
FIELD
FILE
FUNCTION
FUNCTION_INVOCATION
FUNCTION_TYPE_ALIAS
GETTER
LABEL
LIBRARY
LOCAL_VARIABLE
METHOD
MIXIN
PARAMETER
PREFIX
SETTER
TOP_LEVEL_VARIABLE
TYPE_ALIAS
TYPE_PARAMETER
UNIT_TEST_GROUP
UNIT_TEST_TEST
UNKNOWN
ExecutableFile: object
+
CLASS
CLASS_TYPE_ALIAS
COMPILATION_UNIT
CONSTRUCTOR
CONSTRUCTOR_INVOCATION
ENUM
ENUM_CONSTANT
EXTENSION
EXTENSION_TYPE
FIELD
FILE
FUNCTION
FUNCTION_INVOCATION
FUNCTION_TYPE_ALIAS
GETTER
LABEL
LIBRARY
LOCAL_VARIABLE
METHOD
MIXIN
PARAMETER
PREFIX
SETTER
TOP_LEVEL_VARIABLE
TYPE_ALIAS
TYPE_PARAMETER
UNIT_TEST_GROUP
UNIT_TEST_TEST
UNKNOWN
ExecutableFile: object

A description of an executable file.

diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart index 1f2985c05f0..0babcc5266d 100644 --- a/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart +++ b/pkg/analysis_server/lib/plugin/protocol/protocol_dart.dart @@ -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; } diff --git a/pkg/analysis_server/lib/src/search/type_hierarchy.dart b/pkg/analysis_server/lib/src/search/type_hierarchy.dart index 0a0c7838dd9..038347f270e 100644 --- a/pkg/analysis_server/lib/src/search/type_hierarchy.dart +++ b/pkg/analysis_server/lib/src/search/type_hierarchy.dart @@ -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; diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart index 1b8e87ade28..b69e0a721dd 100644 --- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart +++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart @@ -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', diff --git a/pkg/analysis_server/test/plugin/protocol_dart_test.dart b/pkg/analysis_server/test/plugin/protocol_dart_test.dart index 7ff9068b05a..93c3ee08fb7 100644 --- a/pkg/analysis_server/test/plugin/protocol_dart_test.dart +++ b/pkg/analysis_server/test/plugin/protocol_dart_test.dart @@ -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), diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart index 3852eec5078..936473c19e9 100644 --- a/pkg/analysis_server/test/protocol_server_test.dart +++ b/pkg/analysis_server/test/protocol_server_test.dart @@ -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, diff --git a/pkg/analysis_server/test/search/type_hierarchy_test.dart b/pkg/analysis_server/test/search/type_hierarchy_test.dart index ab77d7e7ef0..0b0c729b723 100644 --- a/pkg/analysis_server/test/search/type_hierarchy_test.dart +++ b/pkg/analysis_server/test/search/type_hierarchy_test.dart @@ -1354,6 +1354,177 @@ enum E with M { ]); } + Future 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 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 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 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 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)); } diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ElementKind.java b/pkg/analysis_server/tool/spec/generated/java/types/ElementKind.java index 81be704cbbe..e9cd8cc3b87 100644 --- a/pkg/analysis_server/tool/spec/generated/java/types/ElementKind.java +++ b/pkg/analysis_server/tool/spec/generated/java/types/ElementKind.java @@ -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"; diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart index 815c4cabb6c..256557ede47 100644 --- a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart +++ b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart @@ -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': diff --git a/pkg/analyzer_plugin/doc/api.html b/pkg/analyzer_plugin/doc/api.html index beb55a5606a..32d6b9fda05 100644 --- a/pkg/analyzer_plugin/doc/api.html +++ b/pkg/analyzer_plugin/doc/api.html @@ -1355,7 +1355,7 @@ a:focus, a:hover { An enumeration of the kinds of elements.

-
CLASS
CLASS_TYPE_ALIAS
COMPILATION_UNIT
CONSTRUCTOR
CONSTRUCTOR_INVOCATION
ENUM
ENUM_CONSTANT
EXTENSION
FIELD
FILE
FUNCTION
FUNCTION_INVOCATION
FUNCTION_TYPE_ALIAS
GETTER
LABEL
LIBRARY
LOCAL_VARIABLE
METHOD
MIXIN
PARAMETER
PREFIX
SETTER
TOP_LEVEL_VARIABLE
TYPE_ALIAS
TYPE_PARAMETER
UNIT_TEST_GROUP
UNIT_TEST_TEST
UNKNOWN
FilePath: String
+
CLASS
CLASS_TYPE_ALIAS
COMPILATION_UNIT
CONSTRUCTOR
CONSTRUCTOR_INVOCATION
ENUM
ENUM_CONSTANT
EXTENSION
EXTENSION_TYPE
FIELD
FILE
FUNCTION
FUNCTION_INVOCATION
FUNCTION_TYPE_ALIAS
GETTER
LABEL
LIBRARY
LOCAL_VARIABLE
METHOD
MIXIN
PARAMETER
PREFIX
SETTER
TOP_LEVEL_VARIABLE
TYPE_ALIAS
TYPE_PARAMETER
UNIT_TEST_GROUP
UNIT_TEST_TEST
UNKNOWN
FilePath: String

The absolute, normalized path of a file. diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart index 6ea6d24a8a1..0e2ac2d99b6 100644 --- a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart +++ b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart @@ -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': diff --git a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart index f2ea620ef41..8cab210b597 100644 --- a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart +++ b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart @@ -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', diff --git a/pkg/analyzer_plugin/tool/spec/common_types_spec.html b/pkg/analyzer_plugin/tool/spec/common_types_spec.html index 516886a30c7..fa5b7f5b2b3 100644 --- a/pkg/analyzer_plugin/tool/spec/common_types_spec.html +++ b/pkg/analyzer_plugin/tool/spec/common_types_spec.html @@ -601,6 +601,7 @@ ENUM ENUM_CONSTANT EXTENSION + EXTENSION_TYPE FIELD FILE FUNCTION