Extension type. More tests for search, highlight, navigation.

Change-Id: Iffa7e73be52219591dc75f8aacb7defa4b001b1f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/323720
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
This commit is contained in:
Konstantin Shcheglov 2023-08-31 19:36:37 +00:00 committed by Commit Queue
parent 74794c81b2
commit 2c9089f120
4 changed files with 177 additions and 8 deletions

View file

@ -876,6 +876,11 @@ class _DartUnitHighlightsComputerVisitor extends RecursiveAstVisitor<void> {
HighlightRegionType.BUILT_IN,
);
computer._addRegion_token(
node.constKeyword,
HighlightRegionType.BUILT_IN,
);
computer._addRegion_token(
node.name,
HighlightRegionType.EXTENSION_TYPE,

View file

@ -1101,20 +1101,21 @@ void f() {
Future<void> test_extensionType() async {
final testCode = TestCode.parse(r'''
extension type A<T>.named(int it) implements num {}
extension type const A<T>.named(int it) implements num {}
''');
addTestFile(testCode.code);
await prepareHighlights();
assertHighlightText(testCode, -1, r'''
0 + 9 |extension| BUILT_IN
10 + 4 |type| BUILT_IN
15 + 1 |A| EXTENSION_TYPE
17 + 1 |T| TYPE_PARAMETER
20 + 5 |named| CONSTRUCTOR
26 + 3 |int| CLASS
30 + 2 |it| INSTANCE_FIELD_DECLARATION
34 + 10 |implements| BUILT_IN
45 + 3 |num| CLASS
15 + 5 |const| BUILT_IN
21 + 1 |A| EXTENSION_TYPE
23 + 1 |T| TYPE_PARAMETER
26 + 5 |named| CONSTRUCTOR
32 + 3 |int| CLASS
36 + 2 |it| INSTANCE_FIELD_DECLARATION
40 + 10 |implements| BUILT_IN
51 + 3 |num| CLASS
''');
}

View file

@ -833,6 +833,36 @@ extension E on C //2
assertHasTarget('C //1');
}
Future<void> test_extensionType() async {
addTestFile('''
extension type A(int it) {
A.named() : this(0);
void foo() {
it; // foo()
}
static void bar() {}
}
void f(A a) {
A.it; // f()
A(0);
A.named();
a.foo();
A.bar();
}
''');
await prepareNavigation();
assertHasRegion('int it');
assertHasRegionTarget('this(0)', 'A(int it', targetLength: 0);
assertHasRegionTarget('it; // foo()', 'it) {');
assertHasRegionTarget('A a)', 'A(int');
assertHasRegionTarget('it; // f()', 'it) {');
assertHasRegionTarget('A(0);', 'A(int', targetLength: 0);
assertHasRegionTarget('named();', 'named() :');
assertHasRegionTarget('foo();', 'foo() {');
assertHasRegionTarget('A.bar()', 'A(int');
assertHasRegionTarget('bar();', 'bar() {}');
}
Future<void> test_functionReference_className_staticMethod() async {
addTestFile('''
class A {

View file

@ -628,6 +628,139 @@ void f() {
assertHasResult(SearchResultKind.REFERENCE, 'foo; // 4');
}
Future<void> test_extensionType_constructor_named() async {
addTestFile('''
/// [new A.named] 1
extension type A(int it) {
A.named() : this(0);
A.other() : this.named(); // 2
}
void f() {
A.named(); // 3
A.named; // 4
}
''');
await findElementReferences(search: 'named() :', false);
expect(searchElement!.kind, ElementKind.CONSTRUCTOR);
expect(results, hasLength(4));
assertHasResult(SearchResultKind.REFERENCE, '.named] 1', 6);
assertHasResult(SearchResultKind.INVOCATION, '.named(); // 2', 6);
assertHasResult(SearchResultKind.INVOCATION, '.named(); // 3', 6);
assertHasResult(SearchResultKind.REFERENCE, '.named; // 4', 6);
}
Future<void> test_extensionType_constructor_unnamed() async {
addTestFile('''
/// [new A] 1
/// [A.new] 2
extension type A.named(int it) {
A() : named(0);
A.other() : this(); // 3
}
void f() {
A(); // 4
A.new; // 5
}
''');
await findElementReferences(search: 'A() :', false);
expect(searchElement!.kind, ElementKind.CONSTRUCTOR);
expect(results, hasLength(5));
assertHasResult(SearchResultKind.REFERENCE, '] 1', 0);
assertHasResult(SearchResultKind.REFERENCE, '.new] 2', 4);
assertHasResult(SearchResultKind.INVOCATION, '(); // 3', 0);
assertHasResult(SearchResultKind.INVOCATION, '(); // 4', 0);
assertHasResult(SearchResultKind.REFERENCE, '.new; // 5', 4);
}
Future<void> test_extensionType_field_explicit_static() async {
addTestFile('''
extension E(int it) {
static dynamic foo; // declaration
void m() {
foo; // in m()
foo(); // in m()
foo = 1;
foo += 2;
}
}
void f() {
E.foo; // in f()
E.foo(); // in f()
E.foo = 10;
E.foo += 20;
}
''');
await findElementReferences(search: 'foo; // declaration', false);
expect(searchElement!.kind, ElementKind.FIELD);
expect(results, hasLength(8));
// m()
assertHasResult(SearchResultKind.READ, 'foo; // in m()');
assertHasResult(SearchResultKind.READ, 'foo(); // in m()');
assertHasResult(SearchResultKind.WRITE, 'foo = 1;');
assertHasResult(SearchResultKind.WRITE, 'foo += 2;');
// f()
assertHasResult(SearchResultKind.READ, 'foo; // in f()');
assertHasResult(SearchResultKind.READ, 'foo(); // in f()');
assertHasResult(SearchResultKind.WRITE, 'foo = 10;');
assertHasResult(SearchResultKind.WRITE, 'foo += 20;');
}
Future<void> test_extensionType_field_implicit() async {
addTestFile('''
extension type A(int it) {
int get foo => 0;
set foo(int x) {}
void m() {
foo; // in m()
foo = 1;
}
}
void f(A a) {
a.foo; // in f()
a.foo = 10;
}
''');
{
await findElementReferences(search: 'foo =>', false);
expect(searchElement!.kind, ElementKind.FIELD);
expect(results, hasLength(4));
assertHasResult(SearchResultKind.READ, 'foo; // in m()');
assertHasResult(SearchResultKind.WRITE, 'foo = 1;');
assertHasResult(SearchResultKind.READ, 'foo; // in f()');
assertHasResult(SearchResultKind.WRITE, 'foo = 10;');
}
{
await findElementReferences(search: 'foo(int x) {}', false);
expect(results, hasLength(4));
assertHasResult(SearchResultKind.READ, 'foo; // in m()');
assertHasResult(SearchResultKind.WRITE, 'foo = 1;');
assertHasResult(SearchResultKind.READ, 'foo; // in f()');
assertHasResult(SearchResultKind.WRITE, 'foo = 10;');
}
}
Future<void> test_extensionType_method() async {
addTestFile('''
extension type E(int it) {
void foo() {}
}
void f(E e) {
e.foo(); // 1
e.foo; // 2
}
''');
await findElementReferences(search: 'foo() {}', false);
expect(searchElement!.kind, ElementKind.METHOD);
expect(results, hasLength(2));
assertHasResult(SearchResultKind.INVOCATION, 'foo(); // 1');
assertHasResult(SearchResultKind.REFERENCE, 'foo; // 2');
}
Future<void> test_function() async {
addTestFile('''
fff(p) {}