blob: b65716890fbe413185eb36d6fdfd4c583b7c28d6 [file] [log] [blame]
// 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_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 [testTargetIndexes] 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, regionLength);
assertHasTarget(targetSearch, 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]) {
var offset = findOffset(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 targetLength = -1}) {
assertHasRegion(regionSearch);
assertHasTarget(targetSearch, 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 an leading identifier in [search].
void assertHasTarget(String search, [int length = -1]) {
var offset = findOffset(search);
if (length == -1) {
length = findIdentifierLength(search);
}
assertHasFileTarget(testFile.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 a target in [testTargets] with [testFile], at the
/// offset of [str] in [testFile], and with the length of [str].
void assertHasTargetString(String str) {
assertHasTarget(str, str.length);
}
/// Validates that there is no 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 no a region at [search] with any length.
void assertNoRegionAt(String search) {
var offset = findOffset(search);
findRegion(offset, -1, false);
}
/// Validates that there is no 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 this it into [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 == false) {
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 == true) {
fail('Expected to find (offset=$offset; length=$length) in\n'
'${regions.join('\n')}');
}
}
}
@reflectiveTest
class AnalysisNotificationNavigationTest extends AbstractNavigationTest {
final Completer<void> _resultsAvailable = Completer();
Future<void> prepareNavigation() async {
await handleSuccessfulRequest(
AnalysisSetSubscriptionsParams({
AnalysisService.NAVIGATION: [testFile.path],
}).toRequest('0'),
);
await _resultsAvailable.future;
assertRegionsSorted();
}
@override
void processNotification(Notification notification) {
if (notification.event == ANALYSIS_NOTIFICATION_NAVIGATION) {
var params = AnalysisNavigationParams.fromNotification(notification);
if (params.file == testFile.path) {
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_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()
main() {
}
''');
await prepareNavigation();
assertHasRegionString('A()', 'A'.length);
assertHasTarget('A {');
}
Future<void> test_annotationConstructor_importPrefix() async {
newFile2('$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()
main() {
}
''');
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)
main() {
}
''');
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()
main() {
}
''');
await prepareNavigation();
assertHasRegionString('A()', 'A'.length);
assertHasTarget('A();');
}
Future<void> test_annotationField() async {
addTestFile('''
const myan = new Object();
@myan // ref
main() {
}
''');
await prepareNavigation();
assertHasRegion('myan // ref');
assertHasTarget('myan = new Object();');
}
Future<void> test_annotationField_importPrefix() async {
newFile2('$testPackageLibPath/mayn.dart', r'''
library an;
const myan = new Object();
''');
addTestFile('''
import 'mayn.dart' as man;
@man.myan // ref
main() {
}
''');
await prepareNavigation();
assertHasRegion('myan // ref');
}
Future<void> test_class_constructor_named() async {
addTestFile('''
class A {
A.named(BBB p) {}
}
class BBB {}
''');
await prepareNavigation();
// has region for complete "A.named"
assertHasRegionString('A.named');
assertHasTarget('named(BBB');
// no separate regions for "A" and "named"
assertNoRegion('A.named(', 'A'.length);
assertNoRegion('named(', 'named'.length);
// 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;', 'named();');
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;', 'new();');
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('named();');
}
{
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('named() {}');
}
{
assertHasRegion('A>.named');
assertHasTarget('A {');
}
{
assertHasRegion('named;', '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() async {
addTestFile('''
class AAA {
int fff = 123;
AAA(this.fff);
}
''');
await prepareNavigation();
assertHasRegionTarget('fff);', 'fff = 123');
}
Future<void> test_class_fieldFormalParameter_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_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;');
}
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_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 {
newFile2('$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 {}
main() {
AAA aaa = null;
print(aaa);
}
''');
await prepareNavigation();
assertHasRegionTarget('AAA aaa', 'AAA {}');
assertHasRegionTarget('aaa);', 'aaa = null');
assertHasRegionTarget('main() {', 'main() {');
}
Future<void> test_identifier_unresolved() async {
addTestFile('''
main() {
print(vvv);
}
''');
await prepareNavigation();
assertNoRegionString('vvv');
}
Future<void> test_identifier_whenStrayImportDirective() async {
addTestFile('''
main() {
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_instanceCreation_implicit() async {
addTestFile('''
class A {
}
main() {
new A();
}
''');
await prepareNavigation();
assertHasRegionString('A()', 'A'.length);
assertHasTarget('A {');
}
Future<void> test_instanceCreation_implicit_withTypeArgument() async {
addTestFile('''
class A {}
class B<T> {}
main() {
new B<A>();
}
''');
await prepareNavigation();
{
assertHasRegion('B<A>', 'B'.length);
assertHasTarget('B<T> {');
}
{
assertHasRegion('A>();', 'A'.length);
assertHasTarget('A {');
}
}
Future<void> test_instanceCreation_named() async {
addTestFile('''
class A {
A.named() {}
}
main() {
new A.named();
}
''');
await prepareNavigation();
{
assertHasRegionString('A.named();', 'A'.length);
assertHasTarget('named() {}');
}
{
assertHasRegionString('named();', 'named'.length);
assertHasTarget('named() {}');
}
}
Future<void> test_instanceCreation_named_withTypeArgument() async {
addTestFile('''
class A {}
class B<T> {
B.named() {}
}
main() {
new B<A>.named();
}
''');
await prepareNavigation();
{
assertHasRegionString('B<A>', 'B'.length);
assertHasTarget('named() {}');
}
{
assertHasRegion('A>.named');
assertHasTarget('A {');
}
{
assertHasRegion('named();', 'named'.length);
assertHasTarget('named() {}');
}
}
Future<void> test_instanceCreation_unnamed() async {
addTestFile('''
class A {
A() {}
}
main() {
new A();
}
''');
await prepareNavigation();
assertHasRegionString('A();', 'A'.length);
assertHasTarget('A() {}');
}
Future<void> test_instanceCreation_unnamed_withTypeArgument() async {
addTestFile('''
class A {}
class B<T> {
B() {}
}
main() {
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;
main() {
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');
assertHasTargetString('my.lib');
}
Future<void> test_multiplyDefinedElement() async {
newFile2('$testPackageLibPath/libA.dart', 'library A; int TEST = 1;');
newFile2('$testPackageLibPath/libB.dart', 'library B; int TEST = 2;');
addTestFile('''
import 'libA.dart';
import 'libB.dart';
main() {
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_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;
}
main() {
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) {}
}
main() {
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 = newFile2('$testPackageLibPath/lib.dart', libCode).path;
addTestFile('part of lib;');
await prepareNavigation();
assertHasRegionString('lib');
assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
}
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_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 {
newFile2('$testPackageLibPath/lib.dart', '').path;
var lib2File = newFile2('$testPackageLibPath/lib2.dart', '').path;
newFile2(
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 = newFile2('$testPackageLibPath/lib.dart', libCode).path;
addTestFile('export "lib.dart";');
await prepareNavigation();
assertHasRegionString('"lib.dart"');
assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
}
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 = newFile2('$testPackageLibPath/lib.dart', libCode).path;
addTestFile('import "lib.dart";');
await prepareNavigation();
assertHasRegionString('"lib.dart"');
assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
}
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 =
newFile2('$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_invalidUri() async {
addTestFile('''
part ":[invalid]";
''');
await prepareNavigation();
assertNoRegionString('":[invalid]"');
}
Future<void> test_string_part_unresolvedUri() async {
addTestFile('''
library lib;
part "test_unit.dart";
''');
await prepareNavigation();
assertNoRegionString('"test_unit.dart"');
}
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}); // 0
}
class B extends A {
B({required super.a}); // 1
}
''');
await prepareNavigation();
assertHasRegionTarget('a}); // 1', 'a}); // 0');
}
Future<void> test_superFormalParameter_requiredPositional() async {
addTestFile('''
class A {
A(int a); // 0
}
class B extends A {
B(super.a); // 1
}
''');
await prepareNavigation();
assertHasRegionTarget('super.a', 'a); // 0');
assertHasRegionTarget('a); // 1', 'a); // 0');
}
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)); // 1
}
''');
await prepareNavigation();
assertHasRegionTarget('a<T>', 'a); // 0');
assertHasRegion('int ');
assertHasRegionTarget('T>', 'T>');
assertHasRegionTarget('T b', 'T>');
assertHasRegionTarget('b))', 'b))');
}
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 {}
main() {
AAA aaa = null;
}
''');
await prepareNavigation();
assertHasRegionTarget('AAA aaa', 'AAA {}');
expect(testTarget.kind, ElementKind.CLASS);
}
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('''
main() {
dynamic v = null;
}
''');
await prepareNavigation();
assertNoRegionAt('dynamic');
}
Future<void> test_type_void() async {
addTestFile('''
void main() {
}
''');
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');
}
}