[analysis_server] Support patterns in element references search Change-Id: I303260c865c70691e0c7723b92c2ee7f09038310 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282664 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/test/search/element_references_test.dart b/pkg/analysis_server/test/search/element_references_test.dart index 5355f79..fa6d45d 100644 --- a/pkg/analysis_server/test/search/element_references_test.dart +++ b/pkg/analysis_server/test/search/element_references_test.dart
@@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analysis_server/protocol/protocol_generated.dart'; +import 'package:analyzer/src/test_utilities/test_code_format.dart'; import 'package:analyzer_plugin/protocol/protocol_common.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; @@ -24,9 +25,54 @@ expect(result.isPotential, isPotential); } + Future<void> assertReferences( + String content, { + required ElementKind kind, + required Map<int, SearchResultKind> resultKinds, + }) async { + final code = TestCode.parse(content); + expect( + resultKinds, + hasLength(code.ranges.length), + reason: "'resultsKinds' should have the same number of items as there " + "are ranges in 'content'", + ); + + addTestFile(code.code); + await findElementReferences(offset: code.position.offset, false); + + expect(searchElement!.kind, kind); + final expected = resultKinds.entries.map((entry) { + final index = entry.key; + final kind = entry.value; + final range = code.ranges[index].sourceRange; + return { + 'kind': kind, + 'path': testFile.path, + 'range': range.offset, + 'length': range.length, + }; + }).toSet(); + final actual = results + .map((result) => { + 'kind': result.kind, + 'path': result.location.file, + 'range': result.location.offset, + 'length': result.location.length, + }) + .toSet(); + expect(actual, equals(expected)); + } + Future<void> findElementReferences( - String search, bool includePotential) async { - var offset = findOffset(search); + bool includePotential, { + // TODO(dantup): Remove 'search' parameter and convert original tests to go + // through 'assertReferences' using parsed code. + String? search, + int? offset, + }) async { + assert(search != null || offset != null); + offset ??= findOffset(search!); await waitForTasksFinished(); var request = SearchFindElementReferencesParams( testFile.path, offset, includePotential) @@ -58,7 +104,7 @@ A.named; // 6 } '''); - await findElementReferences('named() {}', false); + await findElementReferences(search: 'named() {}', false); expect(searchElement!.kind, ElementKind.CONSTRUCTOR); expect(results, hasLength(6)); assertHasResult(SearchResultKind.REFERENCE, '.named] 1', 6); @@ -86,7 +132,7 @@ x.named(3); } '''); - await findElementReferences('named(p); // A', true); + await findElementReferences(search: 'named(p); // A', true); expect(searchElement!.kind, ElementKind.CONSTRUCTOR); expect(results, hasLength(1)); assertHasResult(SearchResultKind.INVOCATION, '.named(1)', 6); @@ -111,7 +157,7 @@ A.new; // 7 } '''); - await findElementReferences('A() {}', false); + await findElementReferences(search: 'A() {}', false); expect(searchElement!.kind, ElementKind.CONSTRUCTOR); expect(results, hasLength(7)); assertHasResult(SearchResultKind.REFERENCE, '] 1', 0); @@ -145,7 +191,7 @@ new B(2); } '''); - await findElementReferences('A(p)', true); + await findElementReferences(search: 'A(p)', true); expect(searchElement!.kind, ElementKind.CONSTRUCTOR); expect(results, hasLength(1)); assertHasResult(SearchResultKind.INVOCATION, '(1)', 0); @@ -171,7 +217,7 @@ a.fff(); // in f() } '''); - await findElementReferences('fff; // declaration', false); + await findElementReferences(search: 'fff; // declaration', false); expect(searchElement!.kind, ElementKind.FIELD); expect(results, hasLength(10)); assertHasResult(SearchResultKind.WRITE, 'fff); // in constructor'); @@ -204,7 +250,7 @@ } '''); { - await findElementReferences('fff =>', false); + await findElementReferences(search: 'fff =>', false); expect(searchElement!.kind, ElementKind.FIELD); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'fff); // in m()'); @@ -213,7 +259,7 @@ assertHasResult(SearchResultKind.WRITE, 'fff = 10;'); } { - await findElementReferences('fff(x) {}', false); + await findElementReferences(search: 'fff(x) {}', false); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'fff); // in m()'); assertHasResult(SearchResultKind.WRITE, 'fff = 1;'); @@ -233,7 +279,7 @@ } } '''); - await findElementReferences('fff); // in constructor', false); + await findElementReferences(search: 'fff); // in constructor', false); expect(searchElement!.kind, ElementKind.FIELD); expect(results, hasLength(3)); assertHasResult(SearchResultKind.WRITE, 'fff); // in constructor'); @@ -252,7 +298,7 @@ int get foo => 0; } '''); - await findElementReferences('foo =>', false); + await findElementReferences(search: 'foo =>', false); expect(searchElement!.kind, ElementKind.FIELD); expect(results, hasLength(2)); assertHasResult(SearchResultKind.READ, 'foo: 0'); @@ -273,7 +319,7 @@ print(a.mmm); // in f() } '''); - await findElementReferences('mmm(p) {}', false); + await findElementReferences(search: 'mmm(p) {}', false); expect(searchElement!.kind, ElementKind.METHOD); expect(results, hasLength(4)); assertHasResult(SearchResultKind.INVOCATION, 'mmm(1);'); @@ -293,7 +339,7 @@ print(a.mmm); } '''); - await findElementReferences('mmm(p) {}', false); + await findElementReferences(search: 'mmm(p) {}', false); expect(searchElement!.kind, ElementKind.METHOD); expect(results, hasLength(2)); assertHasResult(SearchResultKind.INVOCATION, 'mmm(10);'); @@ -309,7 +355,7 @@ const E.other() : this.named(); // 4 } '''); - await findElementReferences('named(); // 3', false); + await findElementReferences(search: 'named(); // 3', false); expect(searchElement!.kind, ElementKind.CONSTRUCTOR); expect(results, hasLength(3)); assertHasResult(SearchResultKind.REFERENCE, '.named] 1', 6); @@ -328,7 +374,7 @@ const E.other() : this(); // 6 } '''); - await findElementReferences('E(); // 5', false); + await findElementReferences(search: 'E(); // 5', false); expect(searchElement!.kind, ElementKind.CONSTRUCTOR); expect(results, hasLength(5)); assertHasResult(SearchResultKind.REFERENCE, '] 1', 0); @@ -360,7 +406,7 @@ e.fff(); // 11 } '''); - await findElementReferences('fff; // 01', false); + await findElementReferences(search: 'fff; // 01', false); expect(searchElement!.kind, ElementKind.FIELD); expect(results, hasLength(10)); assertHasResult(SearchResultKind.WRITE, 'fff); // 02'); @@ -395,7 +441,7 @@ } '''); { - await findElementReferences('fff =>', false); + await findElementReferences(search: 'fff =>', false); expect(searchElement!.kind, ElementKind.FIELD); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'fff; // 1'); @@ -404,7 +450,7 @@ assertHasResult(SearchResultKind.WRITE, 'fff = 0; // 4'); } { - await findElementReferences('fff(_) {}', false); + await findElementReferences(search: 'fff(_) {}', false); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'fff; // 1'); assertHasResult(SearchResultKind.WRITE, 'fff = 0; // 2'); @@ -429,7 +475,7 @@ e.foo; // 4 } '''); - await findElementReferences('foo() {}', false); + await findElementReferences(search: 'foo() {}', false); expect(searchElement!.kind, ElementKind.METHOD); expect(results, hasLength(4)); assertHasResult(SearchResultKind.INVOCATION, 'foo(); // 1'); @@ -450,7 +496,7 @@ E(0).bar(); } '''); - await findElementReferences('E on int', false); + await findElementReferences(search: 'E on int', false); expect(searchElement!.kind, ElementKind.EXTENSION); expect(results, hasLength(2)); assertHasResult(SearchResultKind.REFERENCE, 'E.foo();'); @@ -477,7 +523,7 @@ E.fff(); // in f() } '''); - await findElementReferences('fff; // declaration', false); + await findElementReferences(search: 'fff; // declaration', false); expect(searchElement!.kind, ElementKind.FIELD); expect(results, hasLength(8)); // m() @@ -508,7 +554,7 @@ } '''); { - await findElementReferences('fff =>', false); + await findElementReferences(search: 'fff =>', false); expect(searchElement!.kind, ElementKind.FIELD); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'fff); // in m()'); @@ -517,7 +563,7 @@ assertHasResult(SearchResultKind.WRITE, 'fff = 10;'); } { - await findElementReferences('fff(x) {}', false); + await findElementReferences(search: 'fff(x) {}', false); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'fff); // in m()'); assertHasResult(SearchResultKind.WRITE, 'fff = 1;'); @@ -542,7 +588,7 @@ } '''); { - await findElementReferences('fff =>', false); + await findElementReferences(search: 'fff =>', false); expect(searchElement!.kind, ElementKind.FIELD); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'fff); // in m()'); @@ -551,7 +597,7 @@ assertHasResult(SearchResultKind.WRITE, 'fff = 10;'); } { - await findElementReferences('fff(x) {}', false); + await findElementReferences(search: 'fff(x) {}', false); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'fff); // in m()'); assertHasResult(SearchResultKind.WRITE, 'fff = 1;'); @@ -573,7 +619,7 @@ 0.foo; // 4 } '''); - await findElementReferences('foo() {}', false); + await findElementReferences(search: 'foo() {}', false); expect(searchElement!.kind, ElementKind.METHOD); expect(results, hasLength(4)); assertHasResult(SearchResultKind.INVOCATION, 'foo(); // 1'); @@ -590,7 +636,7 @@ print(fff); } '''); - await findElementReferences('fff(p) {}', false); + await findElementReferences(search: 'fff(p) {}', false); expect(searchElement!.kind, ElementKind.FUNCTION); expect(results, hasLength(2)); assertHasResult(SearchResultKind.INVOCATION, 'fff(1)'); @@ -614,7 +660,7 @@ c.fff = 30; } '''); - await findElementReferences('fff; // in B', false); + await findElementReferences(search: 'fff; // in B', false); expect(searchElement!.kind, ElementKind.FIELD); assertHasResult(SearchResultKind.WRITE, 'fff = 10;'); assertHasResult(SearchResultKind.WRITE, 'fff = 20;'); @@ -638,7 +684,7 @@ c.mmm(30); } '''); - await findElementReferences('mmm(_) {} // in B', false); + await findElementReferences(search: 'mmm(_) {} // in B', false); expect(searchElement!.kind, ElementKind.METHOD); assertHasResult(SearchResultKind.INVOCATION, 'mmm(10)'); assertHasResult(SearchResultKind.INVOCATION, 'mmm(20)'); @@ -662,7 +708,7 @@ C.mmm(30); } '''); - await findElementReferences('mmm(_) {} // in B', false); + await findElementReferences(search: 'mmm(_) {} // in B', false); expect(searchElement!.kind, ElementKind.METHOD); expect(results, hasLength(1)); assertHasResult(SearchResultKind.INVOCATION, 'mmm(20)'); @@ -685,7 +731,7 @@ c.m(p: 3); } '''); - await findElementReferences('p}) {} // in B', false); + await findElementReferences(search: 'p}) {} // in B', false); expect(searchElement!.kind, ElementKind.PARAMETER); assertHasResult(SearchResultKind.REFERENCE, 'p: 1'); assertHasResult(SearchResultKind.REFERENCE, 'p: 2'); @@ -704,7 +750,7 @@ } } '''); - await findElementReferences('myLabel; // break', false); + await findElementReferences(search: 'myLabel; // break', false); expect(searchElement!.kind, ElementKind.LABEL); expect(results, hasLength(2)); assertHasResult(SearchResultKind.REFERENCE, 'myLabel; // continue'); @@ -721,7 +767,7 @@ vvv(); } '''); - await findElementReferences('vvv = 1', false); + await findElementReferences(search: 'vvv = 1', false); expect(searchElement!.kind, ElementKind.LOCAL_VARIABLE); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'vvv);'); @@ -735,7 +781,7 @@ mixin A {} class B extends Object with A {} // B '''); - await findElementReferences('A {}', false); + await findElementReferences(search: 'A {}', false); expect(searchElement!.kind, ElementKind.MIXIN); expect(results, hasLength(1)); assertHasResult(SearchResultKind.REFERENCE, 'A {} // B'); @@ -747,7 +793,7 @@ print(noElement); } '''); - await findElementReferences('noElement', false); + await findElementReferences(search: 'noElement', false); expect(searchId, isNull); } @@ -759,7 +805,7 @@ fff(10); } '''); - await findElementReferences('fff(p) {}', false); + await findElementReferences(search: 'fff(p) {}', false); expect(results, hasLength(1)); assertHasResult(SearchResultKind.INVOCATION, 'fff(10);'); } @@ -773,7 +819,7 @@ ppp(); } '''); - await findElementReferences('ppp) {', false); + await findElementReferences(search: 'ppp) {', false); expect(searchElement!.kind, ElementKind.PARAMETER); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'ppp);'); @@ -794,7 +840,7 @@ } } '''); - await findElementReferences('A {}', false); + await findElementReferences(search: 'A {}', false); assertHasResult(SearchResultKind.REFERENCE, 'A a = null;'); expect(getPathString(result.path), ''' LOCAL_VARIABLE a @@ -816,7 +862,7 @@ } } '''); - await findElementReferences('A {}', false); + await findElementReferences(search: 'A {}', false); assertHasResult(SearchResultKind.REFERENCE, 'A a = null;'); expect(getPathString(result.path), ''' LOCAL_VARIABLE a @@ -838,7 +884,7 @@ } } '''); - await findElementReferences('foo() {}', false); + await findElementReferences(search: 'foo() {}', false); assertHasResult(SearchResultKind.INVOCATION, 'foo();'); expect(getPathString(result.path), ''' METHOD bar @@ -859,7 +905,7 @@ } } '''); - await findElementReferences('foo() {}', false); + await findElementReferences(search: 'foo() {}', false); assertHasResult(SearchResultKind.INVOCATION, 'foo();'); expect(getPathString(result.path), ''' METHOD bar @@ -878,7 +924,7 @@ A a = null; } '''); - await findElementReferences('A {}', false); + await findElementReferences(search: 'A {}', false); assertHasResult(SearchResultKind.REFERENCE, 'A a = null;'); expect(getPathString(result.path), ''' LOCAL_VARIABLE a @@ -887,6 +933,267 @@ LIBRARY my_lib'''); } + Future<void> test_pattern_assignment() async { + await assertReferences( + kind: ElementKind.PARAMETER, + resultKinds: { + 0: SearchResultKind.WRITE, + 1: SearchResultKind.READ, + }, + ''' +void f(String ^a, String b) { + (b, /*[0*/a/*0]*/) = (/*[1*/a/*1]*/, b); +} +''', + ); + } + + Future<void> test_pattern_assignment_list() async { + await assertReferences( + kind: ElementKind.PARAMETER, + resultKinds: { + 0: SearchResultKind.WRITE, + }, + ''' +void f(List<int> x, num ^a) { + [/*[0*/a/*0]*/] = x; +} +''', + ); + } + + Future<void> test_pattern_cast_typeName() async { + await assertReferences( + kind: ElementKind.CLASS, + resultKinds: { + 0: SearchResultKind.REFERENCE, + 1: SearchResultKind.REFERENCE, + }, + ''' +String f((num, /*[0*/My^Class/*0]*/) record) { + var (i as int, s as /*[1*/MyClass/*1]*/) = record; +} + +class MyClass {} +''', + ); + } + + Future<void> test_pattern_cast_variable() async { + await assertReferences( + kind: ElementKind.LOCAL_VARIABLE, + resultKinds: { + 0: SearchResultKind.READ, + }, + ''' +void f((num, String) record) { + var (i as int, s^ as String) = record; + print(/*[0*/s/*0]*/); +} +''', + ); + } + + Future<void> test_pattern_map() async { + await assertReferences( + kind: ElementKind.LOCAL_VARIABLE, + resultKinds: { + 0: SearchResultKind.READ, + }, + ''' +void f(x) { + switch (x) { + case {0: String ^a}: + print(/*[0*/a/*0]*/); + break; + } +} +''', + ); + } + + Future<void> test_pattern_map_typeArguments() async { + await assertReferences( + kind: ElementKind.CLASS, + resultKinds: { + 0: SearchResultKind.REFERENCE, + 1: SearchResultKind.REFERENCE, + }, + ''' +/*[0*/A/*0]*/ f(x) { + switch (x) { + case <int, /*[1*/A/*1]*/>{0: var a}: + return a; + break; + } +} + +class ^A {} +''', + ); + } + + Future<void> test_pattern_nullAssert() async { + await assertReferences( + kind: ElementKind.LOCAL_VARIABLE, + resultKinds: { + 0: SearchResultKind.READ, + }, + ''' +void f((int?, int?) position) { + var (x!, y^!) = position; + print(/*[0*/y/*0]*/); +} +''', + ); + } + + Future<void> test_pattern_nullCheck() async { + await assertReferences( + kind: ElementKind.LOCAL_VARIABLE, + resultKinds: { + 0: SearchResultKind.READ, + }, + ''' +void f(String? maybeString) { + switch (maybeString) { + case var ^s?: + print(/*[0*/s/*0]*/); + } +} +''', + ); + } + + Future<void> test_pattern_object_field() async { + await assertReferences( + kind: ElementKind.FIELD, + resultKinds: { + 0: SearchResultKind.READ, + }, + ''' +double calculateArea(Shape shape) => + switch (shape) { + Square(/*[0*/length/*0]*/: var l) => l * l, + }; + +class Shape { } +class Square extends Shape { + double get len^gth => 0; +} +''', + ); + } + + Future<void> test_pattern_object_fieldName_explicit() async { + await assertReferences( + kind: ElementKind.FIELD, + resultKinds: { + 0: SearchResultKind.READ, + }, + ''' +double calculateArea(Object a) => + switch (a) { + Square(/*[0*/length/*0]*/: var l) => l * l, + }; + +class Square { + double len^gth = 0; +} +''', + ); + } + + Future<void> test_pattern_object_fieldName_implicit() async { + await assertReferences( + kind: ElementKind.FIELD, + resultKinds: { + 0: SearchResultKind.READ, + }, + ''' +double calculateArea(Object a) => + switch (a) { + Square(/*[0*//*0]*/:var length) => length * length, + }; + +class Square { + double len^gth = 0; +} +''', + ); + } + + Future<void> test_pattern_object_typeName() async { + await assertReferences( + kind: ElementKind.CLASS, + resultKinds: { + 0: SearchResultKind.REFERENCE, + }, + ''' +double calculateArea(Object a) => + switch (a) { + /*[0*/Square/*0]*/(length: var l) => l * l, + }; + +class Sq^uare { + double get length => 0; +} +''', + ); + } + + Future<void> test_pattern_object_variable() async { + await assertReferences( + kind: ElementKind.LOCAL_VARIABLE, + resultKinds: { + 0: SearchResultKind.READ, + 1: SearchResultKind.READ, + }, + ''' +double calculateArea(Shape shape) => + switch (shape) { + Square(length: var ^l) => /*[0*/l/*0]*/ * /*[1*/l/*1]*/, + }; + +class Shape { } +class Square extends Shape { + double get length => 0; +} +''', + ); + } + + Future<void> test_pattern_record_fieldAssignment() async { + await assertReferences( + kind: ElementKind.PARAMETER, + resultKinds: { + 0: SearchResultKind.WRITE, + }, + ''' +void f(({int foo}) x, num ^a) { + (foo: /*[0*/a/*0]*/,) = x; +} +''', + ); + } + + Future<void> test_pattern_relational_variable() async { + await assertReferences( + kind: ElementKind.LOCAL_VARIABLE, + resultKinds: { + 0: SearchResultKind.READ, + }, + ''' +String f(int char) { + const ze^ro = 0; + return switch (char) { + == /*[0*/zero/*0]*/ => 'zero' + }; +} +''', + ); + } + Future<void> test_potential_disabled() async { addTestFile(''' class A { @@ -897,7 +1204,7 @@ p.test(2); } '''); - await findElementReferences('test(p) {}', false); + await findElementReferences(search: 'test(p) {}', false); assertHasResult(SearchResultKind.INVOCATION, 'test(1);'); assertNoResult(SearchResultKind.INVOCATION, 'test(2);'); } @@ -913,7 +1220,7 @@ print(p.test); // p } '''); - await findElementReferences('test; // declaration', true); + await findElementReferences(search: 'test; // declaration', true); { assertHasResult(SearchResultKind.WRITE, 'test = 1;'); expect(result.isPotential, isFalse); @@ -938,7 +1245,7 @@ p.test(2); } '''); - await findElementReferences('test(p) {}', true); + await findElementReferences(search: 'test(p) {}', true); { assertHasResult(SearchResultKind.INVOCATION, 'test(1);'); expect(result.isPotential, isFalse); @@ -966,7 +1273,7 @@ b.test(3); } '''); - await findElementReferences('test(_) {} // of Derived', true); + await findElementReferences(search: 'test(_) {} // of Derived', true); assertHasRef(SearchResultKind.INVOCATION, 'test(1);', true); assertHasRef(SearchResultKind.INVOCATION, 'test(2);', false); assertHasRef(SearchResultKind.INVOCATION, 'test(3);', true); @@ -980,7 +1287,7 @@ ppp.Stream b; } '''); - await findElementReferences('ppp;', false); + await findElementReferences(search: 'ppp;', false); final searchElement = this.searchElement!; expect(searchElement.kind, ElementKind.PREFIX); expect(searchElement.name, 'ppp'); @@ -1000,7 +1307,7 @@ foo(0, test: 2, 1); } '''); - await findElementReferences('test})', false); + await findElementReferences(search: 'test})', false); expect(searchElement!.kind, ElementKind.PARAMETER); expect(results, hasLength(2)); assertHasResult(SearchResultKind.READ, 'test;'); @@ -1017,7 +1324,7 @@ vvv(); } '''); - await findElementReferences('vvv = 1', false); + await findElementReferences(search: 'vvv = 1', false); expect(searchElement!.kind, ElementKind.TOP_LEVEL_VARIABLE); expect(results, hasLength(4)); assertHasResult(SearchResultKind.READ, 'vvv);'); @@ -1036,14 +1343,14 @@ } '''); { - await findElementReferences('vvv =>', false); + await findElementReferences(search: 'vvv =>', false); expect(searchElement!.kind, ElementKind.TOP_LEVEL_VARIABLE); expect(results, hasLength(2)); assertHasResult(SearchResultKind.READ, 'vvv);'); assertHasResult(SearchResultKind.WRITE, 'vvv = 1;'); } { - await findElementReferences('vvv(x) {}', false); + await findElementReferences(search: 'vvv(x) {}', false); expect(results, hasLength(2)); assertHasResult(SearchResultKind.READ, 'vvv);'); assertHasResult(SearchResultKind.WRITE, 'vvv = 1;'); @@ -1057,7 +1364,7 @@ int b = 2; } '''); - await findElementReferences('int a', false); + await findElementReferences(search: 'int a', false); expect(searchElement!.kind, ElementKind.CLASS); assertHasResult(SearchResultKind.REFERENCE, 'int a'); assertHasResult(SearchResultKind.REFERENCE, 'int b'); @@ -1069,7 +1376,7 @@ void f(F f) { } '''); - await findElementReferences('F =', false); + await findElementReferences(search: 'F =', false); expect(searchElement!.kind, ElementKind.TYPE_ALIAS); expect(results, hasLength(1)); assertHasResult(SearchResultKind.REFERENCE, 'F f'); @@ -1082,13 +1389,13 @@ void(A<String> a) {} '''); // Can find `A`. - await findElementReferences('A<T> =', false); + await findElementReferences(search: 'A<T> =', false); expect(searchElement!.kind, ElementKind.TYPE_ALIAS); expect(results, hasLength(1)); assertHasResult(SearchResultKind.REFERENCE, 'A<String>'); // Can find in `A`. - await findElementReferences('int,', false); + await findElementReferences(search: 'int,', false); expect(searchElement!.kind, ElementKind.CLASS); assertHasResult(SearchResultKind.REFERENCE, 'int,'); } @@ -1099,7 +1406,7 @@ void f(F f) { } '''); - await findElementReferences('F()', false); + await findElementReferences(search: 'F()', false); expect(searchElement!.kind, ElementKind.TYPE_ALIAS); expect(results, hasLength(1)); assertHasResult(SearchResultKind.REFERENCE, 'F f'); @@ -1112,7 +1419,7 @@ T m() => null; } '''); - await findElementReferences('T> {', false); + await findElementReferences(search: 'T> {', false); expect(searchElement!.kind, ElementKind.TYPE_PARAMETER); expect(results, hasLength(2)); assertHasResult(SearchResultKind.REFERENCE, 'T f;');
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart index 690064c..6b580d4 100644 --- a/pkg/analyzer/lib/src/dart/analysis/driver.dart +++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -87,7 +87,7 @@ /// TODO(scheglov) Clean up the list of implicitly analyzed files. class AnalysisDriver implements AnalysisDriverGeneric { /// The version of data format, should be incremented on every format change. - static const int DATA_VERSION = 259; + static const int DATA_VERSION = 260; /// The number of exception contexts allowed to write. Once this field is /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart index 80f9029..1365e1b 100644 --- a/pkg/analyzer/lib/src/dart/analysis/search.dart +++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -738,6 +738,11 @@ PatternVariableElementImpl element, SearchedFiles searchedFiles, ) async { + String path = element.source.fullName; + if (!searchedFiles.add(path, this)) { + return const <SearchResult>[]; + } + var rootVariable = element.rootVariable; var transitiveVariables = rootVariable is JoinPatternVariableElementImpl ? rootVariable.transitiveVariables