| // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'package:analyzer/dart/analysis/results.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/file_system/file_system.dart'; |
| import 'package:analyzer/src/dart/analysis/driver.dart'; |
| import 'package:analyzer/src/dart/analysis/search.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/summary2/reference.dart'; |
| import 'package:analyzer/src/test_utilities/find_element.dart'; |
| import 'package:analyzer/src/util/performance/operation_performance.dart'; |
| import 'package:analyzer/src/utilities/cancellation.dart'; |
| import 'package:collection/collection.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import '../resolution/context_collection_resolution.dart'; |
| import '../resolution/node_text_expectations.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(SearchTest); |
| defineReflectiveTests(SearchMultipleDriversTest); |
| defineReflectiveTests(UpdateNodeTextExpectations); |
| }); |
| } |
| |
| @reflectiveTest |
| class SearchMultipleDriversTest extends PubPackageResolutionTest { |
| @override |
| List<String> get collectionIncludedPaths => |
| [workspaceRootPath, otherPackageRootPath]; |
| |
| AnalysisDriver get driver => driverFor(testFile); |
| |
| String get otherPackageRootPath => '$workspaceRootPath/other'; |
| |
| test_declarations_searchesFilesOnlyOnce() async { |
| // Create another driver to search in to ensure we don't get dupe results. |
| var otherFile = newFile(convertPath('$otherPackageRootPath/main.dart'), ''); |
| var otherDriver = driverFor(otherFile); |
| var results = WorkspaceSymbols(); |
| |
| // Search both drivers. |
| await FindDeclarations( |
| [driver, otherDriver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: OperationPerformanceImpl('<root>'), |
| ).compute(); |
| |
| // Ensure only one result for an SDK class, and that the file was tracked as searched. |
| var declarations = results.declarations; |
| expect(declarations.where((element) => element.name == 'Duration'), |
| hasLength(1)); |
| } |
| } |
| |
| @reflectiveTest |
| class SearchTest extends PubPackageResolutionTest { |
| final OperationPerformanceImpl performance = |
| OperationPerformanceImpl('<root>'); |
| |
| AnalysisDriver get driver => driverFor(testFile); |
| |
| String get testUriStr => 'package:test/test.dart'; |
| |
| void assertDeclarationsText( |
| WorkspaceSymbols symbols, |
| Map<File, String> inFiles, |
| String expected, |
| ) { |
| var actual = _getDeclarationsText(symbols, inFiles); |
| if (actual != expected) { |
| print(actual); |
| NodeTextExpectationsCollector.add(actual); |
| } |
| expect(actual, expected); |
| } |
| |
| Future<void> assertElementReferencesText( |
| Element element, |
| String expected, |
| ) async { |
| var searchedFiles = SearchedFiles(); |
| var results = await driver.search.references(element, searchedFiles); |
| var actual = _getSearchResultsText(results); |
| if (actual != expected) { |
| print(actual); |
| NodeTextExpectationsCollector.add(actual); |
| } |
| expect(actual, expected); |
| } |
| |
| Future<void> assertUnresolvedMemberReferencesText( |
| String name, |
| String expected, |
| ) async { |
| var searchedFiles = SearchedFiles(); |
| var results = |
| await driver.search.unresolvedMemberReferences(name, searchedFiles); |
| var actual = _getSearchResultsText(results); |
| if (actual != expected) { |
| print(actual); |
| NodeTextExpectationsCollector.add(actual); |
| } |
| expect(actual, expected); |
| } |
| |
| test_classMembers_class() async { |
| await resolveTestCode(''' |
| class A { |
| test() {} |
| } |
| class B { |
| int test = 1; |
| int testTwo = 2; |
| main() { |
| int test = 3; |
| } |
| } |
| '''); |
| expect( |
| await _findClassMembers('test'), |
| unorderedEquals([ |
| findElement.method('test', of: 'A'), |
| findElement.field('test', of: 'B'), |
| ]), |
| ); |
| } |
| |
| test_classMembers_enum() async { |
| await resolveTestCode(''' |
| enum E1 { |
| v; |
| void test() {} |
| } |
| |
| enum E2 { |
| v; |
| final int test = 0; |
| } |
| '''); |
| expect( |
| await _findClassMembers('test'), |
| unorderedEquals([ |
| findElement.method('test', of: 'E1'), |
| findElement.field('test', of: 'E2'), |
| ]), |
| ); |
| } |
| |
| test_classMembers_importNotDart() async { |
| await resolveTestCode(''' |
| import 'not-dart.txt'; |
| '''); |
| expect(await _findClassMembers('test'), isEmpty); |
| } |
| |
| test_classMembers_mixin() async { |
| await resolveTestCode(''' |
| mixin A { |
| test() {} |
| } |
| mixin B { |
| int test = 1; |
| int testTwo = 2; |
| main() { |
| int test = 3; |
| } |
| } |
| '''); |
| expect( |
| await _findClassMembers('test'), |
| unorderedEquals([ |
| findElement.method('test', of: 'A'), |
| findElement.field('test', of: 'B'), |
| ]), |
| ); |
| } |
| |
| test_declarations_cancel() async { |
| await resolveTestCode(''' |
| class C { |
| int f; |
| C(); |
| C.named(); |
| int get g => 0; |
| void set s(_) {} |
| void m() {} |
| } |
| '''); |
| var results = WorkspaceSymbols(); |
| var token = CancelableToken(); |
| var searchFuture = FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(token); |
| token.cancel(); |
| await searchFuture; |
| expect(results.cancelled, isTrue); |
| } |
| |
| test_declarations_class() async { |
| await resolveTestCode(''' |
| class C { |
| int f; |
| C(); |
| C.named(); |
| int get g => 0; |
| void set s(_) {} |
| void m() {} |
| } |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| CLASS C |
| offset: 6 1:7 |
| codeOffset: 0 + 91 |
| FIELD f |
| offset: 16 2:7 |
| codeOffset: 12 + 5 |
| className: C |
| CONSTRUCTOR <unnamed> |
| offset: 21 3:3 |
| codeOffset: 21 + 4 |
| className: C |
| parameters: () |
| CONSTRUCTOR named |
| offset: 30 4:5 |
| codeOffset: 28 + 10 |
| className: C |
| parameters: () |
| GETTER g |
| offset: 49 5:11 |
| codeOffset: 41 + 15 |
| className: C |
| SETTER s |
| offset: 68 6:12 |
| codeOffset: 59 + 16 |
| className: C |
| parameters: (dynamic _) |
| METHOD m |
| offset: 83 7:8 |
| codeOffset: 78 + 11 |
| className: C |
| parameters: () |
| '''); |
| } |
| |
| test_declarations_discover() async { |
| var aaaPackageRootPath = '$packagesRootPath/aaa'; |
| var bbbPackageRootPath = '$packagesRootPath/bbb'; |
| var cccPackageRootPath = '$packagesRootPath/ccc'; |
| var aaaFilePath = convertPath('$aaaPackageRootPath/lib/a.dart'); |
| var bbbFilePath = convertPath('$bbbPackageRootPath/lib/b.dart'); |
| var cccFilePath = convertPath('$cccPackageRootPath/lib/c.dart'); |
| |
| writeTestPackageConfig( |
| PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaPackageRootPath) |
| ..add(name: 'bbb', rootPath: bbbPackageRootPath), |
| ); |
| |
| var file_a = newFile(aaaFilePath, 'class A {}'); |
| var file_b = newFile(bbbFilePath, 'class B {}'); |
| var file_c = newFile(cccFilePath, 'class C {}'); |
| |
| await resolveTestCode('class T {}'); |
| |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| |
| assertDeclarationsText(results, { |
| testFile: 'testFile', |
| file_a: 'file_a', |
| file_b: 'file_b', |
| file_c: 'file_c', |
| }, r''' |
| testFile |
| CLASS T |
| offset: 6 1:7 |
| codeOffset: 0 + 10 |
| file_a |
| CLASS A |
| offset: 6 1:7 |
| codeOffset: 0 + 10 |
| file_b |
| CLASS B |
| offset: 6 1:7 |
| codeOffset: 0 + 10 |
| '''); |
| } |
| |
| test_declarations_enum() async { |
| await resolveTestCode(''' |
| enum E { |
| a, bb, ccc |
| } |
| '''); |
| |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| ENUM E |
| offset: 5 1:6 |
| codeOffset: 0 + 23 |
| ENUM_CONSTANT a |
| offset: 11 2:3 |
| codeOffset: 11 + 1 |
| ENUM_CONSTANT bb |
| offset: 14 2:6 |
| codeOffset: 14 + 2 |
| ENUM_CONSTANT ccc |
| offset: 18 2:10 |
| codeOffset: 18 + 3 |
| '''); |
| } |
| |
| test_declarations_extension() async { |
| await resolveTestCode(''' |
| extension E on int { |
| int f; |
| int get g => 0; |
| void set s(_) {} |
| void m() {} |
| } |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| EXTENSION E |
| offset: 10 1:11 |
| codeOffset: 0 + 82 |
| FIELD f |
| offset: 27 2:7 |
| codeOffset: 23 + 5 |
| GETTER g |
| offset: 40 3:11 |
| codeOffset: 32 + 15 |
| SETTER s |
| offset: 59 4:12 |
| codeOffset: 50 + 16 |
| parameters: (dynamic _) |
| METHOD m |
| offset: 74 5:8 |
| codeOffset: 69 + 11 |
| parameters: () |
| '''); |
| } |
| |
| test_declarations_extensionType() async { |
| await resolveTestCode(''' |
| extension type E(int it) { |
| int get g => 0; |
| void set s(_) {} |
| void m() {} |
| } |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| EXTENSION_TYPE E |
| offset: 15 1:16 |
| codeOffset: 0 + 79 |
| CONSTRUCTOR <unnamed> |
| offset: 15 1:16 |
| codeOffset: 16 + 8 |
| className: E |
| parameters: (int it) |
| FIELD it |
| offset: 21 1:22 |
| codeOffset: 17 + 6 |
| className: E |
| GETTER g |
| offset: 37 2:11 |
| codeOffset: 29 + 15 |
| className: E |
| SETTER s |
| offset: 56 3:12 |
| codeOffset: 47 + 16 |
| className: E |
| parameters: (dynamic _) |
| METHOD m |
| offset: 71 4:8 |
| codeOffset: 66 + 11 |
| className: E |
| parameters: () |
| '''); |
| } |
| |
| test_declarations_fuzzyMatch() async { |
| await resolveTestCode(''' |
| class A {} |
| class B {} |
| class C {} |
| class D {} |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| 'A', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| CLASS A |
| offset: 6 1:7 |
| codeOffset: 0 + 10 |
| '''); |
| } |
| |
| test_declarations_maxResults() async { |
| await resolveTestCode(''' |
| class A {} |
| class B {} |
| class C {} |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| 2, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| expect(results.declarations, hasLength(2)); |
| } |
| |
| test_declarations_mixin() async { |
| await resolveTestCode(''' |
| mixin M { |
| int f; |
| int get g => 0; |
| void set s(_) {} |
| void m() {} |
| } |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| MIXIN M |
| offset: 6 1:7 |
| codeOffset: 0 + 71 |
| FIELD f |
| offset: 16 2:7 |
| codeOffset: 12 + 5 |
| mixinName: M |
| GETTER g |
| offset: 29 3:11 |
| codeOffset: 21 + 15 |
| mixinName: M |
| SETTER s |
| offset: 48 4:12 |
| codeOffset: 39 + 16 |
| mixinName: M |
| parameters: (dynamic _) |
| METHOD m |
| offset: 63 5:8 |
| codeOffset: 58 + 11 |
| mixinName: M |
| parameters: () |
| '''); |
| } |
| |
| test_declarations_onlyForFile() async { |
| newFile('$testPackageLibPath/a.dart', 'class A {}'); |
| var b = newFile('$testPackageLibPath/b.dart', 'class B {}'); |
| |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| onlyForFile: b.path, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| expect(results.files, [b.path]); |
| |
| assertDeclarationsText(results, {testFile: 'testFile', b: 'file_b'}, r''' |
| file_b |
| CLASS B |
| offset: 6 1:7 |
| codeOffset: 0 + 10 |
| '''); |
| } |
| |
| test_declarations_parameters() async { |
| await resolveTestCode(''' |
| class C { |
| int get g => 0; |
| void m(int a, double b) {} |
| } |
| void f(bool a, String b) {} |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| CLASS C |
| offset: 6 1:7 |
| codeOffset: 0 + 58 |
| GETTER g |
| offset: 20 2:11 |
| codeOffset: 12 + 15 |
| className: C |
| METHOD m |
| offset: 35 3:8 |
| codeOffset: 30 + 26 |
| className: C |
| parameters: (int a, double b) |
| FUNCTION f |
| offset: 64 5:6 |
| codeOffset: 59 + 27 |
| parameters: (bool a, String b) |
| '''); |
| } |
| |
| test_declarations_parameters_functionTyped() async { |
| await resolveTestCode(''' |
| void f1(bool a(int b, String c)) {} |
| void f2(a(b, c)) {} |
| void f3(bool Function(int a, String b) c) {} |
| void f4(bool Function(int, String) a) {} |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| FUNCTION f1 |
| offset: 5 1:6 |
| codeOffset: 0 + 35 |
| parameters: (bool Function(int, String) a) |
| FUNCTION f2 |
| offset: 41 2:6 |
| codeOffset: 36 + 19 |
| parameters: (dynamic Function(dynamic, dynamic) a) |
| FUNCTION f3 |
| offset: 61 3:6 |
| codeOffset: 56 + 44 |
| parameters: (bool Function(int, String) c) |
| FUNCTION f4 |
| offset: 106 4:6 |
| codeOffset: 101 + 40 |
| parameters: (bool Function(int, String) a) |
| '''); |
| } |
| |
| test_declarations_parameters_typeArguments() async { |
| await resolveTestCode(''' |
| class A<T, T2> { |
| void m1(Map<int, String> a) {} |
| void m2<U>(Map<T, U> a) {} |
| void m3<U1, U2>(Map<Map<T2, U2>, Map<U1, T>> a) {} |
| } |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| CLASS A |
| offset: 6 1:7 |
| codeOffset: 0 + 133 |
| METHOD m1 |
| offset: 24 2:8 |
| codeOffset: 19 + 30 |
| className: A |
| parameters: (Map<int, String> a) |
| METHOD m2 |
| offset: 57 3:8 |
| codeOffset: 52 + 26 |
| className: A |
| parameters: (Map<T, U> a) |
| METHOD m3 |
| offset: 86 4:8 |
| codeOffset: 81 + 50 |
| className: A |
| parameters: (Map<Map<T2, U2>, Map<U1, T>> a) |
| '''); |
| } |
| |
| test_declarations_top() async { |
| await resolveTestCode(''' |
| int get g => 0; |
| void set s(_) {} |
| void f(int p) {} |
| int v; |
| typedef void tf1(); |
| typedef tf2<T> = int Function<S>(T tp, S sp); |
| '''); |
| var results = WorkspaceSymbols(); |
| await FindDeclarations( |
| [driver], |
| results, |
| '', |
| null, |
| ownedFiles: analysisContextCollection.ownedFiles, |
| performance: performance, |
| ).compute(); |
| assertDeclarationsText(results, {testFile: 'testFile'}, r''' |
| testFile |
| GETTER g |
| offset: 8 1:9 |
| codeOffset: 0 + 15 |
| SETTER s |
| offset: 25 2:10 |
| codeOffset: 16 + 16 |
| parameters: (dynamic _) |
| FUNCTION f |
| offset: 38 3:6 |
| codeOffset: 33 + 16 |
| parameters: (int p) |
| VARIABLE v |
| offset: 54 4:5 |
| codeOffset: 50 + 5 |
| TYPE_ALIAS tf1 |
| offset: 70 5:14 |
| codeOffset: 57 + 19 |
| TYPE_ALIAS tf2 |
| offset: 85 6:9 |
| codeOffset: 77 + 45 |
| '''); |
| } |
| |
| test_issue49951_references_dontAddToKnown_unrelated() async { |
| var myRoot = newFolder('$workspaceRootPath/packages/my'); |
| |
| var myFile = newFile('${myRoot.path}/lib/my.dart', r''' |
| class A {} |
| '''); |
| |
| // Configure `package:my`. |
| writePackageConfig( |
| myRoot.path, |
| PackageConfigFileBuilder()..add(name: 'my', rootPath: myRoot.path), |
| ); |
| |
| var myDriver = driverFor(myFile); |
| var mySession = contextFor(myFile).currentSession; |
| var libraryElementResult = |
| await mySession.getLibraryByUri('package:my/my.dart'); |
| libraryElementResult as LibraryElementResult; |
| |
| var A = libraryElementResult.element.getClass('A')!; |
| |
| var searchedFiles = SearchedFiles(); |
| searchedFiles.ownAnalyzed(myDriver.search); |
| |
| var testDriver = driverFor(testFile); |
| |
| // No references, but this is not the most important. |
| var references = await testDriver.search.references(A, searchedFiles); |
| expect(references, isEmpty); |
| |
| // We should not add the file to known files. It is not in the |
| // `package:test` itself, and not in a package from its package config. |
| // So, it is absolutely unrelated to `package:test`. |
| for (var knowFile in testDriver.fsState.knownFiles) { |
| if (knowFile.path == myFile.path) { |
| fail('The file should not be added.'); |
| } |
| } |
| } |
| |
| test_searchMemberReferences_qualified_resolved() async { |
| await resolveTestCode(''' |
| class C { |
| var test; |
| } |
| main(C c) { |
| c.test; |
| c.test = 1; |
| c.test += 2; |
| c.test(); |
| } |
| '''); |
| |
| await assertUnresolvedMemberReferencesText('test', ''); |
| } |
| |
| test_searchMemberReferences_qualified_unresolved() async { |
| await resolveTestCode(''' |
| void f(p) { |
| p.test; |
| p.test = 1; |
| p.test += 2; |
| p.test(); |
| } |
| '''); |
| |
| await assertUnresolvedMemberReferencesText('test', r''' |
| self::@function::f |
| 16 2:5 |test| READ qualified unresolved |
| 26 3:5 |test| WRITE qualified unresolved |
| 40 4:5 |test| READ_WRITE qualified unresolved |
| 55 5:5 |test| INVOCATION qualified unresolved |
| '''); |
| } |
| |
| test_searchMemberReferences_unqualified_resolved() async { |
| await resolveTestCode(''' |
| class C { |
| var test; |
| main() { |
| test; |
| test = 1; |
| test += 2; |
| test(); |
| } |
| } |
| '''); |
| |
| await assertUnresolvedMemberReferencesText('test', ''); |
| } |
| |
| test_searchMemberReferences_unqualified_unresolved() async { |
| await resolveTestCode(''' |
| class C { |
| main() { |
| print(test); |
| test = 1; |
| test += 2; |
| test(); |
| } |
| } |
| '''); |
| |
| await assertUnresolvedMemberReferencesText('test', r''' |
| self::@class::C::@method::main |
| 31 3:11 |test| READ unresolved |
| 42 4:5 |test| WRITE unresolved |
| 56 5:5 |test| READ_WRITE unresolved |
| 71 6:5 |test| INVOCATION unresolved |
| '''); |
| } |
| |
| test_searchReferences_class_constructor_declaredInAugmentation() async { |
| newFile('$testPackageLibPath/a.dart', r''' |
| augment library 'test.dart'; |
| |
| augment class A { |
| A.named(); |
| } |
| '''); |
| |
| await resolveTestCode(''' |
| import augment 'a.dart'; |
| |
| class A { |
| void foo() { |
| A.named(); |
| } |
| } |
| |
| void f() { |
| A.named(); |
| } |
| '''); |
| |
| var A = findElement.class_('A'); |
| var element = A.augmented.constructors.single; |
| expect(element.name, 'named'); |
| |
| await assertElementReferencesText(element, r''' |
| self::@class::A::@method::foo |
| 56 5:6 |.named| INVOCATION qualified |
| self::@function::f |
| 87 10:4 |.named| INVOCATION qualified |
| '''); |
| } |
| |
| test_searchReferences_class_getter_in_objectPattern() async { |
| await resolveTestCode(''' |
| void f(Object? x) { |
| if (x case A(foo: 0)) {} |
| if (x case A(: var foo)) {} |
| } |
| |
| class A { |
| int get foo => 0; |
| } |
| '''); |
| var element = findElement.getter('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 35 2:16 |foo| REFERENCE qualified |
| 62 3:16 || REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_class_method_in_objectPattern() async { |
| await resolveTestCode(''' |
| void f(Object? x) { |
| if (x case A(foo: _)) {} |
| if (x case A(: var foo)) {} |
| } |
| |
| class A { |
| void foo() {} |
| } |
| '''); |
| var element = findElement.method('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 35 2:16 |foo| REFERENCE qualified |
| 62 3:16 || REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_ClassElement_definedInSdk() async { |
| await resolveTestCode(''' |
| import 'dart:math'; |
| Random v1; |
| Random v2; |
| '''); |
| |
| var element = findElement.importFind('dart:math').class_('Random'); |
| await assertElementReferencesText(element, r''' |
| self::@variable::v1 |
| 20 2:1 |Random| REFERENCE |
| self::@variable::v2 |
| 31 3:1 |Random| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ClassElement_definedInside() async { |
| await resolveTestCode(''' |
| class A {}; |
| main(A p) { |
| A v; |
| } |
| class B1 extends A {} |
| class B2 implements A {} |
| class B3 extends Object with A {} |
| List<A> v2 = null; |
| '''); |
| var element = findElement.class_('A'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main::@parameter::p |
| 17 2:6 |A| REFERENCE |
| self::@function::main |
| 26 3:3 |A| REFERENCE |
| self::@class::B1 |
| 50 5:18 |A| REFERENCE |
| self::@class::B2 |
| 75 6:21 |A| REFERENCE |
| self::@class::B3 |
| 109 7:30 |A| REFERENCE |
| self::@variable::v2 |
| 119 8:6 |A| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ClassElement_definedOutside() async { |
| newFile('$testPackageLibPath/lib.dart', r''' |
| class A {}; |
| '''); |
| await resolveTestCode(''' |
| import 'lib.dart'; |
| main(A p) { |
| A v; |
| } |
| '''); |
| var element = findNode.namedType('A p').element!; |
| await assertElementReferencesText(element, r''' |
| self::@function::main::@parameter::p |
| 24 2:6 |A| REFERENCE |
| self::@function::main |
| 33 3:3 |A| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ClassElement_enum() async { |
| await resolveTestCode(''' |
| enum MyEnum {a} |
| |
| main(MyEnum p) { |
| MyEnum v; |
| MyEnum.a; |
| } |
| '''); |
| var element = findElement.enum_('MyEnum'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main::@parameter::p |
| 22 3:6 |MyEnum| REFERENCE |
| self::@function::main |
| 36 4:3 |MyEnum| REFERENCE |
| 48 5:3 |MyEnum| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ClassElement_inRecordTypeAnnotation_named() async { |
| await resolveTestCode(''' |
| class A {} |
| |
| void f(({int foo, A bar}) r) {} |
| '''); |
| var element = findElement.class_('A'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f::@parameter::r |
| 30 3:19 |A| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ClassElement_inRecordTypeAnnotation_positional() async { |
| await resolveTestCode(''' |
| class A {} |
| |
| void f((int, A) r) {} |
| '''); |
| var element = findElement.class_('A'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f::@parameter::r |
| 25 3:14 |A| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ClassElement_mixin() async { |
| await resolveTestCode(''' |
| mixin A {} |
| class B extends Object with A {} |
| '''); |
| var element = findElement.mixin('A'); |
| await assertElementReferencesText(element, r''' |
| self::@class::B |
| 39 2:29 |A| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ClassElement_typeArgument_ofGenericAnnotation() async { |
| await resolveTestCode(''' |
| class A<T> { |
| const A(); |
| } |
| |
| class B {} |
| |
| @A<B>() |
| void f() {} |
| '''); |
| |
| var element = findElement.class_('B'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 44 7:4 |B| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_CompilationUnitElement() async { |
| newFile('$testPackageLibPath/foo.dart', ''); |
| await resolveTestCode(''' |
| import 'foo.dart'; |
| export 'foo.dart'; |
| '''); |
| var element = findElement.importFind('package:test/foo.dart').unitElement; |
| await assertElementReferencesText(element, r''' |
| self |
| 7 1:8 |'foo.dart'| REFERENCE qualified |
| 26 2:8 |'foo.dart'| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_ConstructorElement_class_named() async { |
| await resolveTestCode(''' |
| /// [new A.named] 1 |
| class A { |
| A.named() {} |
| A.other() : this.named(); |
| } |
| |
| class B extends A { |
| B() : super.named(); |
| factory B.other() = A.named; |
| } |
| |
| void f() { |
| A.named(); |
| A.named; |
| } |
| '''); |
| var element = findElement.constructor('named'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A |
| 10 1:11 |.named| REFERENCE qualified |
| self::@class::A::@constructor::other |
| 63 4:19 |.named| INVOCATION qualified |
| self::@class::B::@constructor::new |
| 109 8:14 |.named| INVOCATION qualified |
| self::@class::B::@constructor::other |
| 142 9:24 |.named| REFERENCE qualified |
| self::@function::f |
| 167 13:4 |.named| INVOCATION qualified |
| 180 14:4 |.named| REFERENCE_BY_CONSTRUCTOR_TEAR_OFF qualified |
| '''); |
| } |
| |
| test_searchReferences_ConstructorElement_class_named_viaTypeAlias() async { |
| await resolveTestCode(''' |
| class A<T> { |
| A.named(); |
| } |
| |
| typedef B = A<int>; |
| |
| void f() { |
| B.named(); |
| B.named; |
| } |
| '''); |
| |
| var element = findElement.constructor('named'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 64 8:4 |.named| INVOCATION qualified |
| 77 9:4 |.named| REFERENCE_BY_CONSTRUCTOR_TEAR_OFF qualified |
| '''); |
| } |
| |
| test_searchReferences_ConstructorElement_class_unnamed_declared() async { |
| await resolveTestCode(''' |
| /// [new A] 1 |
| class A { |
| A() {} |
| A.other() : this(); |
| } |
| |
| class B extends A { |
| B() : super(); |
| factory B.other() = A; |
| } |
| |
| void f() { |
| A(); |
| A.new; |
| } |
| '''); |
| var element = findElement.unnamedConstructor('A'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A |
| 10 1:11 || REFERENCE qualified |
| self::@class::A::@constructor::other |
| 51 4:19 || INVOCATION qualified |
| self::@class::B::@constructor::new |
| 91 8:14 || INVOCATION qualified |
| self::@class::B::@constructor::other |
| 118 9:24 || REFERENCE qualified |
| self::@function::f |
| 137 13:4 || INVOCATION qualified |
| 144 14:4 |.new| REFERENCE_BY_CONSTRUCTOR_TEAR_OFF qualified |
| '''); |
| } |
| |
| test_searchReferences_ConstructorElement_class_unnamed_otherFile() async { |
| String other = convertPath('$testPackageLibPath/other.dart'); |
| String otherCode = ''' |
| import 'test.dart'; |
| |
| void f() { |
| A(); |
| } |
| '''; |
| newFile(other, otherCode); |
| |
| await resolveTestCode(''' |
| class A { |
| A() {} |
| } |
| '''); |
| var element = findElement.unnamedConstructor('A'); |
| await assertElementReferencesText(element, r''' |
| package:test/other.dart::@unit::package:test/other.dart::@function::f |
| 35 4:4 || INVOCATION qualified |
| '''); |
| } |
| |
| test_searchReferences_ConstructorElement_class_unnamed_synthetic() async { |
| await resolveTestCode(''' |
| /// [new A] 1 |
| class A {} |
| |
| class B extends A { |
| B() : super(); |
| factory B.other() = A; |
| } |
| |
| void f() { |
| A(); |
| A.new; |
| } |
| '''); |
| var element = findElement.unnamedConstructor('A'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A |
| 10 1:11 || REFERENCE qualified |
| self::@class::B::@constructor::new |
| 59 5:14 || INVOCATION qualified |
| self::@class::B::@constructor::other |
| 86 6:24 || REFERENCE qualified |
| self::@function::f |
| 105 10:4 || INVOCATION qualified |
| 112 11:4 |.new| REFERENCE_BY_CONSTRUCTOR_TEAR_OFF qualified |
| '''); |
| } |
| |
| test_searchReferences_ConstructorElement_enum_named() async { |
| await resolveTestCode(''' |
| /// [new E.named] 1 |
| enum E { |
| v.named(); |
| const E.named(); |
| const E.other() : this.named(); |
| } |
| '''); |
| var element = findElement.constructor('named'); |
| await assertElementReferencesText(element, r''' |
| self::@enum::E |
| 10 1:11 |.named| REFERENCE qualified |
| self::@enum::E::@field::v |
| 32 3:4 |.named| INVOCATION qualified |
| self::@enum::E::@constructor::other |
| 85 5:25 |.named| INVOCATION qualified |
| '''); |
| } |
| |
| test_searchReferences_ConstructorElement_enum_unnamed_declared() async { |
| await resolveTestCode(''' |
| /// [new E] |
| enum E { |
| v1, |
| v2(), |
| v3.new(); |
| const E(); |
| const E.other() : this(); |
| } |
| '''); |
| var element = findElement.unnamedConstructor('E'); |
| await assertElementReferencesText(element, r''' |
| self::@enum::E |
| 10 1:11 || REFERENCE qualified |
| self::@enum::E::@field::v1 |
| 25 3:5 || INVOCATION_BY_ENUM_CONSTANT_WITHOUT_ARGUMENTS qualified |
| self::@enum::E::@field::v2 |
| 31 4:5 || INVOCATION qualified |
| self::@enum::E::@field::v3 |
| 39 5:5 |.new| INVOCATION qualified |
| self::@enum::E::@constructor::other |
| 84 7:25 || INVOCATION qualified |
| '''); |
| } |
| |
| test_searchReferences_ConstructorElement_enum_unnamed_synthetic() async { |
| await resolveTestCode(''' |
| /// [new E] |
| enum E { |
| v1, |
| v2(), |
| v3.new(); |
| } |
| '''); |
| var element = findElement.unnamedConstructor('E'); |
| await assertElementReferencesText(element, r''' |
| self::@enum::E |
| 10 1:11 || REFERENCE qualified |
| self::@enum::E::@field::v1 |
| 25 3:5 || INVOCATION_BY_ENUM_CONSTANT_WITHOUT_ARGUMENTS qualified |
| self::@enum::E::@field::v2 |
| 31 4:5 || INVOCATION qualified |
| self::@enum::E::@field::v3 |
| 39 5:5 |.new| INVOCATION qualified |
| '''); |
| } |
| |
| test_searchReferences_ExtensionElement() async { |
| await resolveTestCode(''' |
| extension E on int { |
| void foo() {} |
| static void bar() {} |
| } |
| |
| main() { |
| E(0).foo(); |
| E.bar(); |
| } |
| '''); |
| var element = findElement.extension_('E'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 74 7:3 |E| REFERENCE |
| 88 8:3 |E| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ExtensionTypeElement() async { |
| await resolveTestCode(''' |
| extension type E(int it) { |
| static void bar() {} |
| } |
| |
| void f(E e) { |
| E.bar(); |
| } |
| '''); |
| var element = findElement.extensionType('E'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f::@parameter::e |
| 60 5:8 |E| REFERENCE |
| self::@function::f |
| 69 6:3 |E| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_FieldElement_class() async { |
| await resolveTestCode(''' |
| class A { |
| var field; |
| A({this.field}); |
| main() { |
| new A(field: 1); |
| // getter |
| field; |
| this.field; |
| field(); |
| this.field(); |
| // setter |
| field = 2; |
| this.field = 3; |
| } |
| } |
| '''); |
| var element = findElement.field('field'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A::@constructor::new::@parameter::field |
| 33 3:11 |field| WRITE qualified |
| self::@class::A::@method::main |
| 92 7:5 |field| READ |
| 108 8:10 |field| READ qualified |
| 119 9:5 |field| READ |
| 137 10:10 |field| READ qualified |
| 164 12:5 |field| WRITE |
| 184 13:10 |field| WRITE qualified |
| '''); |
| } |
| |
| test_searchReferences_FieldElement_class_synthetic() async { |
| await resolveTestCode(''' |
| class A { |
| get field => null; |
| set field(x) {} |
| main() { |
| // getter |
| field; |
| this.field; |
| field(); |
| this.field(); |
| // setter |
| field = 2; |
| this.field = 3; |
| } |
| } |
| '''); |
| var element = findElement.field('field'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A::@method::main |
| 78 6:5 |field| READ |
| 94 7:10 |field| READ qualified |
| 105 8:5 |field| READ |
| 123 9:10 |field| READ qualified |
| 150 11:5 |field| WRITE |
| 170 12:10 |field| WRITE qualified |
| '''); |
| } |
| |
| test_searchReferences_FieldElement_enum() async { |
| await resolveTestCode(''' |
| enum E { |
| v(field: 0); |
| final int field; |
| const E({required this.field}); |
| } |
| |
| void f(E e) { |
| e.field; |
| } |
| '''); |
| var element = findElement.field('field'); |
| await assertElementReferencesText(element, r''' |
| self::@enum::E::@constructor::new::@parameter::field |
| 68 4:26 |field| WRITE qualified |
| self::@function::f |
| 98 8:5 |field| READ qualified |
| '''); |
| } |
| |
| test_searchReferences_FieldElement_enum_values() async { |
| await resolveTestCode(''' |
| enum MyEnum { |
| A, B, C |
| } |
| main() { |
| MyEnum.A.index; |
| MyEnum.values; |
| MyEnum.A; |
| MyEnum.B; |
| } |
| '''); |
| var index = typeProvider.enumElement!.getField('index')!; |
| await assertElementReferencesText(index, r''' |
| self::@function::main |
| 46 5:12 |index| READ qualified |
| '''); |
| |
| var values = findElement.field('values'); |
| await assertElementReferencesText(values, r''' |
| self::@function::main |
| 62 6:10 |values| READ qualified |
| '''); |
| |
| var A = findElement.field('A'); |
| await assertElementReferencesText(A, r''' |
| self::@function::main |
| 44 5:10 |A| READ qualified |
| 79 7:10 |A| READ qualified |
| '''); |
| |
| var B = findElement.field('B'); |
| await assertElementReferencesText(B, r''' |
| self::@function::main |
| 91 8:10 |B| READ qualified |
| '''); |
| } |
| |
| test_searchReferences_FunctionElement() async { |
| await resolveTestCode(''' |
| test() {} |
| main() { |
| test(); |
| test; |
| } |
| '''); |
| var element = findElement.function('test'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 21 3:3 |test| INVOCATION |
| 31 4:3 |test| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_FunctionElement_local() async { |
| await resolveTestCode(''' |
| main() { |
| test() {} |
| test(); |
| test; |
| } |
| '''); |
| var element = findElement.localFunction('test'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 23 3:3 |test| INVOCATION |
| 33 4:3 |test| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ImportElement_noPrefix() async { |
| await resolveTestCode(''' |
| import 'dart:math' show max, pi, Random hide min; |
| export 'dart:math' show max, pi, Random hide min; |
| main() { |
| pi; |
| new Random(); |
| max(1, 2); |
| } |
| Random bar() => null; |
| '''); |
| var element = findElement.import('dart:math', mustBeUnique: false); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 111 4:3 || REFERENCE |
| 121 5:7 || REFERENCE |
| 133 6:3 || REFERENCE |
| self::@function::bar |
| 146 8:1 || REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ImportElement_noPrefix_inPackage() async { |
| var aaaPackageRootPath = '$packagesRootPath/aaa'; |
| var aaaFilePath = convertPath('$aaaPackageRootPath/lib/a.dart'); |
| |
| writeTestPackageConfig( |
| PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaPackageRootPath), |
| ); |
| |
| fileForContextSelection = testFile; |
| |
| await resolveFileCode(aaaFilePath, ''' |
| import 'dart:math' show max, pi, Random hide min; |
| export 'dart:math' show max, pi, Random hide min; |
| main() { |
| pi; |
| new Random(); |
| max(1, 2); |
| } |
| Random bar() => null; |
| '''); |
| |
| var element = findElement.import('dart:math'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 111 4:3 || REFERENCE |
| 121 5:7 || REFERENCE |
| 133 6:3 || REFERENCE |
| self::@function::bar |
| 146 8:1 || REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ImportElement_withPrefix() async { |
| await resolveTestCode(''' |
| import 'dart:math' as math show max, pi, Random hide min; |
| export 'dart:math' show max, pi, Random hide min; |
| main() { |
| math.pi; |
| new math.Random(); |
| math.max(1, 2); |
| } |
| math.Random bar() => null; |
| '''); |
| var element = findElement.import('dart:math', mustBeUnique: false); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 119 4:3 |math.| REFERENCE |
| 134 5:7 |math.| REFERENCE |
| 151 6:3 |math.| REFERENCE |
| self::@function::bar |
| 169 8:1 |math.| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_ImportElement_withPrefix_forMultipleImports() async { |
| await resolveTestCode(''' |
| import 'dart:async' as p; |
| import 'dart:math' as p; |
| main() { |
| p.Random r; |
| p.Future f; |
| } |
| '''); |
| { |
| var element = findElement.import('dart:async'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 76 5:3 |p.| REFERENCE |
| '''); |
| } |
| { |
| var element = findElement.import('dart:math'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 62 4:3 |p.| REFERENCE |
| '''); |
| } |
| } |
| |
| test_searchReferences_LabelElement() async { |
| await resolveTestCode(''' |
| main() { |
| label: |
| while (true) { |
| if (true) { |
| break label; |
| } |
| break label; |
| } |
| } |
| '''); |
| var element = findElement.label('label'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 61 5:13 |label| REFERENCE |
| 84 7:11 |label| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_LibraryElement() async { |
| newFile('$testPackageLibPath/unitA.dart', 'part of lib;'); |
| newFile('$testPackageLibPath/unitB.dart', 'part of lib;'); |
| await resolveTestCode(''' |
| library lib; |
| part 'unitA.dart'; |
| part 'unitB.dart'; |
| '''); |
| var element = result.libraryElement; |
| await assertElementReferencesText(element, r''' |
| self::@unit::package:test/unitA.dart |
| 8 1:9 |lib| REFERENCE |
| self::@unit::package:test/unitB.dart |
| 8 1:9 |lib| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_LibraryElement_inPackage() async { |
| var aaaPackageRootPath = '$packagesRootPath/aaa'; |
| |
| writeTestPackageConfig( |
| PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaPackageRootPath), |
| ); |
| |
| var libPath = convertPath('$aaaPackageRootPath/lib/a.dart'); |
| var partPathA = convertPath('$aaaPackageRootPath/lib/unitA.dart'); |
| var partPathB = convertPath('$aaaPackageRootPath/lib/unitB.dart'); |
| |
| newFile(partPathA, 'part of lib;'); |
| newFile(partPathB, 'part of lib;'); |
| |
| fileForContextSelection = testFile; |
| |
| await resolveFileCode(libPath, ''' |
| library lib; |
| part 'unitA.dart'; |
| part 'unitB.dart'; |
| '''); |
| var element = result.libraryElement; |
| await assertElementReferencesText(element, r''' |
| self::@unit::package:aaa/unitA.dart |
| 8 1:9 |lib| REFERENCE |
| self::@unit::package:aaa/unitB.dart |
| 8 1:9 |lib| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_LocalVariableElement() async { |
| await resolveTestCode(r''' |
| main() { |
| var v; |
| v = 1; |
| v += 2; |
| v; |
| v(); |
| } |
| '''); |
| var element = findElement.localVar('v'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 20 3:3 |v| WRITE |
| 29 4:3 |v| READ_WRITE |
| 39 5:3 |v| READ |
| 44 6:3 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_LocalVariableElement_inForEachElement_expressionBody() async { |
| await resolveTestCode(''' |
| Object f() => [ |
| for (var v in []) v, |
| ]; |
| '''); |
| var element = findElement.localVar('v'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 36 2:21 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_LocalVariableElement_inForEachElement_inBlock() async { |
| await resolveTestCode(''' |
| Object f() { |
| { |
| return [ |
| for (var v in []) v, |
| ]; |
| } |
| } |
| '''); |
| var element = findElement.localVar('v'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 54 4:25 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_LocalVariableElement_inForEachElement_inFunctionBody() async { |
| await resolveTestCode(''' |
| Object f() { |
| return [ |
| for (var v in []) v, |
| ]; |
| } |
| '''); |
| var element = findElement.localVar('v'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 46 3:23 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_LocalVariableElement_inForEachElement_topLevel() async { |
| await resolveTestCode(''' |
| var x = [ |
| for (var v in []) v, |
| ]; |
| '''); |
| var element = findElement.localVar('v'); |
| await assertElementReferencesText(element, r''' |
| self::@variable::x |
| 30 2:21 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_LocalVariableElement_inForEachLoop() async { |
| await resolveTestCode(''' |
| main() { |
| for (var v in []) { |
| v = 1; |
| v += 2; |
| v; |
| v(); |
| } |
| } |
| '''); |
| var element = findElement.localVar('v'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 35 3:5 |v| WRITE |
| 46 4:5 |v| READ_WRITE |
| 58 5:5 |v| READ |
| 65 6:5 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_LocalVariableElement_inPackage() async { |
| var aaaPackageRootPath = '$packagesRootPath/aaa'; |
| var testPath = convertPath('$aaaPackageRootPath/lib/a.dart'); |
| |
| writeTestPackageConfig( |
| PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaPackageRootPath), |
| ); |
| |
| fileForContextSelection = testFile; |
| |
| await resolveFileCode(testPath, ''' |
| main() { |
| var v; |
| v = 1; |
| v += 2; |
| v; |
| v(); |
| } |
| '''); |
| var element = findElement.localVar('v'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 20 3:3 |v| WRITE |
| 29 4:3 |v| READ_WRITE |
| 39 5:3 |v| READ |
| 44 6:3 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_macroGenerated_references() async { |
| if (!configureWithCommonMacros()) { |
| return; |
| } |
| |
| await resolveTestCode(''' |
| import 'append.dart'; |
| |
| class A {} |
| |
| @DeclareInLibrary('void f() { A; }') |
| class B { |
| void foo() { A; } |
| } |
| '''); |
| |
| var element = findElement.class_('A'); |
| await assertElementReferencesText(element, r''' |
| self::@class::B::@method::foo |
| 97 7:16 |A| REFERENCE |
| self::@augmentation::package:test/test.macro.dart::@function::f |
| 54 3:12 |A| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_MethodElement_class() async { |
| await resolveTestCode(''' |
| class A { |
| m() {} |
| main() { |
| m(); |
| this.m(); |
| m; |
| this.m; |
| } |
| } |
| '''); |
| var element = findElement.method('m'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A::@method::main |
| 34 4:5 |m| INVOCATION |
| 48 5:10 |m| INVOCATION qualified |
| 57 6:5 |m| REFERENCE |
| 69 7:10 |m| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_MethodElement_enum() async { |
| await resolveTestCode(''' |
| enum E { |
| v; |
| void foo() {} |
| void bar() { |
| foo(); |
| this.foo(); |
| } |
| } |
| |
| void f(E e) { |
| e.foo(); |
| e.foo; |
| } |
| '''); |
| var element = findElement.method('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@enum::E::@method::bar |
| 49 5:5 |foo| INVOCATION |
| 65 6:10 |foo| INVOCATION qualified |
| self::@function::f |
| 97 11:5 |foo| INVOCATION qualified |
| 108 12:5 |foo| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_MethodElement_extension_instance() async { |
| await resolveTestCode(''' |
| extension E on int { |
| void foo() {} |
| |
| void bar() { |
| foo(); |
| this.foo(); |
| foo; |
| this.foo; |
| } |
| } |
| |
| main() { |
| E(0).foo(); |
| 0.foo(); |
| E(0).foo; |
| 0.foo; |
| } |
| '''); |
| var element = findElement.method('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@extension::E::@method::bar |
| 57 5:5 |foo| INVOCATION |
| 73 6:10 |foo| INVOCATION qualified |
| 84 7:5 |foo| REFERENCE |
| 98 8:10 |foo| REFERENCE qualified |
| self::@function::main |
| 126 13:8 |foo| INVOCATION qualified |
| 137 14:5 |foo| INVOCATION qualified |
| 151 15:8 |foo| REFERENCE qualified |
| 160 16:5 |foo| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_MethodElement_extension_named() async { |
| await resolveTestCode(''' |
| extension E on int { |
| void foo() {} |
| |
| void bar() { |
| foo(); |
| this.foo(); |
| foo; |
| this.foo; |
| } |
| } |
| '''); |
| var element = findElement.method('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@extension::E::@method::bar |
| 57 5:5 |foo| INVOCATION |
| 73 6:10 |foo| INVOCATION qualified |
| 84 7:5 |foo| REFERENCE |
| 98 8:10 |foo| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_MethodElement_extension_static() async { |
| await resolveTestCode(''' |
| extension E on int { |
| static void foo() {} |
| |
| static void bar() { |
| foo(); |
| foo; |
| } |
| } |
| |
| main() { |
| E.foo(); |
| E.foo; |
| } |
| '''); |
| var element = findElement.method('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@extension::E::@method::bar |
| 71 5:5 |foo| INVOCATION |
| 82 6:5 |foo| REFERENCE |
| self::@function::main |
| 107 11:5 |foo| INVOCATION qualified |
| 118 12:5 |foo| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_MethodElement_extension_unnamed() async { |
| await resolveTestCode(''' |
| extension on int { |
| void foo() {} |
| |
| void bar() { |
| foo(); |
| this.foo(); |
| foo; |
| this.foo; |
| } |
| } |
| '''); |
| var element = findElement.method('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@extension::0::@method::bar |
| 55 5:5 |foo| INVOCATION |
| 71 6:10 |foo| INVOCATION qualified |
| 82 7:5 |foo| REFERENCE |
| 96 8:10 |foo| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_MethodElement_extensionType() async { |
| await resolveTestCode(''' |
| extension type E(int it) { |
| void foo() {} |
| |
| void bar() { |
| foo(); |
| } |
| } |
| |
| void f(E e) { |
| e.foo(); |
| } |
| '''); |
| var element = findElement.method('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@extensionType::E::@method::bar |
| 63 5:5 |foo| INVOCATION |
| self::@function::f |
| 95 10:5 |foo| INVOCATION qualified |
| '''); |
| } |
| |
| test_searchReferences_MethodMember_class() async { |
| await resolveTestCode(''' |
| class A<T> { |
| T m() => null; |
| } |
| main(A<int> a) { |
| a.m(); |
| } |
| '''); |
| var element = findElement.method('m'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 53 5:5 |m| INVOCATION qualified |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_ofConstructor_super_named() async { |
| await resolveTestCode(''' |
| class A { |
| A({required int a}); |
| } |
| class B extends A { |
| B({required super.a}); |
| } |
| '''); |
| var element = findElement.unnamedConstructor('A').parameter('a'); |
| await assertElementReferencesText(element, r''' |
| self::@class::B::@constructor::new::@parameter::a |
| 75 5:21 |a| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_ofConstructor_super_positional() async { |
| await resolveTestCode(''' |
| class A { |
| A(int a); |
| } |
| class B extends A { |
| B(super.a); |
| } |
| '''); |
| var element = findElement.unnamedConstructor('A').parameter('a'); |
| await assertElementReferencesText(element, r''' |
| self::@class::B::@constructor::new::@parameter::a |
| 54 5:11 |a| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_optionalNamed() async { |
| await resolveTestCode(''' |
| foo({p}) { |
| p = 1; |
| p += 2; |
| p; |
| p(); |
| } |
| main() { |
| foo(p: 42); |
| } |
| '''); |
| var element = findElement.parameter('p'); |
| await assertElementReferencesText(element, r''' |
| self::@function::foo |
| 13 2:3 |p| WRITE |
| 22 3:3 |p| READ_WRITE |
| 32 4:3 |p| READ |
| 37 5:3 |p| READ |
| self::@function::main |
| 59 8:7 |p| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_optionalNamed_anywhere() async { |
| await resolveTestCode(''' |
| foo(int a, int b, {p}) { |
| p; |
| } |
| main() { |
| foo(0, p: 1, 2); |
| } |
| '''); |
| var element = findElement.parameter('p'); |
| await assertElementReferencesText(element, r''' |
| self::@function::foo |
| 27 2:3 |p| READ |
| self::@function::main |
| 50 5:10 |p| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_optionalPositional() async { |
| await resolveTestCode(''' |
| foo([p]) { |
| p = 1; |
| p += 2; |
| p; |
| p(); |
| } |
| main() { |
| foo(42); |
| } |
| '''); |
| var element = findElement.parameter('p'); |
| await assertElementReferencesText(element, r''' |
| self::@function::foo |
| 13 2:3 |p| WRITE |
| 22 3:3 |p| READ_WRITE |
| 32 4:3 |p| READ |
| 37 5:3 |p| READ |
| self::@function::main |
| 59 8:7 || REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_requiredNamed() async { |
| await resolveTestCode(''' |
| foo({required int p}) { |
| p = 1; |
| p += 2; |
| p; |
| p(); |
| } |
| main() { |
| foo(p: 42); |
| } |
| '''); |
| var element = findElement.parameter('p'); |
| await assertElementReferencesText(element, r''' |
| self::@function::foo |
| 26 2:3 |p| WRITE |
| 35 3:3 |p| READ_WRITE |
| 45 4:3 |p| READ |
| 50 5:3 |p| READ |
| self::@function::main |
| 72 8:7 |p| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_requiredPositional_ofConstructor() async { |
| await resolveTestCode(''' |
| class C { |
| var f; |
| C(p) : f = p + 1 { |
| p = 2; |
| p += 3; |
| p; |
| p(); |
| } |
| } |
| main() { |
| new C(42); |
| } |
| '''); |
| var element = findElement.parameter('p'); |
| await assertElementReferencesText(element, r''' |
| self::@class::C::@constructor::new |
| 32 3:14 |p| READ |
| 44 4:5 |p| WRITE |
| 55 5:5 |p| READ_WRITE |
| 67 6:5 |p| READ |
| 74 7:5 |p| READ |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_requiredPositional_ofLocalFunction() async { |
| await resolveTestCode(''' |
| main() { |
| foo(p) { |
| p = 1; |
| p += 2; |
| p; |
| p(); |
| } |
| foo(42); |
| } |
| '''); |
| var element = findElement.parameter('p'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 24 3:5 |p| WRITE |
| 35 4:5 |p| READ_WRITE |
| 47 5:5 |p| READ |
| 54 6:5 |p| READ |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_requiredPositional_ofMethod() async { |
| await resolveTestCode(''' |
| class C { |
| foo(p) { |
| p = 1; |
| p += 2; |
| p; |
| p(); |
| } |
| } |
| main(C c) { |
| c.foo(42); |
| } |
| '''); |
| var element = findElement.parameter('p'); |
| await assertElementReferencesText(element, r''' |
| self::@class::C::@method::foo |
| 25 3:5 |p| WRITE |
| 36 4:5 |p| READ_WRITE |
| 48 5:5 |p| READ |
| 55 6:5 |p| READ |
| '''); |
| } |
| |
| test_searchReferences_ParameterElement_requiredPositional_ofTopLevelFunction() async { |
| await resolveTestCode(''' |
| foo(p) { |
| p = 1; |
| p += 2; |
| p; |
| p(); |
| } |
| main() { |
| foo(42); |
| } |
| '''); |
| var element = findElement.parameter('p'); |
| await assertElementReferencesText(element, r''' |
| self::@function::foo |
| 11 2:3 |p| WRITE |
| 20 3:3 |p| READ_WRITE |
| 30 4:3 |p| READ |
| 35 5:3 |p| READ |
| '''); |
| } |
| |
| test_searchReferences_PrefixElement() async { |
| String partCode = r''' |
| part of my_lib; |
| ppp.Future c; |
| '''; |
| newFile('$testPackageLibPath/my_part.dart', partCode); |
| await resolveTestCode(''' |
| library my_lib; |
| import 'dart:async' as ppp; |
| part 'my_part.dart'; |
| main() { |
| ppp.Future a; |
| ppp.Stream b; |
| } |
| '''); |
| var element = findElement.prefix('ppp'); |
| await assertElementReferencesText(element, r''' |
| self::@unit::package:test/my_part.dart::@variable::c |
| 16 2:1 |ppp| REFERENCE |
| self::@function::main |
| 76 5:3 |ppp| REFERENCE |
| 92 6:3 |ppp| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_PrefixElement_extensionOverride() async { |
| newFile('$testPackageLibPath/a.dart', r''' |
| extension E on int { |
| void foo() {} |
| } |
| '''); |
| |
| await resolveTestCode(''' |
| import 'a.dart' as prefix; |
| |
| void f() { |
| prefix.E(0).foo(); |
| } |
| '''); |
| var element = findElement.prefix('prefix'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 41 4:3 |prefix| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_PrefixElement_inPackage() async { |
| var aaaPackageRootPath = '$packagesRootPath/aaa'; |
| |
| writeTestPackageConfig( |
| PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaPackageRootPath), |
| ); |
| |
| fileForContextSelection = testFile; |
| |
| var libPath = convertPath('$aaaPackageRootPath/lib/a.dart'); |
| var partPath = convertPath('$aaaPackageRootPath/lib/my_part.dart'); |
| |
| String partCode = r''' |
| part of my_lib; |
| ppp.Future c; |
| '''; |
| newFile(partPath, partCode); |
| await resolveFileCode(libPath, ''' |
| library my_lib; |
| import 'dart:async' as ppp; |
| part 'my_part.dart'; |
| main() { |
| ppp.Future a; |
| ppp.Stream b; |
| } |
| '''); |
| |
| var element = findElement.prefix('ppp'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 76 5:3 |ppp| REFERENCE |
| 92 6:3 |ppp| REFERENCE |
| self::@unit::package:aaa/my_part.dart::@variable::c |
| 16 2:1 |ppp| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_private_declaredInDefiningUnit() async { |
| String p1 = convertPath('$testPackageLibPath/part1.dart'); |
| String p2 = convertPath('$testPackageLibPath/part2.dart'); |
| String p3 = convertPath('$testPackageLibPath/part3.dart'); |
| String code1 = 'part of lib; _C v1;'; |
| String code2 = 'part of lib; _C v2;'; |
| newFile(p1, code1); |
| newFile(p2, code2); |
| newFile(p3, 'part of lib; int v3;'); |
| |
| await resolveTestCode(''' |
| library lib; |
| part 'part1.dart'; |
| part 'part2.dart'; |
| part 'part3.dart'; |
| class _C {} |
| _C v; |
| '''); |
| var element = findElement.class_('_C'); |
| await assertElementReferencesText(element, r''' |
| self::@unit::package:test/part1.dart::@variable::v1 |
| 13 1:14 |_C| REFERENCE |
| self::@unit::package:test/part2.dart::@variable::v2 |
| 13 1:14 |_C| REFERENCE |
| self::@variable::v |
| 82 6:1 |_C| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_private_declaredInPart() async { |
| String p = convertPath('$testPackageLibPath/lib.dart'); |
| String p1 = convertPath('$testPackageLibPath/part1.dart'); |
| String p2 = convertPath('$testPackageLibPath/part2.dart'); |
| |
| var code = ''' |
| library lib; |
| part 'part1.dart'; |
| part 'part2.dart'; |
| _C v; |
| '''; |
| var code1 = ''' |
| part of lib; |
| class _C {} |
| _C v1; |
| '''; |
| String code2 = 'part of lib; _C v2;'; |
| |
| newFile(p, code); |
| newFile(p1, code1); |
| newFile(p2, code2); |
| |
| await resolveTestCode(code); |
| |
| var element = findElement.partFind('package:test/part1.dart').class_('_C'); |
| await assertElementReferencesText(element, r''' |
| self::@unit::package:test/part1.dart::@variable::v1 |
| 25 3:1 |_C| REFERENCE |
| self::@unit::package:test/part2.dart::@variable::v2 |
| 13 1:14 |_C| REFERENCE |
| self::@variable::v |
| 51 4:1 |_C| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_private_inPackage() async { |
| var aaaPackageRootPath = '$packagesRootPath/aaa'; |
| var testFile = convertPath('$aaaPackageRootPath/lib/a.dart'); |
| var p1 = convertPath('$aaaPackageRootPath/lib/part1.dart'); |
| var p2 = convertPath('$aaaPackageRootPath/lib/part2.dart'); |
| |
| writeTestPackageConfig( |
| PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaPackageRootPath), |
| ); |
| |
| fileForContextSelection = this.testFile; |
| |
| String testCode = ''' |
| library lib; |
| part 'part1.dart'; |
| part 'part2.dart'; |
| class _C {} |
| _C v; |
| '''; |
| String code1 = 'part of lib; _C v1;'; |
| String code2 = 'part of lib; _C v2;'; |
| |
| newFile(p1, code1); |
| newFile(p2, code2); |
| |
| await resolveFileCode(testFile, testCode); |
| |
| var element = findElement.class_('_C'); |
| await assertElementReferencesText(element, r''' |
| self::@variable::v |
| 63 5:1 |_C| REFERENCE |
| self::@unit::package:aaa/part1.dart::@variable::v1 |
| 13 1:14 |_C| REFERENCE |
| self::@unit::package:aaa/part2.dart::@variable::v2 |
| 13 1:14 |_C| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_PropertyAccessor_getter_ofExtension_instance() async { |
| await resolveTestCode(''' |
| extension E on int { |
| int get foo => 0; |
| |
| void bar() { |
| foo; |
| this.foo; |
| } |
| } |
| |
| main() { |
| E(0).foo; |
| 0.foo; |
| } |
| '''); |
| var element = findElement.getter('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@extension::E::@method::bar |
| 61 5:5 |foo| REFERENCE |
| 75 6:10 |foo| REFERENCE qualified |
| self::@function::main |
| 103 11:8 |foo| REFERENCE qualified |
| 112 12:5 |foo| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_PropertyAccessor_setter_ofExtension_instance() async { |
| await resolveTestCode(''' |
| extension E on int { |
| set foo(int _) {} |
| |
| void bar() { |
| foo = 1; |
| this.foo = 2; |
| } |
| } |
| |
| main() { |
| E(0).foo = 3; |
| 0.foo = 4; |
| } |
| '''); |
| var element = findElement.setter('foo'); |
| await assertElementReferencesText(element, r''' |
| self::@extension::E::@method::bar |
| 61 5:5 |foo| REFERENCE |
| 79 6:10 |foo| REFERENCE qualified |
| self::@function::main |
| 111 11:8 |foo| REFERENCE qualified |
| 124 12:5 |foo| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_PropertyAccessorElement_getter() async { |
| await resolveTestCode(''' |
| class A { |
| get ggg => null; |
| main() { |
| ggg; |
| this.ggg; |
| ggg(); |
| this.ggg(); |
| } |
| } |
| '''); |
| var element = findElement.getter('ggg'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A::@method::main |
| 44 4:5 |ggg| REFERENCE |
| 58 5:10 |ggg| REFERENCE qualified |
| 67 6:5 |ggg| REFERENCE |
| 83 7:10 |ggg| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_PropertyAccessorElement_setter() async { |
| await resolveTestCode(''' |
| class A { |
| set s(x) {} |
| main() { |
| s = 1; |
| this.s = 2; |
| } |
| } |
| '''); |
| var element = findElement.setter('s'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A::@method::main |
| 39 4:5 |s| REFERENCE |
| 55 5:10 |s| REFERENCE qualified |
| '''); |
| } |
| |
| test_searchReferences_TopLevelVariableElement() async { |
| newFile('$testPackageLibPath/lib.dart', ''' |
| library lib; |
| var V; |
| '''); |
| await resolveTestCode(''' |
| import 'lib.dart' show V; |
| import 'lib.dart' as pref; |
| main() { |
| pref.V = 1; |
| pref.V; |
| pref.V(); |
| V = 1; |
| V; |
| V(); |
| } |
| '''); |
| var element = findElement |
| .importFind('package:test/lib.dart', mustBeUnique: false) |
| .topVar('V'); |
| await assertElementReferencesText(element, r''' |
| self |
| 23 1:24 |V| REFERENCE qualified |
| self::@function::main |
| 69 4:8 |V| WRITE qualified |
| 83 5:8 |V| READ qualified |
| 93 6:8 |V| READ qualified |
| 100 7:3 |V| WRITE |
| 109 8:3 |V| READ |
| 114 9:3 |V| READ |
| '''); |
| } |
| |
| test_searchReferences_TypeAliasElement() async { |
| await resolveTestCode(''' |
| class A<T> { |
| static int field = 0; |
| static void method() {} |
| } |
| |
| typedef B = A<int>; |
| |
| class C extends B {} |
| |
| void f(B p) { |
| B v; |
| B.field = 1; |
| B.field; |
| B.method(); |
| } |
| '''); |
| |
| var element = findElement.typeAlias('B'); |
| await assertElementReferencesText(element, r''' |
| self::@class::C |
| 103 8:17 |B| REFERENCE |
| self::@function::f::@parameter::p |
| 116 10:8 |B| REFERENCE |
| self::@function::f |
| 125 11:3 |B| REFERENCE |
| 132 12:3 |B| REFERENCE |
| 147 13:3 |B| REFERENCE |
| 158 14:3 |B| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_TypeAliasElement_inConstructorName() async { |
| await resolveTestCode(''' |
| class A<T> {} |
| |
| typedef B = A<int>; |
| |
| void f() { |
| B(); |
| } |
| '''); |
| |
| var element = findElement.typeAlias('B'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 49 6:3 |B| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_TypeParameterElement_ofClass() async { |
| await resolveTestCode(''' |
| class A<T> { |
| foo(T a) {} |
| bar(T b) {} |
| } |
| '''); |
| var element = findElement.typeParameter('T'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A::@method::foo::@parameter::a |
| 19 2:7 |T| REFERENCE |
| self::@class::A::@method::bar::@parameter::b |
| 33 3:7 |T| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_TypeParameterElement_ofEnum() async { |
| await resolveTestCode(''' |
| enum E<T> { |
| v; |
| final T a; |
| void foo(T b) {} |
| } |
| '''); |
| var element = findElement.typeParameter('T'); |
| await assertElementReferencesText(element, r''' |
| self::@enum::E::@field::a |
| 25 3:9 |T| REFERENCE |
| self::@enum::E::@method::foo::@parameter::b |
| 41 4:12 |T| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_TypeParameterElement_ofLocalFunction() async { |
| await resolveTestCode(''' |
| main() { |
| void foo<T>(T a) { |
| void bar(T b) {} |
| } |
| } |
| '''); |
| var element = findElement.typeParameter('T'); |
| await assertElementReferencesText(element, r''' |
| self::@function::main |
| 23 2:15 |T| REFERENCE |
| 43 3:14 |T| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_TypeParameterElement_ofMethod() async { |
| await resolveTestCode(''' |
| class A { |
| foo<T>(T p) {} |
| } |
| '''); |
| var element = findElement.typeParameter('T'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A::@method::foo::@parameter::p |
| 19 2:10 |T| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_TypeParameterElement_ofTopLevelFunction() async { |
| await resolveTestCode(''' |
| foo<T>(T a) { |
| bar(T b) {} |
| } |
| '''); |
| var element = findElement.typeParameter('T'); |
| await assertElementReferencesText(element, r''' |
| self::@function::foo::@parameter::a |
| 7 1:8 |T| REFERENCE |
| self::@function::foo |
| 20 2:7 |T| REFERENCE |
| '''); |
| } |
| |
| test_searchReferences_VariablePatternElement_declaration() async { |
| await resolveTestCode(''' |
| void f(x) { |
| var (v) = x; |
| v = 1; |
| v += 2; |
| v; |
| v(); |
| } |
| '''); |
| var element = findNode.bindPatternVariableElement('v) ='); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 29 3:3 |v| WRITE |
| 38 4:3 |v| READ_WRITE |
| 48 5:3 |v| READ |
| 53 6:3 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_VariablePatternElement_ifCase() async { |
| await resolveTestCode(''' |
| void f(Object? x) { |
| if (x case int v) { |
| v; |
| } |
| } |
| '''); |
| var element = findNode.bindPatternVariableElement('v)'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 46 3:5 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_VariablePatternElement_ifCase_logicalOr() async { |
| await resolveTestCode(''' |
| void f(Object? x) { |
| if (x case int v || [int v]) { |
| v; |
| v = 1; |
| } |
| } |
| '''); |
| var element = findNode.bindPatternVariableElement('v]'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 57 3:5 |v| READ |
| 64 4:5 |v| WRITE |
| '''); |
| } |
| |
| test_searchReferences_VariablePatternElement_patternAssignment() async { |
| await resolveTestCode(''' |
| void f() { |
| int v; |
| (v, _) = (0, 1); |
| v; |
| } |
| '''); |
| var element = findElement.localVar('v'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 23 3:4 |v| WRITE |
| 41 4:3 |v| READ |
| '''); |
| } |
| |
| test_searchReferences_VariablePatternElement_switchExpression() async { |
| await resolveTestCode(''' |
| Object f(Object? x) => switch (0) { |
| int v when v > 0 => v + 1 + (v = 2), |
| _ => -1, |
| } |
| '''); |
| var element = findNode.bindPatternVariableElement('int v'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 49 2:14 |v| READ |
| 58 2:23 |v| READ |
| 67 2:32 |v| WRITE |
| '''); |
| } |
| |
| test_searchReferences_VariablePatternElement_switchExpression_topLevel() async { |
| await resolveTestCode(''' |
| var f = switch (0) { |
| int v when v > 0 => v + 1 + (v = 2), |
| _ => -1, |
| } |
| '''); |
| var element = findNode.bindPatternVariableElement('int v'); |
| await assertElementReferencesText(element, r''' |
| self::@variable::f |
| 34 2:14 |v| READ |
| 43 2:23 |v| READ |
| 52 2:32 |v| WRITE |
| '''); |
| } |
| |
| test_searchReferences_VariablePatternElement_switchStatement_shared() async { |
| await resolveTestCode(''' |
| void f(Object? x) { |
| switch (0) { |
| case int v when v > 0: |
| case [int v] when v < 0: |
| v; |
| v = 1; |
| } |
| } |
| '''); |
| var element = findNode.bindPatternVariableElement('int v when'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 55 3:21 |v| READ |
| 84 4:23 |v| READ |
| 97 5:7 |v| READ |
| 106 6:7 |v| WRITE |
| '''); |
| } |
| |
| test_searchReferences_VariablePatternElement_switchStatement_shared_hasLogicalOr() async { |
| await resolveTestCode(''' |
| void f(Object? x) { |
| switch (0) { |
| case int v when v > 0: |
| case [int v] || [..., int v] when v < 0: |
| v; |
| v = 1; |
| } |
| } |
| '''); |
| var element = findNode.bindPatternVariableElement('int v when'); |
| await assertElementReferencesText(element, r''' |
| self::@function::f |
| 55 3:21 |v| READ |
| 100 4:39 |v| READ |
| 113 5:7 |v| READ |
| 122 6:7 |v| WRITE |
| '''); |
| } |
| |
| test_searchSubtypes() async { |
| await resolveTestCode(''' |
| class T {} |
| class A extends T {} |
| class B = Object with T; |
| class C implements T {} |
| '''); |
| var element = findElement.class_('T'); |
| await assertElementReferencesText(element, r''' |
| self::@class::A |
| 27 2:17 |T| REFERENCE |
| self::@class::B |
| 54 3:23 |T| REFERENCE |
| self::@class::C |
| 76 4:20 |T| REFERENCE |
| '''); |
| } |
| |
| test_searchSubtypes_mixinDeclaration() async { |
| await resolveTestCode(''' |
| class T {} |
| mixin A on T {} |
| mixin B implements T {} |
| '''); |
| var element = findElement.class_('T'); |
| await assertElementReferencesText(element, r''' |
| self::@mixin::A |
| 22 2:12 |T| REFERENCE |
| self::@mixin::B |
| 46 3:20 |T| REFERENCE |
| '''); |
| } |
| |
| test_subtypes_class() async { |
| await resolveTestCode(''' |
| class A {} |
| |
| class B extends A { |
| void methodB() {} |
| } |
| |
| class C extends Object with A { |
| void methodC() {} |
| } |
| |
| class D implements A { |
| void methodD() {} |
| } |
| |
| class E extends B { |
| void methodE() {} |
| } |
| |
| class F {} |
| '''); |
| var a = findElement.class_('A'); |
| |
| // Search by 'type'. |
| List<SubtypeResult> subtypes = |
| await driver.search.subtypes(SearchedFiles(), type: a); |
| expect(subtypes, hasLength(3)); |
| |
| SubtypeResult b = subtypes.singleWhere((r) => r.name == 'B'); |
| SubtypeResult c = subtypes.singleWhere((r) => r.name == 'C'); |
| SubtypeResult d = subtypes.singleWhere((r) => r.name == 'D'); |
| |
| expect(b.libraryUri, testUriStr); |
| expect(b.id, '$testUriStr;$testUriStr;B'); |
| expect(b.members, ['methodB']); |
| |
| expect(c.libraryUri, testUriStr); |
| expect(c.id, '$testUriStr;$testUriStr;C'); |
| expect(c.members, ['methodC']); |
| |
| expect(d.libraryUri, testUriStr); |
| expect(d.id, '$testUriStr;$testUriStr;D'); |
| expect(d.members, ['methodD']); |
| |
| // Search by 'id'. |
| { |
| List<SubtypeResult> subtypes = |
| await driver.search.subtypes(SearchedFiles(), subtype: b); |
| expect(subtypes, hasLength(1)); |
| SubtypeResult e = subtypes.singleWhere((r) => r.name == 'E'); |
| expect(e.members, ['methodE']); |
| } |
| } |
| |
| test_subTypes_class_discover() async { |
| var aaaPackageRootPath = '$packagesRootPath/aaa'; |
| var bbbPackageRootPath = '$packagesRootPath/bbb'; |
| |
| var aaaFilePath = convertPath('$aaaPackageRootPath/lib/a.dart'); |
| var bbbFilePath = convertPath('$bbbPackageRootPath/lib/b.dart'); |
| |
| writeTestPackageConfig( |
| PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaPackageRootPath) |
| ..add(name: 'bbb', rootPath: bbbPackageRootPath), |
| ); |
| |
| var tUri = 'package:test/test.dart'; |
| var aUri = 'package:aaa/a.dart'; |
| var bUri = 'package:bbb/b.dart'; |
| |
| addTestFile(r''' |
| import 'package:aaa/a.dart'; |
| |
| class T1 extends A { |
| void method1() {} |
| } |
| |
| class T2 extends A { |
| void method2() {} |
| } |
| '''); |
| |
| newFile(bbbFilePath, r''' |
| import 'package:aaa/a.dart'; |
| |
| class B extends A { |
| void method1() {} |
| } |
| '''); |
| |
| newFile(aaaFilePath, r''' |
| class A { |
| void method1() {} |
| void method2() {} |
| } |
| '''); |
| |
| var aLibraryResult = |
| await driver.getLibraryByUri(aUri) as LibraryElementResult; |
| ClassElement aClass = aLibraryResult.element.getClass('A')!; |
| |
| // Search by 'type'. |
| List<SubtypeResult> subtypes = |
| await driver.search.subtypes(SearchedFiles(), type: aClass); |
| expect(subtypes, hasLength(3)); |
| |
| SubtypeResult t1 = subtypes.singleWhere((r) => r.name == 'T1'); |
| SubtypeResult t2 = subtypes.singleWhere((r) => r.name == 'T2'); |
| SubtypeResult b = subtypes.singleWhere((r) => r.name == 'B'); |
| |
| expect(t1.libraryUri, tUri); |
| expect(t1.id, '$tUri;$tUri;T1'); |
| expect(t1.members, ['method1']); |
| |
| expect(t2.libraryUri, tUri); |
| expect(t2.id, '$tUri;$tUri;T2'); |
| expect(t2.members, ['method2']); |
| |
| expect(b.libraryUri, bUri); |
| expect(b.id, '$bUri;$bUri;B'); |
| expect(b.members, ['method1']); |
| } |
| |
| test_subTypes_class_discover2() async { |
| var aaaPackageRootPath = '$packagesRootPath/aaa'; |
| var bbbPackageRootPath = '$packagesRootPath/bbb'; |
| var cccPackageRootPath = '$packagesRootPath/ccc'; |
| |
| var aaaFilePath = convertPath('$aaaPackageRootPath/lib/a.dart'); |
| var bbbFilePath = convertPath('$bbbPackageRootPath/lib/b.dart'); |
| var cccFilePath = convertPath('$cccPackageRootPath/lib/c.dart'); |
| |
| writeTestPackageConfig( |
| PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaPackageRootPath) |
| ..add(name: 'bbb', rootPath: bbbPackageRootPath), |
| ); |
| |
| addTestFile('class T implements List {}'); |
| newFile(aaaFilePath, 'class A implements List {}'); |
| newFile(bbbFilePath, 'class B implements List {}'); |
| newFile(cccFilePath, 'class C implements List {}'); |
| |
| var coreLibResult = |
| await driver.getLibraryByUri('dart:core') as LibraryElementResult; |
| ClassElement listElement = coreLibResult.element.getClass('List')!; |
| |
| var searchedFiles = SearchedFiles(); |
| var results = await driver.search.subTypes(listElement, searchedFiles); |
| |
| void assertHasResult(String path, String name, {bool not = false}) { |
| var matcher = contains(predicate((SearchResult r) { |
| var element = r.enclosingElement; |
| return element.name == name && element.source!.fullName == path; |
| })); |
| expect(results, not ? isNot(matcher) : matcher); |
| } |
| |
| assertHasResult(testFile.path, 'T'); |
| assertHasResult(aaaFilePath, 'A'); |
| assertHasResult(bbbFilePath, 'B'); |
| assertHasResult(cccFilePath, 'C', not: true); |
| } |
| |
| test_subtypes_class_files() async { |
| String pathB = convertPath('$testPackageLibPath/b.dart'); |
| String pathC = convertPath('$testPackageLibPath/c.dart'); |
| newFile(pathB, r''' |
| import 'test.dart'; |
| class B extends A {} |
| '''); |
| newFile(pathC, r''' |
| import 'test.dart'; |
| class C extends A {} |
| class D {} |
| '''); |
| |
| await resolveTestCode(''' |
| class A {} |
| '''); |
| var a = findElement.class_('A'); |
| |
| List<SubtypeResult> subtypes = |
| await driver.search.subtypes(SearchedFiles(), type: a); |
| expect(subtypes, hasLength(2)); |
| |
| SubtypeResult b = subtypes.singleWhere((r) => r.name == 'B'); |
| SubtypeResult c = subtypes.singleWhere((r) => r.name == 'C'); |
| |
| expect(b.id, endsWith('b.dart;B')); |
| expect(c.id, endsWith('c.dart;C')); |
| } |
| |
| test_subtypes_class_macroGenerated() async { |
| if (!configureWithCommonMacros()) { |
| return; |
| } |
| |
| await resolveTestCode(''' |
| import 'append.dart'; |
| |
| class A {} |
| |
| @DeclareTypesPhase('C', """ |
| class C extends A { |
| void methodC() {} |
| } |
| """) |
| class B extends A { |
| void methodB() {} |
| } |
| '''); |
| var A = findElement.class_('A'); |
| |
| // Search by 'type'. |
| var subtypes = await driver.search.subtypes( |
| SearchedFiles(), |
| type: A, |
| ); |
| expect(subtypes, hasLength(2)); |
| |
| var B = subtypes.singleWhere((r) => r.name == 'B'); |
| var C = subtypes.singleWhere((r) => r.name == 'C'); |
| |
| expect(B.libraryUri, testUriStr); |
| expect(B.id, '$testUriStr;$testUriStr;B'); |
| expect(B.members, ['methodB']); |
| |
| expect(C.libraryUri, testUriStr); |
| expect(C.id, 'package:test/test.dart;package:test/test.macro.dart;C'); |
| expect(C.members, ['methodC']); |
| } |
| |
| test_subtypes_enum() async { |
| await resolveTestCode(''' |
| class A {} |
| |
| enum E1 implements A { |
| v; |
| void methodE1() {} |
| } |
| |
| enum E2 with A { |
| v; |
| void methodE2() {} |
| } |
| |
| class B {} |
| '''); |
| |
| var subtypes = await driver.search.subtypes( |
| SearchedFiles(), |
| type: findElement.class_('A'), |
| ); |
| expect(subtypes, hasLength(2)); |
| |
| var resultE1 = subtypes.singleWhere((r) => r.name == 'E1'); |
| var resultE2 = subtypes.singleWhere((r) => r.name == 'E2'); |
| |
| expect(resultE1.libraryUri, testUriStr); |
| expect(resultE1.id, '$testUriStr;$testUriStr;E1'); |
| expect(resultE1.members, ['methodE1']); |
| |
| expect(resultE2.libraryUri, testUriStr); |
| expect(resultE2.id, '$testUriStr;$testUriStr;E2'); |
| expect(resultE2.members, ['methodE2']); |
| } |
| |
| test_subtypes_extensionType() async { |
| await resolveTestCode(''' |
| class A {} |
| |
| extension type E1(A it) implements A { |
| void methodE1() {} |
| } |
| |
| extension type E2(A it) implements A { |
| void methodE2() {} |
| } |
| '''); |
| |
| var subtypes = await driver.search.subtypes( |
| SearchedFiles(), |
| type: findElement.class_('A'), |
| ); |
| expect(subtypes, hasLength(2)); |
| |
| var resultE1 = subtypes.singleWhere((r) => r.name == 'E1'); |
| var resultE2 = subtypes.singleWhere((r) => r.name == 'E2'); |
| |
| expect(resultE1.libraryUri, testUriStr); |
| expect(resultE1.id, '$testUriStr;$testUriStr;E1'); |
| expect(resultE1.members, ['methodE1']); |
| |
| expect(resultE2.libraryUri, testUriStr); |
| expect(resultE2.id, '$testUriStr;$testUriStr;E2'); |
| expect(resultE2.members, ['methodE2']); |
| } |
| |
| test_subtypes_extensionType2() async { |
| await resolveTestCode(''' |
| extension type A(int it) {} |
| |
| extension type B(int it) implements A { |
| void methodB() {} |
| } |
| '''); |
| |
| var subtypes = await driver.search.subtypes( |
| SearchedFiles(), |
| type: findElement.extensionType('A'), |
| ); |
| expect(subtypes, hasLength(1)); |
| |
| var B = subtypes.singleWhere((r) => r.name == 'B'); |
| |
| expect(B.libraryUri, testUriStr); |
| expect(B.id, '$testUriStr;$testUriStr;B'); |
| expect(B.members, ['methodB']); |
| } |
| |
| test_subtypes_mixin_superclassConstraints() async { |
| await resolveTestCode(''' |
| class A { |
| void methodA() {} |
| } |
| |
| class B { |
| void methodB() {} |
| } |
| |
| mixin M on A, B { |
| void methodA() {} |
| void methodM() {} |
| } |
| '''); |
| var a = findElement.class_('A'); |
| var b = findElement.class_('B'); |
| |
| { |
| var subtypes = await driver.search.subtypes(SearchedFiles(), type: a); |
| expect(subtypes, hasLength(1)); |
| |
| var m = subtypes.singleWhere((r) => r.name == 'M'); |
| expect(m.libraryUri, testUriStr); |
| expect(m.id, '$testUriStr;$testUriStr;M'); |
| expect(m.members, ['methodA', 'methodM']); |
| } |
| |
| { |
| var subtypes = await driver.search.subtypes(SearchedFiles(), type: b); |
| expect(subtypes, hasLength(1)); |
| |
| var m = subtypes.singleWhere((r) => r.name == 'M'); |
| expect(m.libraryUri, testUriStr); |
| expect(m.id, '$testUriStr;$testUriStr;M'); |
| expect(m.members, ['methodA', 'methodM']); |
| } |
| } |
| |
| test_topLevelElements() async { |
| await resolveTestCode(''' |
| class A {} |
| class B = Object with A; |
| mixin C {} |
| typedef D(); |
| f() {} |
| var g = null; |
| class NoMatchABCDEF {} |
| '''); |
| var a = findElement.class_('A'); |
| var b = findElement.class_('B'); |
| var c = findElement.mixin('C'); |
| var d = findElement.typeAlias('D'); |
| var f = findElement.function('f'); |
| var g = findElement.topVar('g'); |
| RegExp regExp = RegExp(r'^[ABCDfg]$'); |
| expect(await driver.search.topLevelElements(regExp), |
| unorderedEquals([a, b, c, d, f, g])); |
| } |
| |
| Future<List<Element>> _findClassMembers(String name) { |
| var searchedFiles = SearchedFiles(); |
| return driver.search.classMembers(name, searchedFiles); |
| } |
| |
| String _getDeclarationsText( |
| WorkspaceSymbols symbols, |
| Map<File, String> inFiles, |
| ) { |
| var groups = symbols.declarations |
| .map((declaration) { |
| var file = getFile(symbols.files[declaration.fileIndex]); |
| var fileStr = inFiles[file]; |
| return fileStr != null ? MapEntry(fileStr, declaration) : null; |
| }) |
| .nonNulls |
| .groupListsBy((entry) => entry.key); |
| |
| var buffer = StringBuffer(); |
| for (var group in groups.entries) { |
| var fileStr = group.key; |
| buffer.writeln(fileStr); |
| var fileDeclarations = group.value.map((e) => e.value).toList(); |
| var sorted = fileDeclarations.sortedBy<num>((e) => e.offset); |
| for (var declaration in sorted) { |
| var name = declaration.name; |
| buffer.write(' ${declaration.kind.name} '); |
| buffer.writeln(name.isNotEmpty ? name : '<unnamed>'); |
| buffer.writeln( |
| ' offset: ${declaration.offset} ' |
| '${declaration.line}:${declaration.column}', |
| ); |
| buffer.writeln( |
| ' codeOffset: ${declaration.codeOffset} + ' |
| '${declaration.codeLength}', |
| ); |
| |
| var className = declaration.className; |
| if (className != null) { |
| buffer.writeln(' className: $className'); |
| } |
| |
| var mixinName = declaration.mixinName; |
| if (mixinName != null) { |
| buffer.writeln(' mixinName: $mixinName'); |
| } |
| |
| var parameters = declaration.parameters; |
| if (parameters != null) { |
| buffer.writeln(' parameters: $parameters'); |
| } |
| } |
| } |
| return buffer.toString(); |
| } |
| |
| String _getSearchResultsText(List<SearchResult> results) { |
| var selfUriStr = '${result.uri}'; |
| |
| String referenceToString(Reference reference) { |
| var name = reference.name; |
| if (name == selfUriStr) { |
| name = 'self'; |
| } |
| |
| var parent = reference.parent ?? |
| (throw StateError('Should not go past libraries')); |
| |
| // A library. |
| if (parent.parent == null) { |
| return name; |
| } |
| |
| // A unit of the self library. |
| if (parent.name == '@unit' && name == 'self') { |
| return 'self'; |
| } |
| |
| return '${referenceToString(parent)}::$name'; |
| } |
| |
| String elementToReferenceString(Element element) { |
| var enclosingElement = element.enclosingElement; |
| var reference = (element as ElementImpl).reference; |
| if (reference != null) { |
| return referenceToString(reference); |
| } else if (element is ParameterElement) { |
| var enclosingStr = enclosingElement != null |
| ? elementToReferenceString(enclosingElement) |
| : 'root'; |
| return '$enclosingStr::@parameter::${element.name}'; |
| } else { |
| return '${element.name}@${element.nameOffset}'; |
| } |
| } |
| |
| var analysisSession = result.session; |
| |
| var groups = results |
| .groupListsBy((result) => result.enclosingElement) |
| .entries |
| .map((e) { |
| var enclosingElement = e.key; |
| return _GroupToPrint( |
| enclosingElement: enclosingElement, |
| enclosingElementStr: elementToReferenceString(enclosingElement), |
| results: e.value.sortedBy<num>((e) => e.offset), |
| ); |
| }).sorted((first, second) { |
| var firstPath = first.path; |
| var secondPath = second.path; |
| var byPath = firstPath.compareTo(secondPath); |
| if (byPath != 0) { |
| return byPath; |
| } |
| return first.results.first.offset - second.results.first.offset; |
| }); |
| |
| var buffer = StringBuffer(); |
| for (var group in groups) { |
| var unitPath = group.path; |
| var unitResult = analysisSession.getParsedUnit(unitPath); |
| unitResult as ParsedUnitResult; |
| buffer.writeln(group.enclosingElementStr); |
| for (var result in group.results) { |
| var offset = result.offset; |
| var length = result.length; |
| var end = offset + length; |
| var location = unitResult.lineInfo.getLocation(offset); |
| var snippet = unitResult.content.substring(offset, end); |
| |
| buffer.write(' '); |
| buffer.write(result.offset); |
| buffer.write(' '); |
| buffer.write(location.lineNumber); |
| buffer.write(':'); |
| buffer.write(location.columnNumber); |
| buffer.write(' |$snippet|'); |
| buffer.write(' '); |
| buffer.write(result.kind.name); |
| if (result.isQualified) { |
| buffer.write(' qualified'); |
| } |
| if (!result.isResolved) { |
| buffer.write(' unresolved'); |
| } |
| buffer.writeln(); |
| } |
| } |
| return buffer.toString(); |
| } |
| } |
| |
| class _GroupToPrint { |
| final Element enclosingElement; |
| final String enclosingElementStr; |
| final List<SearchResult> results; |
| |
| _GroupToPrint({ |
| required this.enclosingElement, |
| required this.enclosingElementStr, |
| required this.results, |
| }); |
| |
| String get path { |
| return enclosingElement |
| .thisOrAncestorOfType<CompilationUnitElement>()! |
| .source |
| .fullName; |
| } |
| } |