| // Copyright (c) 2014, 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 'dart:async'; | |
| import 'package:analysis_server/protocol/protocol.dart'; | |
| import 'package:analysis_server/protocol/protocol_constants.dart'; | |
| import 'package:analysis_server/protocol/protocol_generated.dart'; | |
| import 'package:analyzer/file_system/file_system.dart'; | |
| import 'package:analyzer_plugin/protocol/protocol_common.dart'; | |
| import 'package:test/test.dart'; | |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; | |
| import '../analysis_abstract.dart'; | |
| import '../analysis_server_base.dart'; | |
| void main() { | |
| defineReflectiveSuite(() { | |
| defineReflectiveTests(AnalysisNotificationNavigationTest); | |
| }); | |
| } | |
| class AbstractNavigationTest extends PubPackageAnalysisServerTest { | |
| late List<NavigationRegion> regions; | |
| late List<NavigationTarget> targets; | |
| late List<String> targetFiles; | |
| late NavigationRegion testRegion; | |
| late List<int> testTargetIndexes; | |
| late List<NavigationTarget> testTargets; | |
| late NavigationTarget testTarget; | |
| /// Validates that there is a target in [testTargets] with [file], | |
| /// at [offset] and with the given [length]. | |
| void assertHasFileTarget(String file, int offset, int length) { | |
| for (var target in testTargets) { | |
| if (targetFiles[target.fileIndex] == file && | |
| target.offset == offset && | |
| target.length == length) { | |
| testTarget = target; | |
| return; | |
| } | |
| } | |
| fail( | |
| 'Expected to find target (file=$file; offset=$offset; length=$length) in\n' | |
| '$testRegion in\n' | |
| '${testTargets.join('\n')}', | |
| ); | |
| } | |
| void assertHasOperatorRegion( | |
| String regionSearch, | |
| int regionLength, | |
| String targetSearch, | |
| int targetLength, | |
| ) { | |
| assertHasRegion(regionSearch, length: regionLength); | |
| assertHasTarget(targetSearch, length: targetLength); | |
| } | |
| /// Validates that there is a region at the offset of [search] in [testFile]. | |
| /// If [length] is not specified explicitly, then length of an identifier | |
| /// from [search] is used. | |
| void assertHasRegion(String search, {int length = -1, File? targetFile}) { | |
| var file = targetFile ?? testFile; | |
| var offset = offsetInFile(file, search); | |
| if (length == -1) { | |
| length = findIdentifierLength(search); | |
| } | |
| findRegion(offset, length, true); | |
| } | |
| /// Validates that there is a region at the offset of [search] in [testFile] | |
| /// with the given [length] or the length of [search]. | |
| void assertHasRegionString(String search, [int length = -1]) { | |
| var offset = findOffset(search); | |
| if (length == -1) { | |
| length = search.length; | |
| } | |
| findRegion(offset, length, true); | |
| } | |
| /// Validates that there is an identifier region at [regionSearch] with target | |
| /// at [targetSearch]. | |
| void assertHasRegionTarget( | |
| String regionSearch, | |
| String targetSearch, { | |
| int regionLength = -1, | |
| int targetLength = -1, | |
| }) { | |
| assertHasRegion(regionSearch, length: regionLength); | |
| assertHasTarget(targetSearch, length: targetLength); | |
| } | |
| /// Validates that there is a target in [testTargets] with [testFile], at the | |
| /// offset of [search] in [testFile], and with the given [length] or the | |
| /// length of a leading identifier in [search]. | |
| void assertHasTarget(String search, {int length = -1, File? targetFile}) { | |
| var file = targetFile ?? testFile; | |
| var offset = offsetInFile(file, search); | |
| if (length == -1) { | |
| length = findIdentifierLength(search); | |
| } | |
| assertHasFileTarget(file.path, offset, length); | |
| } | |
| // TODO(scheglov): Improve target matching. | |
| void assertHasTargetInDartCore(String search) { | |
| var dartCoreFile = getFile('/sdk/lib/core/core.dart'); | |
| var dartCoreContent = dartCoreFile.readAsStringSync(); | |
| var offset = dartCoreContent.indexOf(search); | |
| expect(offset, isNot(-1)); | |
| if (dartCoreContent.contains(search, offset + search.length)) { | |
| fail('Not unique'); | |
| } | |
| var length = findIdentifierLength(search); | |
| assertHasFileTarget(dartCoreFile.path, offset, length); | |
| } | |
| /// Validates that there is not a region at [search] and with the given | |
| /// [length]. | |
| void assertNoRegion(String search, int length) { | |
| var offset = findOffset(search); | |
| findRegion(offset, length, false); | |
| } | |
| /// Validates that there is not a region at [search] with any length. | |
| void assertNoRegionAt(String search) { | |
| var offset = findOffset(search); | |
| findRegion(offset, -1, false); | |
| } | |
| /// Validates that there is not a region for [search] string. | |
| void assertNoRegionString(String search) { | |
| var offset = findOffset(search); | |
| var length = search.length; | |
| findRegion(offset, length, false); | |
| } | |
| void assertRegionsSorted() { | |
| var lastEnd = -1; | |
| for (var region in regions) { | |
| var offset = region.offset; | |
| if (offset < lastEnd) { | |
| fail('$lastEnd was expected to be > $offset in\n${regions.join('\n')}'); | |
| } | |
| lastEnd = offset + region.length; | |
| } | |
| } | |
| /// Finds the navigation region with the given [offset] and [length]. | |
| /// If [length] is `-1`, then it is ignored. | |
| /// | |
| /// If [exists] is `true`, then fails if such region does not exist. | |
| /// Otherwise remembers it in [testRegion]. | |
| /// Also fills [testTargets] with its targets. | |
| /// | |
| /// If [exists] is `false`, then fails if such region exists. | |
| void findRegion(int offset, int length, bool exists) { | |
| for (var region in regions) { | |
| if (region.offset == offset && | |
| (length == -1 || region.length == length)) { | |
| if (!exists) { | |
| fail( | |
| 'Not expected to find (offset=$offset; length=$length) in\n' | |
| '${regions.join('\n')}', | |
| ); | |
| } | |
| testRegion = region; | |
| testTargetIndexes = region.targets; | |
| testTargets = testTargetIndexes.map((i) => targets[i]).toList(); | |
| return; | |
| } | |
| } | |
| if (exists) { | |
| fail( | |
| 'Expected to find (offset=$offset; length=$length) in\n' | |
| '${regions.join('\n')}', | |
| ); | |
| } | |
| } | |
| } | |
| @reflectiveTest | |
| class AnalysisNotificationNavigationTest extends AbstractNavigationTest { | |
| final Completer<void> _resultsAvailable = Completer(); | |
| String get augmentFilePath => '$testPackageLibPath/a.dart'; | |
| Future<void> prepareNavigation() async { | |
| await handleSuccessfulRequest( | |
| AnalysisSetSubscriptionsParams({ | |
| AnalysisService.NAVIGATION: [testFile.path], | |
| }).toRequest('0', clientUriConverter: server.uriConverter), | |
| ); | |
| await _resultsAvailable.future; | |
| assertRegionsSorted(); | |
| } | |
| @override | |
| void processNotification(Notification notification) { | |
| if (notification.event == analysisNotificationNavigation) { | |
| var params = AnalysisNavigationParams.fromNotification( | |
| notification, | |
| clientUriConverter: server.uriConverter, | |
| ); | |
| if (params.file == testFile.path || params.file == augmentFilePath) { | |
| regions = params.regions; | |
| targets = params.targets; | |
| targetFiles = params.files; | |
| _resultsAvailable.complete(); | |
| } | |
| } | |
| } | |
| @override | |
| Future<void> setUp() async { | |
| super.setUp(); | |
| await setRoots(included: [workspaceRootPath], excluded: []); | |
| } | |
| Future<void> test_afterAnalysis() async { | |
| addTestFile(''' | |
| class AAA {} | |
| AAA aaa; | |
| '''); | |
| await waitForTasksFinished(); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('AAA aaa;', 'AAA {}'); | |
| } | |
| Future<void> test_afterAnalysis_inNullAwareElements_inList() async { | |
| addTestFile(''' | |
| class AAA {} | |
| final aaa = [?((AAA arg) => null)]; | |
| '''); | |
| await waitForTasksFinished(); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('AAA arg', 'AAA {}'); | |
| } | |
| Future<void> test_afterAnalysis_inNullAwareElements_inSet() async { | |
| addTestFile(''' | |
| class AAA {} | |
| final aaa = {?((AAA arg) => null)}; | |
| '''); | |
| await waitForTasksFinished(); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('AAA arg', 'AAA {}'); | |
| } | |
| Future<void> test_afterAnalysis_inNullAwareKey_inMap() async { | |
| addTestFile(''' | |
| class AAA {} | |
| final aaa = {?((AAA arg) => null): "value"}; | |
| '''); | |
| await waitForTasksFinished(); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('AAA arg', 'AAA {}'); | |
| } | |
| Future<void> test_afterAnalysis_inNullAwareValue_inMap() async { | |
| addTestFile(''' | |
| class AAA {} | |
| final aaa = {"key": ?((AAA arg) => null)}; | |
| '''); | |
| await waitForTasksFinished(); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('AAA arg', 'AAA {}'); | |
| } | |
| Future<void> test_annotation_generic_typeArguments_class() async { | |
| addTestFile(''' | |
| class A<T> { | |
| const A(); | |
| } | |
| @A<int>() | |
| void f() {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('int>()'); | |
| } | |
| Future<void> test_annotationConstructor_generic_named() async { | |
| addTestFile(''' | |
| class A<T> { | |
| const A.named(_); | |
| } | |
| @A<int>.named(0) | |
| void f() {} | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegion('A<int>.named(0)'); | |
| assertHasTarget('named(_);'); | |
| } | |
| { | |
| assertHasRegion('named(0)'); | |
| assertHasTarget('named(_);'); | |
| } | |
| } | |
| Future<void> test_annotationConstructor_generic_unnamed() async { | |
| addTestFile(''' | |
| class A<T> { | |
| const A(_); | |
| } | |
| @A<int>(0) | |
| void f() {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionString('A<int>(0)', 'A'.length); | |
| assertHasTarget('A(_);'); | |
| } | |
| Future<void> test_annotationConstructor_implicit() async { | |
| addTestFile(''' | |
| class A { | |
| } | |
| @A() | |
| void f() { | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionString('A()', 'A'.length); | |
| assertHasTarget('A {'); | |
| } | |
| Future<void> test_annotationConstructor_importPrefix() async { | |
| newFile('$testPackageLibPath/my_annotation.dart', r''' | |
| library an; | |
| class MyAnnotation { | |
| const MyAnnotation(); | |
| const MyAnnotation.named(); | |
| } | |
| '''); | |
| addTestFile(''' | |
| import 'my_annotation.dart' as man; | |
| @man.MyAnnotation() | |
| @man.MyAnnotation.named() | |
| void f() { | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('MyAnnotation()'); | |
| assertHasRegion('MyAnnotation.named()'); | |
| assertHasRegion('named()'); | |
| { | |
| assertHasRegion('man.MyAnnotation()'); | |
| assertHasTarget('man;'); | |
| } | |
| { | |
| assertHasRegion('man.MyAnnotation.named()'); | |
| assertHasTarget('man;'); | |
| } | |
| } | |
| Future<void> test_annotationConstructor_named() async { | |
| addTestFile(''' | |
| class A { | |
| const A.named(p); | |
| } | |
| @A.named(0) | |
| void f() { | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegion('A.named(0)'); | |
| assertHasTarget('named(p);'); | |
| } | |
| { | |
| assertHasRegion('named(0)'); | |
| assertHasTarget('named(p);'); | |
| } | |
| } | |
| Future<void> test_annotationConstructor_unnamed() async { | |
| addTestFile(''' | |
| class A { | |
| const A(); | |
| } | |
| @A() | |
| void f() { | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionString('A()', 'A'.length); | |
| assertHasTarget('A();'); | |
| } | |
| Future<void> test_annotationField() async { | |
| addTestFile(''' | |
| const myan = new Object(); | |
| @myan // ref | |
| void f() { | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('myan // ref'); | |
| assertHasTarget('myan = new Object();'); | |
| } | |
| Future<void> test_annotationField_importPrefix() async { | |
| newFile('$testPackageLibPath/mayn.dart', r''' | |
| library an; | |
| const myan = new Object(); | |
| '''); | |
| addTestFile(''' | |
| import 'mayn.dart' as man; | |
| @man.myan // ref | |
| void f() { | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('myan // ref'); | |
| } | |
| Future<void> test_assignedVariablePattern() async { | |
| addTestFile(''' | |
| void f() { | |
| int? left; | |
| int? right; | |
| (left, right) = (1, 1); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('left,', 'left;'); | |
| } | |
| Future<void> test_augmentation_class_method() async { | |
| addTestFile(r''' | |
| part of 'a.dart'; | |
| augment class A { | |
| foo(){ | |
| bar(); | |
| } | |
| } | |
| '''); | |
| var aFile = newFile(augmentFilePath, ''' | |
| part 'test.dart'; | |
| class A { | |
| void bar(){} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('bar'); | |
| assertHasTarget('bar', targetFile: aFile); | |
| } | |
| Future<void> test_augmentation_within_augment() async { | |
| addTestFile(r''' | |
| part of 'a.dart'; | |
| augment class A { | |
| A.named(){ | |
| bar(); | |
| } | |
| void [!bar!](){} | |
| } | |
| '''); | |
| newFile(augmentFilePath, ''' | |
| part 'test.dart'; | |
| class A {} | |
| void f() { | |
| A.named(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('bar'); | |
| assertHasFileTarget( | |
| convertPath(testFilePath), | |
| parsedSourceRange.offset, | |
| parsedSourceRange.length, | |
| ); | |
| } | |
| @SkippedTest() // TODO(scheglov): implement augmentation | |
| Future<void> test_class_augmentation_constructor() async { | |
| var aFile = newFile(augmentFilePath, r''' | |
| part of 'test.dart'; | |
| augment class A { | |
| A.named(){} | |
| } | |
| '''); | |
| addTestFile(''' | |
| part 'a.dart'; | |
| class A {} | |
| void f() { | |
| A.named(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('named'); | |
| assertHasTarget('named', targetFile: aFile); | |
| } | |
| Future<void> test_class_augmentation_method() async { | |
| var aFile = newFile(augmentFilePath, r''' | |
| part of 'test.dart'; | |
| augment class A { | |
| void foo() {} | |
| } | |
| '''); | |
| addTestFile(''' | |
| part 'a.dart'; | |
| class A {} | |
| void f() { | |
| A().foo(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('foo'); | |
| assertHasTarget('foo', targetFile: aFile); | |
| } | |
| Future<void> | |
| test_class_constructor_annotationConstructor_importPrefix() async { | |
| var a = newFile('$testPackageLibPath/a.dart', r''' | |
| class A { | |
| const A(); | |
| const A.named(); | |
| } | |
| '''); | |
| addTestFile(''' | |
| part of 'b.dart'; | |
| import 'a.dart' as prefix; | |
| class B { | |
| @prefix.A() | |
| @prefix.A.named() | |
| B().foo(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('prefix.A()'); | |
| assertHasTarget('prefix;'); | |
| assertHasRegion('A()'); | |
| assertHasTarget('A();', targetFile: a); | |
| assertHasRegion('prefix.A.named()'); | |
| assertHasTarget('prefix;'); | |
| assertHasRegion('A.named()'); | |
| assertHasTarget('named()', targetFile: a); | |
| assertHasRegion('named()'); | |
| assertHasTarget('named()', targetFile: a); | |
| } | |
| Future<void> test_class_constructor_named() async { | |
| addTestFile(''' | |
| class A { | |
| A.named(BBB p) {} | |
| } | |
| class BBB {} | |
| '''); | |
| await prepareNavigation(); | |
| // has no region for complete "A.named" | |
| assertNoRegion('A.named', 'A.named'.length); | |
| // has separate regions for "A" and "named" | |
| assertHasRegion('A.named(', length: 'A'.length); | |
| assertHasTarget('A {'); | |
| assertHasRegion('named(', length: 'named'.length); | |
| assertHasTarget('named(BBB'); | |
| // validate that we don't forget to resolve parameters | |
| assertHasRegionTarget('BBB p', 'BBB {}'); | |
| } | |
| Future<void> test_class_constructor_unnamed() async { | |
| addTestFile(''' | |
| class A { | |
| A(BBB p) {} | |
| } | |
| class BBB {} | |
| '''); | |
| await prepareNavigation(); | |
| // has region for complete "A.named" | |
| assertHasRegion('A(BBB'); | |
| assertHasTarget('A(BBB'); | |
| // validate that we don't forget to resolve parameters | |
| assertHasRegionTarget('BBB p', 'BBB {}'); | |
| } | |
| Future<void> test_class_constructorReference_named() async { | |
| addTestFile(''' | |
| class A {} | |
| class B<T> { | |
| B.named(); | |
| } | |
| void f() { | |
| B<A>.named; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('B<A>.named;', 'B<T> {'); | |
| assertHasRegionTarget('named;', 'named();'); | |
| assertHasRegionTarget('A>', 'A {}'); | |
| } | |
| Future<void> test_class_constructorReference_unnamed_declared() async { | |
| addTestFile(''' | |
| class A { | |
| A(); | |
| } | |
| void f() { | |
| A.new; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A.new;', 'A {'); | |
| assertHasRegionTarget('new;', 'A();'); | |
| } | |
| Future<void> test_class_constructorReference_unnamed_declared_new() async { | |
| addTestFile(''' | |
| class A { | |
| A.new(); | |
| } | |
| void f() { | |
| A.new; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A.new;', 'A {'); | |
| assertHasRegionTarget('new;', 'new();'); | |
| } | |
| Future<void> test_class_constructorReference_unnamed_default() async { | |
| addTestFile(''' | |
| class A {} | |
| void f() { | |
| A.new; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A.new;', 'A {}'); | |
| assertHasRegionTarget('new;', 'A {}'); | |
| } | |
| Future<void> test_class_factoryRedirectingConstructor_implicit() async { | |
| addTestFile(''' | |
| class A { | |
| factory A() = B; | |
| } | |
| class B { | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('B;'); | |
| assertHasTarget('B {'); | |
| } | |
| Future<void> | |
| test_class_factoryRedirectingConstructor_implicit_withTypeArgument() async { | |
| addTestFile(''' | |
| class A {} | |
| class B { | |
| factory B() = C<A>; | |
| } | |
| class C<T> {} | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegion('C<A>'); | |
| assertHasTarget('C<T> {'); | |
| } | |
| { | |
| assertHasRegion('A>;'); | |
| assertHasTarget('A {'); | |
| } | |
| } | |
| Future<void> test_class_factoryRedirectingConstructor_named() async { | |
| addTestFile(''' | |
| class A { | |
| factory A() = B.named; | |
| } | |
| class B { | |
| B.named(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegionString('B.named;', 'B'.length); | |
| assertHasTarget('B {'); | |
| } | |
| { | |
| assertHasRegionString('named;', 'named'.length); | |
| assertHasTarget('named();'); | |
| } | |
| } | |
| Future<void> | |
| test_class_factoryRedirectingConstructor_named_withTypeArgument() async { | |
| addTestFile(''' | |
| class A {} | |
| class B { | |
| factory B.named() = C<A>.named; | |
| } | |
| class C<T> { | |
| C.named() {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegion('C<A>'); | |
| assertHasTarget('C<T> {'); | |
| } | |
| { | |
| assertHasRegion('A>.named'); | |
| assertHasTarget('A {'); | |
| } | |
| { | |
| assertHasRegion('named;', length: 'named'.length); | |
| assertHasTarget('named() {}'); | |
| } | |
| } | |
| Future<void> test_class_factoryRedirectingConstructor_unnamed() async { | |
| addTestFile(''' | |
| class A { | |
| factory A() = B; | |
| } | |
| class B { | |
| B() {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('B;'); | |
| assertHasTarget('B() {}'); | |
| } | |
| Future<void> | |
| test_class_factoryRedirectingConstructor_unnamed_withTypeArgument() async { | |
| addTestFile(''' | |
| class A {} | |
| class B { | |
| factory B() = C<A>; | |
| } | |
| class C<T> { | |
| C() {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegion('C<A>'); | |
| assertHasTarget('C() {}'); | |
| } | |
| { | |
| assertHasRegion('A>;'); | |
| assertHasTarget('A {'); | |
| } | |
| } | |
| Future<void> test_class_factoryRedirectingConstructor_unresolved() async { | |
| addTestFile(''' | |
| class A { | |
| factory A() = B; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| // don't check regions, but there should be no exceptions | |
| } | |
| Future<void> test_class_fieldFormalParameter_requiredNamed() async { | |
| addTestFile(''' | |
| class A { | |
| final int f; | |
| A({required this.f}) : assert(f > 0); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('this.f', 'f;'); | |
| assertHasRegionTarget('f}) :', 'f;'); | |
| assertHasRegionTarget('f > 0', 'f}) :'); | |
| } | |
| Future<void> test_class_fieldFormalParameter_requiredPositional() async { | |
| addTestFile(''' | |
| class A { | |
| final int f; | |
| A(this.f) : assert(f > 0); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('this.f', 'f;'); | |
| assertHasRegionTarget('f) :', 'f;'); | |
| assertHasRegionTarget('f > 0', 'f) :'); | |
| } | |
| Future<void> | |
| test_class_fieldFormalParameter_requiredPositional_functionTyped() async { | |
| addTestFile(''' | |
| class B { | |
| final Object f; | |
| B(int this.f<T>(T a)) : assert(f is Object); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('f<T>', 'f;'); | |
| assertHasRegion('int '); | |
| assertHasRegionTarget('T>', 'T>'); | |
| assertHasRegionTarget('T a', 'T>'); | |
| assertHasRegionTarget('a))', 'a))'); | |
| assertHasRegionTarget('f is', 'f<T>'); | |
| } | |
| Future<void> | |
| test_class_fieldFormalParameter_requiredPositional_unresolved() async { | |
| addTestFile(''' | |
| class AAA { | |
| AAA(this.fff); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegion('fff);', 3); | |
| } | |
| Future<void> test_class_fromSDK() async { | |
| addTestFile(''' | |
| int V = 42; | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('int V'); | |
| var targetIndex = testTargetIndexes[0]; | |
| var target = targets[targetIndex]; | |
| expect(target.startLine, greaterThan(0)); | |
| expect(target.startColumn, greaterThan(0)); | |
| } | |
| Future<void> test_class_getter_originDeclaration() async { | |
| addTestFile(''' | |
| class A { | |
| int get foo => 0; | |
| void bar() { | |
| foo; | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo;', 'foo =>'); | |
| } | |
| Future<void> test_class_getter_originField() async { | |
| addTestFile(''' | |
| class A { | |
| final int foo = 0; | |
| void bar() { | |
| foo; | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo;', 'foo = 0;'); | |
| } | |
| Future<void> test_class_setter_originDeclaration() async { | |
| addTestFile(''' | |
| class A { | |
| set foo(int _) | |
| void bar() { | |
| foo = 0; | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo = 0;', 'foo(int _)'); | |
| } | |
| Future<void> test_class_setter_originField() async { | |
| addTestFile(''' | |
| class A { | |
| int foo = 42; | |
| void bar() { | |
| foo = 0; | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo = 0;', 'foo = 42;'); | |
| } | |
| Future<void> test_enum_constant() async { | |
| addTestFile(''' | |
| enum E { a, b } | |
| void f() { | |
| E.a; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('a;'); | |
| assertHasTarget('a,'); | |
| } | |
| Future<void> test_enum_constructor_named() async { | |
| addTestFile(''' | |
| const a = 0; | |
| enum E<T> { | |
| v<int>.named(a); // 1 | |
| E.named(int _) {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('v<int', 'named(int'); | |
| assertHasRegion('int>'); | |
| assertHasRegionTarget('named(a); // 1', 'named(int'); | |
| assertHasRegionTarget('a); // 1', 'a = 0'); | |
| assertHasRegion('int _'); | |
| } | |
| Future<void> test_enum_constructor_unnamed() async { | |
| addTestFile(''' | |
| enum E { | |
| v1, | |
| v2(), | |
| v3.new(); | |
| const E(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('v1', 'E();'); | |
| assertHasRegionTarget('v2()', 'E();'); | |
| assertHasRegionTarget('v3', 'E();'); | |
| assertHasRegionTarget('new()', 'E();'); | |
| } | |
| Future<void> test_enum_field() async { | |
| addTestFile(''' | |
| enum E { | |
| v; | |
| final int foo = 0; | |
| void bar() { | |
| foo; | |
| foo = 1; | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('int foo'); | |
| assertHasRegionTarget('foo;', 'foo = 0;'); | |
| assertHasRegionTarget('foo = 1;', 'foo = 0;'); | |
| } | |
| Future<void> test_enum_getter() async { | |
| addTestFile(''' | |
| enum E { | |
| v; | |
| int get foo => 0; | |
| void bar() { | |
| foo; | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('int get'); | |
| assertHasRegionTarget('foo;', 'foo =>'); | |
| } | |
| Future<void> test_enum_implements() async { | |
| addTestFile(''' | |
| class A {} | |
| enum E implements A { // ref | |
| v | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A { // ref', 'A {}'); | |
| } | |
| Future<void> test_enum_index() async { | |
| addTestFile(''' | |
| enum E { a, b } | |
| void f() { | |
| E.a.index; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('index'); | |
| assertHasTargetInDartCore('index => -1; // Enum'); | |
| } | |
| Future<void> test_enum_method() async { | |
| addTestFile(''' | |
| enum E { | |
| v; | |
| void foo(int a) {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('int '); | |
| } | |
| Future<void> test_enum_setter() async { | |
| addTestFile(''' | |
| enum E { | |
| v; | |
| set foo(int _) {} | |
| void bar() { | |
| foo = 0; | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('int _'); | |
| assertHasRegionTarget('foo = 0;', 'foo('); | |
| } | |
| Future<void> test_enum_typeParameter() async { | |
| addTestFile(''' | |
| enum E<T> { | |
| v(0); | |
| const E(T t); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('T t', 'T>'); | |
| } | |
| Future<void> test_enum_values() async { | |
| addTestFile(''' | |
| enum E { a, b } | |
| void f() { | |
| E.values; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('values'); | |
| assertHasTarget('E'); | |
| } | |
| Future<void> test_enum_with() async { | |
| addTestFile(''' | |
| mixin M {} | |
| enum E with M { // ref | |
| v | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('M { // ref', 'M {}'); | |
| } | |
| Future<void> test_extension_on() async { | |
| addTestFile(''' | |
| class C //1 | |
| {} | |
| extension E on C //2 | |
| {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('C //2'); | |
| assertHasTarget('C //1'); | |
| } | |
| Future<void> test_extensionType() async { | |
| addTestFile(''' | |
| extension type A(int it) { | |
| void foo() { | |
| it; // foo() | |
| } | |
| static void bar() {} | |
| } | |
| void f(A a) { | |
| A.it; // f() | |
| A(0); | |
| a.foo(); | |
| A.bar(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('int it'); | |
| assertHasRegionTarget('it; // foo()', 'it) {'); | |
| assertHasRegionTarget('A a)', 'A(int'); | |
| assertHasRegionTarget('it; // f()', 'it) {'); | |
| assertHasRegionTarget('A(0);', 'A(int'); | |
| assertHasRegionTarget('foo();', 'foo() {'); | |
| assertHasRegionTarget('A.bar()', 'A(int'); | |
| assertHasRegionTarget('bar();', 'bar() {}'); | |
| } | |
| Future<void> test_extensionType_inBodyConstructor_named() async { | |
| addTestFile(''' | |
| extension type A(int it) { | |
| A.named() : this(0); | |
| A.other() : this.named(1); | |
| } | |
| void f() { | |
| A.named(2); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A.named() :', 'A(int'); | |
| assertHasRegionTarget('named() :', 'named() :'); | |
| assertHasRegionTarget('this.named(1)', 'named() :'); | |
| assertHasRegionTarget('named(1)', 'named() :'); | |
| assertHasRegionTarget('A.named(2)', 'A(int'); | |
| assertHasRegionTarget('named(2)', 'named() :'); | |
| } | |
| Future<void> test_extensionType_primaryConstructor_named() async { | |
| addTestFile(''' | |
| extension type A.named(int it) { | |
| A.other() : this.named(0); | |
| } | |
| void f() { | |
| A.named(1); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A.named(int', 'A.named(int'); | |
| assertHasRegionTarget('named(int', 'named(int'); | |
| assertHasRegion('int it'); | |
| assertHasRegionTarget('it) {', 'it) {'); | |
| assertHasRegionTarget('this.named(0)', 'named(int'); | |
| assertHasRegionTarget('named(0)', 'named(int'); | |
| assertHasRegionTarget('A.named(1)', 'A.named(int'); | |
| assertHasRegionTarget('named(1)', 'named(int'); | |
| } | |
| Future<void> test_extensionType_primaryConstructor_unnamed() async { | |
| addTestFile(''' | |
| extension type A(int it) { | |
| A.other() : this(0); | |
| } | |
| void f() { | |
| A(1); | |
| A.new(2); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A(int', 'A(int'); | |
| assertHasRegion('int it'); | |
| assertHasRegionTarget('it) {', 'it) {'); | |
| assertHasRegionTarget('this(0)', 'A(int'); | |
| assertHasRegionTarget('A(1)', 'A(int'); | |
| assertHasRegionTarget('new(2)', 'A(int'); | |
| } | |
| Future<void> test_functionReference_className_staticMethod() async { | |
| addTestFile(''' | |
| class A { | |
| static void foo<T>() {} | |
| } | |
| void f() { | |
| A.foo<A>; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo<A>', 'foo<T>'); | |
| assertHasRegionTarget('A>', 'A {'); | |
| } | |
| Future<void> test_functionReference_function() async { | |
| addTestFile(''' | |
| class A {} | |
| void foo<T>() {} | |
| void f() { | |
| foo<A>; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo<A>', 'foo<T>'); | |
| assertHasRegionTarget('A>', 'A {'); | |
| } | |
| Future<void> test_functionReference_importPrefix_function() async { | |
| newFile('$testPackageLibPath/a.dart', r''' | |
| void foo<T>() {} | |
| '''); | |
| addTestFile(''' | |
| import 'a.dart' as prefix; | |
| class A {} | |
| void f() { | |
| prefix.foo<A>; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('prefix.', 'prefix;'); | |
| assertHasRegion('foo<A>'); | |
| assertHasRegionTarget('A>', 'A {'); | |
| } | |
| Future<void> test_functionReference_instance_method() async { | |
| addTestFile(''' | |
| class A { | |
| void foo<T>() {} | |
| } | |
| void f(A a) { | |
| a.foo<A>; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo<A>', 'foo<T>'); | |
| assertHasRegionTarget('A>', 'A {'); | |
| } | |
| Future<void> test_functionReference_method() async { | |
| addTestFile(''' | |
| class A { | |
| void foo<T>() {} | |
| void f() { | |
| foo<A>; | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo<A>', 'foo<T>'); | |
| assertHasRegionTarget('A>', 'A {'); | |
| } | |
| Future<void> test_functionReference_staticMethod() async { | |
| addTestFile(''' | |
| class A { | |
| static void foo<T>() {} | |
| void f() { | |
| foo<A>; | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo<A>', 'foo<T>'); | |
| assertHasRegionTarget('A>', 'A {'); | |
| } | |
| Future<void> test_identifier_resolved() async { | |
| addTestFile(''' | |
| class AAA {} | |
| void f() { | |
| AAA aaa = null; | |
| print(aaa); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('AAA aaa', 'AAA {}'); | |
| assertHasRegionTarget('aaa);', 'aaa = null'); | |
| assertHasRegionTarget('f() {', 'f() {'); | |
| } | |
| Future<void> test_identifier_unresolved() async { | |
| addTestFile(''' | |
| void f() { | |
| print(vvv); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionString('vvv'); | |
| } | |
| Future<void> test_identifier_whenStrayImportDirective() async { | |
| addTestFile(''' | |
| void f() { | |
| int aaa = 42; | |
| print(aaa); | |
| } | |
| import 'dart:math'; | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('aaa);', 'aaa = 42'); | |
| } | |
| Future<void> test_inComment() async { | |
| addTestFile(''' | |
| class FirstClass {} | |
| class SecondClass { | |
| /** | |
| * Return a [FirstClass] object equivalent to this object in every other way. | |
| */ | |
| convert() { | |
| return new FirstClass(); | |
| } | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('FirstClass]', 'FirstClass {'); | |
| assertHasRegionTarget('FirstClass(', 'FirstClass {'); | |
| } | |
| Future<void> test_inComment_docImportPrefix() async { | |
| newFile('$testPackageLibPath/a.dart', r''' | |
| class A {} | |
| '''); | |
| addTestFile(''' | |
| /// @docImport 'a.dart' as prefix; | |
| library; | |
| /// [prefix] and [prefix.A]. | |
| void f() {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('prefix]', 'prefix;'); | |
| assertHasRegionTarget('prefix.A]', 'prefix;'); | |
| assertHasRegion('A].'); | |
| } | |
| Future<void> test_inComment_enumMember_qualified() async { | |
| addTestFile(''' | |
| /// [A.one]. | |
| enum A { | |
| one, | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A.', 'A {'); | |
| assertHasRegionTarget('one]', 'one,'); | |
| } | |
| Future<void> test_inComment_extensionMember() async { | |
| addTestFile(''' | |
| /// [myField] | |
| extension on String { | |
| String get myField => ''; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('myField]', 'myField =>'); | |
| } | |
| Future<void> test_inComment_extensionMember_qualified() async { | |
| addTestFile(''' | |
| /// [StringExtension.myField] | |
| extension StringExtension on String { | |
| String get myField => ''; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('StringExtension.', 'StringExtension on'); | |
| assertHasRegionTarget('myField]', 'myField =>'); | |
| } | |
| Future<void> test_inComment_instanceMember_qualified() async { | |
| addTestFile(''' | |
| /// [A.myField]. | |
| class A { | |
| final String myField = ''; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A.', 'A {'); | |
| assertHasRegionTarget('myField]', 'myField ='); | |
| } | |
| Future<void> test_inComment_instanceMember_qualified_inherited() async { | |
| addTestFile(''' | |
| class A { | |
| final String myField = ''; | |
| } | |
| /// [B.myField]. | |
| class B extends A {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('B.', 'B extends'); | |
| assertHasRegionTarget('myField]', 'myField ='); | |
| } | |
| Future<void> test_inComment_namedConstructor_qualified() async { | |
| addTestFile(''' | |
| /// [A.named]. | |
| class A { | |
| A.named(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A.named]', 'A {'); | |
| assertHasRegionTarget('named]', 'named('); | |
| } | |
| Future<void> test_inComment_staticMember_qualified() async { | |
| addTestFile(''' | |
| /// [A.myStaticField]. | |
| class A { | |
| static final String myStaticField = ''; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A.', 'A {'); | |
| assertHasRegionTarget('myStaticField]', 'myStaticField ='); | |
| } | |
| Future<void> test_instanceCreation_implicit() async { | |
| addTestFile(''' | |
| class A { | |
| } | |
| void f() { | |
| new A(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionString('A()', 'A'.length); | |
| assertHasTarget('A {'); | |
| } | |
| Future<void> test_instanceCreation_implicit_withTypeArgument() async { | |
| addTestFile(''' | |
| class A {} | |
| class B<T> {} | |
| void f() { | |
| new B<A>(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegion('B<A>', length: 'B'.length); | |
| assertHasTarget('B<T> {'); | |
| } | |
| { | |
| assertHasRegion('A>();', length: 'A'.length); | |
| assertHasTarget('A {'); | |
| } | |
| } | |
| Future<void> test_instanceCreation_named() async { | |
| addTestFile(''' | |
| class A { | |
| A.named() {} | |
| } | |
| void f() { | |
| new A.named(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegionString('A.named();', 'A'.length); | |
| assertHasTarget('A {'); | |
| } | |
| { | |
| assertHasRegionString('named();', 'named'.length); | |
| assertHasTarget('named() {}'); | |
| } | |
| } | |
| Future<void> test_instanceCreation_named_withTypeArgument() async { | |
| addTestFile(''' | |
| class A {} | |
| class B<T> { | |
| B.named() {} | |
| } | |
| void f() { | |
| new B<A>.named(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegionString('B<A>', 'B'.length); | |
| assertHasTarget('B<T> {'); | |
| } | |
| { | |
| assertHasRegion('A>.named'); | |
| assertHasTarget('A {'); | |
| } | |
| { | |
| assertHasRegion('named();', length: 'named'.length); | |
| assertHasTarget('named() {}'); | |
| } | |
| } | |
| Future<void> test_instanceCreation_unnamed() async { | |
| addTestFile(''' | |
| class A { | |
| A() {} | |
| } | |
| void f() { | |
| new A(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionString('A();', 'A'.length); | |
| assertHasTarget('A() {}'); | |
| } | |
| Future<void> test_instanceCreation_unnamed_withTypeArgument() async { | |
| addTestFile(''' | |
| class A {} | |
| class B<T> { | |
| B() {} | |
| } | |
| void f() { | |
| new B<A>(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegionString('B<A>();', 'B'.length); | |
| assertHasTarget('B() {}'); | |
| } | |
| { | |
| assertHasRegion('A>();'); | |
| assertHasTarget('A {'); | |
| } | |
| } | |
| Future<void> test_instanceCreation_withImportPrefix_named() async { | |
| addTestFile(''' | |
| import 'dart:async' as ppp; | |
| void f() { | |
| new ppp.Future.value(42); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegion('ppp.'); | |
| assertHasTarget('ppp;'); | |
| } | |
| assertHasRegion('Future.value'); | |
| assertHasRegion('value(42)'); | |
| } | |
| Future<void> test_library() async { | |
| addTestFile(''' | |
| library my.lib; | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionString('my.lib'); | |
| assertHasTarget('library', length: 0); // line 0, col 0 for unit targets. | |
| } | |
| Future<void> | |
| test_libraryAugmentation_topLevelFunction_annotationConstructor_importPrefix() async { | |
| var a = newFile('$testPackageLibPath/a.dart', r''' | |
| class A { | |
| const A(); | |
| } | |
| '''); | |
| newFile('$testPackageLibPath/b.dart', r''' | |
| part 'test.dart'; | |
| '''); | |
| addTestFile(''' | |
| part of 'b.dart'; | |
| import 'a.dart' as prefix; | |
| @prefix.A() | |
| external B().foo(); | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion('prefix.A()'); | |
| assertHasTarget('prefix;'); | |
| assertHasRegion('A()'); | |
| assertHasTarget('A();', targetFile: a); | |
| } | |
| Future<void> test_multiplyDefinedElement() async { | |
| newFile('$testPackageLibPath/libA.dart', 'library A; int TEST = 1;'); | |
| newFile('$testPackageLibPath/libB.dart', 'library B; int TEST = 2;'); | |
| addTestFile(''' | |
| import 'libA.dart'; | |
| import 'libB.dart'; | |
| void f() { | |
| TEST; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('TEST'); | |
| } | |
| Future<void> test_namedExpression_name() async { | |
| addTestFile(''' | |
| void f(int a, int b, {int? c, int? d}) {} | |
| void g() { | |
| f(0, c: 2, 1, d: 3); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('c: 2', 'c,'); | |
| assertHasRegionTarget('d: 3', 'd}) {}'); | |
| } | |
| Future<void> test_navigation_dart_example_api() async { | |
| var exampleLinkPath = 'examples/api/lib/test_file.dart'; | |
| var exampleApiFile = convertPath(join(workspaceRootPath, exampleLinkPath)); | |
| newFile(exampleApiFile, '/// Test'); | |
| addTestFile(''' | |
| /// Dartdoc comment | |
| /// {@tool dartpad} | |
| /// Example description. | |
| /// | |
| /// ** See code in $exampleLinkPath ** | |
| /// {@end-tool} | |
| const int foo = 0; | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion(exampleLinkPath, length: 31); | |
| assertHasFileTarget(exampleApiFile, 0, 0); | |
| } | |
| Future<void> test_navigation_dart_example_api_multiple() async { | |
| var exampleLinkPath0 = 'examples/api/lib/test_file.0.dart'; | |
| var exampleLinkPath1 = 'examples/api/lib/test_file.1.dart'; | |
| var exampleApiFile0 = convertPath( | |
| join(workspaceRootPath, exampleLinkPath0), | |
| ); | |
| var exampleApiFile1 = convertPath( | |
| join(workspaceRootPath, exampleLinkPath1), | |
| ); | |
| newFile(exampleApiFile0, '/// Test 0'); | |
| newFile(exampleApiFile1, '/// Test 1'); | |
| addTestFile(''' | |
| /// Dartdoc comment | |
| /// {@tool dartpad} | |
| /// Example description. | |
| /// | |
| /// ** See code in $exampleLinkPath0 ** | |
| /// {@end-tool} | |
| /// | |
| /// {@tool dartpad} | |
| /// Example description. | |
| /// | |
| /// ** See code in $exampleLinkPath1 ** | |
| /// {@end-tool} | |
| const int foo = 0; | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegion(exampleLinkPath0, length: 33); | |
| assertHasFileTarget(exampleApiFile0, 0, 0); | |
| assertHasRegion(exampleLinkPath1, length: 33); | |
| assertHasFileTarget(exampleApiFile1, 0, 0); | |
| } | |
| Future<void> test_objectPattern_patternField_explicitlyNamed() async { | |
| addTestFile(''' | |
| class A { | |
| int get foo => 0; | |
| } | |
| void f(Object? x) { | |
| if (x case A(foo: var a)) {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo', 'foo =>'); | |
| } | |
| Future<void> test_objectPattern_patternField_implicitlyNamed() async { | |
| addTestFile(''' | |
| class A { | |
| int get foo => 0; | |
| } | |
| void f(Object? x) { | |
| if (x case A(: var foo)) {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('foo))', 'foo =>'); | |
| // Ensure the declared variable is a target even if it has no references. | |
| // Previously it would only be recorded via references and not from the | |
| // declaration itself. | |
| // https://github.com/dart-lang/sdk/issues/53554 | |
| assertHasTarget('foo))'); | |
| } | |
| Future<void> test_objectPattern_patternField_notResolved() async { | |
| addTestFile(''' | |
| class A {} | |
| void f(Object? x) { | |
| if (x case A(foo: var a)) {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('foo:'); | |
| } | |
| Future<void> test_operator_arithmetic() async { | |
| addTestFile(''' | |
| class A { | |
| A operator +(other) => null; | |
| A operator -() => null; | |
| A operator -(other) => null; | |
| A operator *(other) => null; | |
| A operator /(other) => null; | |
| } | |
| void f() { | |
| var a = new A(); | |
| a - 1; | |
| a + 2; | |
| -a; // unary | |
| --a; | |
| ++a; | |
| a--; // mm | |
| a++; // pp | |
| a -= 3; | |
| a += 4; | |
| a *= 5; | |
| a /= 6; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasOperatorRegion('- 1', 1, '-(other) => null', 1); | |
| assertHasOperatorRegion('+ 2', 1, '+(other) => null', 1); | |
| assertHasOperatorRegion('-a; // unary', 1, '-() => null', 1); | |
| assertHasOperatorRegion('--a;', 2, '-(other) => null', 1); | |
| assertHasOperatorRegion('++a;', 2, '+(other) => null', 1); | |
| assertHasOperatorRegion('--; // mm', 2, '-(other) => null', 1); | |
| assertHasOperatorRegion('++; // pp', 2, '+(other) => null', 1); | |
| assertHasOperatorRegion('-= 3', 2, '-(other) => null', 1); | |
| assertHasOperatorRegion('+= 4', 2, '+(other) => null', 1); | |
| assertHasOperatorRegion('*= 5', 2, '*(other) => null', 1); | |
| assertHasOperatorRegion('/= 6', 2, '/(other) => null', 1); | |
| } | |
| Future<void> test_operator_index() async { | |
| addTestFile(''' | |
| class A { | |
| A operator +(other) => null; | |
| } | |
| class B { | |
| A operator [](index) => null; | |
| operator []=(index, A value) {} | |
| } | |
| void f() { | |
| var b = new B(); | |
| b[0] // []; | |
| b[1] = 1; // []=; | |
| b[2] += 2; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasOperatorRegion('[0', 1, '[](index)', 2); | |
| assertHasOperatorRegion('] // []', 1, '[](index)', 2); | |
| assertHasOperatorRegion('[1', 1, '[]=(index,', 3); | |
| assertHasOperatorRegion('] = 1;', 1, '[]=(index,', 3); | |
| assertHasOperatorRegion('[2', 1, '[]=(index,', 3); | |
| assertHasOperatorRegion('] += 2;', 1, '[]=(index,', 3); | |
| assertHasOperatorRegion('+= 2;', 2, '+(other)', 1); | |
| } | |
| Future<void> test_partOf() async { | |
| var libCode = 'library lib; part "test.dart";'; | |
| var libFile = newFile('$testPackageLibPath/lib.dart', libCode).path; | |
| addTestFile('part of lib;'); | |
| await prepareNavigation(); | |
| assertHasRegionString('lib'); | |
| assertHasFileTarget(libFile, 0, 0); | |
| } | |
| Future<void> test_propertyAccess_propertyName_read() async { | |
| addTestFile(''' | |
| class A { | |
| var f = 0; | |
| } | |
| void f(A a) { | |
| a.f; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('f;', 'f = 0'); | |
| } | |
| Future<void> test_propertyAccess_propertyName_write() async { | |
| addTestFile(''' | |
| class A { | |
| var f = 0; | |
| } | |
| void f(A a) { | |
| a.f = 1; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('f = 1', 'f = 0'); | |
| } | |
| Future<void> test_recordPattern_patternField() async { | |
| addTestFile(''' | |
| void f(Object? x) { | |
| if (x case (foo: var a,)) {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('foo'); | |
| } | |
| Future<void> test_redirectingConstructorInvocation() async { | |
| addTestFile(''' | |
| class A { | |
| A() {} | |
| A.foo() : this(); | |
| A.bar() : this.foo(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegion('this();'); | |
| assertHasTarget('A() {}'); | |
| } | |
| { | |
| assertHasRegion('this.foo'); | |
| assertHasTarget('foo() :'); | |
| } | |
| { | |
| assertHasRegion('foo();'); | |
| assertHasTarget('foo() :'); | |
| } | |
| } | |
| Future<void> test_string_configuration() async { | |
| newFile('$testPackageLibPath/lib.dart', '').path; | |
| var lib2File = newFile('$testPackageLibPath/lib2.dart', '').path; | |
| newFile( | |
| testFilePath, | |
| 'import "lib.dart" if (dart.library.html) "lib2.dart";', | |
| ); | |
| await prepareNavigation(); | |
| assertHasRegionString('"lib2.dart"'); | |
| assertHasFileTarget(lib2File, 0, 0); | |
| } | |
| Future<void> test_string_export() async { | |
| var libCode = 'library lib;'; | |
| var libFile = newFile('$testPackageLibPath/lib.dart', libCode).path; | |
| addTestFile('export "lib.dart";'); | |
| await prepareNavigation(); | |
| assertHasRegionString('"lib.dart"'); | |
| assertHasFileTarget(libFile, 0, 0); | |
| } | |
| Future<void> test_string_export_unresolvedUri() async { | |
| addTestFile('export "no.dart";'); | |
| await prepareNavigation(); | |
| assertNoRegionString('"no.dart"'); | |
| } | |
| Future<void> test_string_import() async { | |
| var libCode = 'library lib;'; | |
| var libFile = newFile('$testPackageLibPath/lib.dart', libCode).path; | |
| addTestFile('import "lib.dart";'); | |
| await prepareNavigation(); | |
| assertHasRegionString('"lib.dart"'); | |
| assertHasFileTarget(libFile, 0, 0); | |
| } | |
| Future<void> test_string_import_noUri() async { | |
| addTestFile('import ;'); | |
| await prepareNavigation(); | |
| assertNoRegionAt('import ;'); | |
| } | |
| Future<void> test_string_import_unresolvedUri() async { | |
| addTestFile('import "no.dart";'); | |
| await prepareNavigation(); | |
| assertNoRegionString('"no.dart"'); | |
| } | |
| Future<void> test_string_part() async { | |
| var unitCode = 'part of lib; f() {}'; | |
| var unitFile = newFile('$testPackageLibPath/test_unit.dart', unitCode).path; | |
| addTestFile(''' | |
| library lib; | |
| part "test_unit.dart"; | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionString('"test_unit.dart"'); | |
| assertHasFileTarget(unitFile, 0, 0); | |
| } | |
| Future<void> test_string_part_hasSource_notPart() async { | |
| addTestFile(''' | |
| library lib; | |
| part "test_unit.dart"; | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionString('"test_unit.dart"'); | |
| } | |
| Future<void> test_string_part_invalidUri() async { | |
| addTestFile(''' | |
| part ":[invalid]"; | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionString('":[invalid]"'); | |
| } | |
| Future<void> test_superConstructorInvocation() async { | |
| addTestFile(''' | |
| class A { | |
| A() {} | |
| A.named() {} | |
| } | |
| class B extends A { | |
| B() : super(); | |
| B.named() : super.named(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| { | |
| assertHasRegionString('super'); | |
| assertHasTarget('A() {}'); | |
| } | |
| { | |
| assertHasRegion('super.named'); | |
| assertHasTarget('named() {}'); | |
| } | |
| { | |
| assertHasRegion('named();'); | |
| assertHasTarget('named() {}'); | |
| } | |
| } | |
| Future<void> test_superConstructorInvocation_synthetic() async { | |
| addTestFile(''' | |
| class A { | |
| } | |
| class B extends A { | |
| B() : super(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionString('super'); | |
| assertHasTarget('A {'); | |
| } | |
| Future<void> test_superFormalParameter_requiredNamed() async { | |
| addTestFile(''' | |
| class A { | |
| A({required int a}); | |
| } | |
| class B extends A { | |
| B({required super.a}) : assert(a > 0); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('a}) :', 'a});'); | |
| assertHasRegionTarget('a > 0', 'a}) :'); | |
| } | |
| Future<void> test_superFormalParameter_requiredPositional() async { | |
| addTestFile(''' | |
| class A { | |
| A(int a); | |
| } | |
| class B extends A { | |
| B(super.a) : assert(a > 0); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('super.a', 'a);'); | |
| assertHasRegionTarget('a) :', 'a);'); | |
| assertHasRegionTarget('a > 0', 'a) :'); | |
| } | |
| Future<void> | |
| test_superFormalParameter_requiredPositional_functionTyped() async { | |
| addTestFile(''' | |
| class A { | |
| A(Object a); // 0 | |
| } | |
| class B extends A { | |
| B(int super.a<T>(T b)) : assert(a is Object); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('a<T>', 'a); // 0'); | |
| assertHasRegion('int '); | |
| assertHasRegionTarget('T>', 'T>'); | |
| assertHasRegionTarget('T b', 'T>'); | |
| assertHasRegionTarget('b))', 'b))'); | |
| assertHasRegionTarget('b))', 'b))'); | |
| assertHasRegionTarget('a is', 'a<T>'); | |
| } | |
| Future<void> test_superFormalParameter_requiredPositional_unresolved() async { | |
| addTestFile(''' | |
| class A {} | |
| class B extends A { | |
| B(super.a); // 1 | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('a); // 1'); | |
| } | |
| Future<void> test_targetElement() async { | |
| addTestFile(''' | |
| class AAA {} | |
| void f() { | |
| AAA aaa = null; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('AAA aaa', 'AAA {}'); | |
| expect(testTarget.kind, ElementKind.CLASS); | |
| } | |
| Future<void> test_targetElement_atDeclaration_enum() async { | |
| addTestFile(''' | |
| enum E { one } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('E {', 'E {'); | |
| } | |
| Future<void> test_targetElement_atDeclaration_extension() async { | |
| addTestFile(''' | |
| extension E on String {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('E on', 'E on'); | |
| } | |
| Future<void> test_targetElement_atDeclaration_extensionType() async { | |
| addTestFile(''' | |
| extension type E(int it) {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('E(int', 'E(int'); | |
| } | |
| Future<void> test_targetElement_atDeclaration_mixin() async { | |
| addTestFile(''' | |
| mixin M {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('M {', 'M {'); | |
| } | |
| Future<void> test_targetElement_atDeclaration_typeAlias_functionType() async { | |
| addTestFile(''' | |
| typedef void F(); | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('F();', 'F();'); | |
| } | |
| Future<void> test_targetElement_atDeclaration_typeAlias_generic() async { | |
| addTestFile(''' | |
| typedef F = void Function(); | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('F =', 'F ='); | |
| } | |
| Future<void> test_targetElement_typedef_functionType() async { | |
| addTestFile(''' | |
| typedef A = void Function(); | |
| void f(A a) {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A a', 'A ='); | |
| expect(testTarget.kind, ElementKind.TYPE_ALIAS); | |
| } | |
| Future<void> test_targetElement_typedef_interfaceType() async { | |
| addTestFile(''' | |
| typedef A = List<int>; | |
| void f(A a) {} | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('A a', 'A ='); | |
| expect(testTarget.kind, ElementKind.TYPE_ALIAS); | |
| } | |
| Future<void> test_type_dynamic() async { | |
| addTestFile(''' | |
| void f() { | |
| dynamic v = null; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('dynamic'); | |
| } | |
| Future<void> test_type_void() async { | |
| addTestFile(''' | |
| void f() { | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('void'); | |
| } | |
| Future<void> test_var_declaredVariable() async { | |
| addTestFile(''' | |
| class C {} | |
| f(List<C> items) { | |
| for (var item in items) {} | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('var', 'C {}'); | |
| expect(testTarget.kind, ElementKind.CLASS); | |
| } | |
| Future<void> test_var_localVariable_multiple_inferred_different() async { | |
| addTestFile(''' | |
| class A {} | |
| class B {} | |
| void f() { | |
| var a = new A(), b = new B(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('var'); | |
| } | |
| Future<void> test_var_localVariable_multiple_inferred_same() async { | |
| addTestFile(''' | |
| class C {} | |
| void f() { | |
| var a = new C(), b = new C(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('var', 'C {}'); | |
| expect(testTarget.kind, ElementKind.CLASS); | |
| } | |
| Future<void> test_var_localVariable_single_inferred() async { | |
| addTestFile(''' | |
| class C {} | |
| f() { | |
| var c = new C(); | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('var', 'C {}'); | |
| expect(testTarget.kind, ElementKind.CLASS); | |
| } | |
| Future<void> test_var_localVariable_single_notInferred() async { | |
| addTestFile(''' | |
| f() { | |
| var x; | |
| } | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('var'); | |
| } | |
| Future<void> test_var_topLevelVariable_multiple_inferred_different() async { | |
| addTestFile(''' | |
| class A {} | |
| class B {} | |
| var a = new A(), b = new B(); | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('var'); | |
| } | |
| Future<void> test_var_topLevelVariable_multiple_inferred_same() async { | |
| addTestFile(''' | |
| class C {} | |
| var a = new C(), b = new C(); | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('var', 'C {}'); | |
| expect(testTarget.kind, ElementKind.CLASS); | |
| } | |
| Future<void> test_var_topLevelVariable_single_inferred() async { | |
| addTestFile(''' | |
| class C {} | |
| var c = new C(); | |
| '''); | |
| await prepareNavigation(); | |
| assertHasRegionTarget('var', 'C {}'); | |
| expect(testTarget.kind, ElementKind.CLASS); | |
| } | |
| Future<void> test_var_topLevelVariable_single_notInferred() async { | |
| addTestFile(''' | |
| var x; | |
| '''); | |
| await prepareNavigation(); | |
| assertNoRegionAt('var'); | |
| } | |
| } |