8d983debe0
+ fix some typos Change-Id: Ic4f05cc57130657445f3c2f5312998d018f56a8e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/483540 Reviewed-by: Samuel Rawlins <srawlins@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
2201 lines
48 KiB
Dart
2201 lines
48 KiB
Dart
// 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_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_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_extensionType_secondaryConstructor_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_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_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');
|
|
}
|
|
}
|