blob: a4d99bb410beb0ebf0133c912920f593dd1f8dde [file] [log] [blame]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../src/dart/resolution/driver_resolution.dart';
import 'resolver_test_case.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(SimpleResolverTest);
});
}
@reflectiveTest
class SimpleResolverTest extends DriverResolutionTest {
test_argumentResolution_required_matching() async {
addTestFile(r'''
class A {
void f() {
g(1, 2, 3);
}
void g(a, b, c) {}
}''');
await _validateArgumentResolution([0, 1, 2]);
}
test_argumentResolution_required_tooFew() async {
addTestFile(r'''
class A {
void f() {
g(1, 2);
}
void g(a, b, c) {}
}''');
await _validateArgumentResolution([0, 1]);
}
test_argumentResolution_required_tooMany() async {
addTestFile(r'''
class A {
void f() {
g(1, 2, 3);
}
void g(a, b) {}
}''');
await _validateArgumentResolution([0, 1, -1]);
}
test_argumentResolution_requiredAndNamed_extra() async {
addTestFile('''
class A {
void f() {
g(1, 2, c: 3, d: 4);
}
void g(a, b, {c}) {}
}''');
await _validateArgumentResolution([0, 1, 2, -1]);
}
test_argumentResolution_requiredAndNamed_matching() async {
addTestFile(r'''
class A {
void f() {
g(1, 2, c: 3);
}
void g(a, b, {c}) {}
}''');
await _validateArgumentResolution([0, 1, 2]);
}
test_argumentResolution_requiredAndNamed_missing() async {
addTestFile('''
class A {
void f() {
g(1, 2, d: 3);
}
void g(a, b, {c, d}) {}
}''');
await _validateArgumentResolution([0, 1, 3]);
}
test_argumentResolution_requiredAndPositional_fewer() async {
addTestFile('''
class A {
void f() {
g(1, 2, 3);
}
void g(a, b, [c, d]) {}
}''');
await _validateArgumentResolution([0, 1, 2]);
}
test_argumentResolution_requiredAndPositional_matching() async {
addTestFile(r'''
class A {
void f() {
g(1, 2, 3, 4);
}
void g(a, b, [c, d]) {}
}''');
await _validateArgumentResolution([0, 1, 2, 3]);
}
test_argumentResolution_requiredAndPositional_more() async {
addTestFile(r'''
class A {
void f() {
g(1, 2, 3, 4);
}
void g(a, b, [c]) {}
}''');
await _validateArgumentResolution([0, 1, 2, -1]);
}
test_argumentResolution_setter_propagated() async {
addTestFile(r'''
main() {
var a = new A();
a.sss = 0;
}
class A {
set sss(x) {}
}''');
await resolveTestFile();
var rhs = findNode.assignment(' = 0;').rightHandSide;
expect(
rhs.staticParameterElement,
findElement.parameter('x'),
);
}
test_argumentResolution_setter_propagated_propertyAccess() async {
addTestFile(r'''
main() {
var a = new A();
a.b.sss = 0;
}
class A {
B b = new B();
}
class B {
set sss(x) {}
}''');
await resolveTestFile();
var rhs = findNode.assignment(' = 0;').rightHandSide;
expect(
rhs.staticParameterElement,
findElement.parameter('x'),
);
}
test_argumentResolution_setter_static() async {
addTestFile(r'''
main() {
A a = new A();
a.sss = 0;
}
class A {
set sss(x) {}
}''');
await resolveTestFile();
var rhs = findNode.assignment(' = 0;').rightHandSide;
expect(
rhs.staticParameterElement,
findElement.parameter('x'),
);
}
test_argumentResolution_setter_static_propertyAccess() async {
addTestFile(r'''
main() {
A a = new A();
a.b.sss = 0;
}
class A {
B b = new B();
}
class B {
set sss(x) {}
}''');
await resolveTestFile();
var rhs = findNode.assignment(' = 0;').rightHandSide;
expect(
rhs.staticParameterElement,
findElement.parameter('x'),
);
}
test_breakTarget_labeled() async {
// Verify that the target of the label is correctly found and is recorded
// as the unlabeled portion of the statement.
addTestFile(r'''
void f() {
loop1: while (true) {
loop2: for (int i = 0; i < 10; i++) {
break loop1;
break loop2;
}
}
}
''');
await resolveTestFile();
var break1 = findNode.breakStatement('break loop1;');
var whileStatement = findNode.whileStatement('while (');
expect(break1.target, same(whileStatement));
var break2 = findNode.breakStatement('break loop2;');
var forStatement = findNode.forStatement('for (');
expect(break2.target, same(forStatement));
}
test_breakTarget_unlabeledBreakFromDo() async {
addTestFile('''
void f() {
do {
break;
} while (true);
}
''');
await resolveTestFile();
var doStatement = findNode.doStatement('do {');
var breakStatement = findNode.breakStatement('break;');
expect(breakStatement.target, same(doStatement));
}
test_breakTarget_unlabeledBreakFromFor() async {
addTestFile(r'''
void f() {
for (int i = 0; i < 10; i++) {
break;
}
}
''');
await resolveTestFile();
var forStatement = findNode.forStatement('for (');
var breakStatement = findNode.breakStatement('break;');
expect(breakStatement.target, same(forStatement));
}
test_breakTarget_unlabeledBreakFromForEach() async {
addTestFile('''
void f() {
for (x in []) {
break;
}
}
''');
await resolveTestFile();
var forStatement = findNode.forEachStatement('for (');
var breakStatement = findNode.breakStatement('break;');
expect(breakStatement.target, same(forStatement));
}
test_breakTarget_unlabeledBreakFromSwitch() async {
addTestFile(r'''
void f() {
while (true) {
switch (0) {
case 0:
break;
}
}
}
''');
await resolveTestFile();
var switchStatement = findNode.switchStatement('switch (');
var breakStatement = findNode.breakStatement('break;');
expect(breakStatement.target, same(switchStatement));
}
test_breakTarget_unlabeledBreakFromWhile() async {
addTestFile(r'''
void f() {
while (true) {
break;
}
}
''');
await resolveTestFile();
var whileStatement = findNode.whileStatement('while (');
var breakStatement = findNode.breakStatement('break;');
expect(breakStatement.target, same(whileStatement));
}
test_breakTarget_unlabeledBreakToOuterFunction() async {
// Verify that unlabeled break statements can't resolve to loops in an
// outer function.
addTestFile(r'''
void f() {
while (true) {
void g() {
break;
}
}
}
''');
await resolveTestFile();
var breakStatement = findNode.breakStatement('break;');
expect(breakStatement.target, isNull);
}
test_class_definesCall() async {
await assertNoErrorsInCode(r'''
class A {
int call(int x) { return x; }
}
int f(A a) {
return a(0);
}''');
}
test_class_extends_implements() async {
await assertNoErrorsInCode(r'''
class A extends B implements C {}
class B {}
class C {}''');
}
test_continueTarget_labeled() async {
// Verify that the target of the label is correctly found and is recorded
// as the unlabeled portion of the statement.
addTestFile('''
void f() {
loop1: while (true) {
loop2: for (int i = 0; i < 10; i++) {
continue loop1;
continue loop2;
}
}
}
''');
await resolveTestFile();
var continue1 = findNode.continueStatement('continue loop1');
var whileStatement = findNode.whileStatement('while (');
expect(continue1.target, same(whileStatement));
var continue2 = findNode.continueStatement('continue loop2');
var forStatement = findNode.forStatement('for (');
expect(continue2.target, same(forStatement));
}
test_continueTarget_unlabeledContinueFromDo() async {
addTestFile('''
void f() {
do {
continue;
} while (true);
}
''');
await resolveTestFile();
var doStatement = findNode.doStatement('do {');
var continueStatement = findNode.continueStatement('continue;');
expect(continueStatement.target, same(doStatement));
}
test_continueTarget_unlabeledContinueFromFor() async {
addTestFile('''
void f() {
for (int i = 0; i < 10; i++) {
continue;
}
}
''');
await resolveTestFile();
var forStatement = findNode.forStatement('for (');
var continueStatement = findNode.continueStatement('continue;');
expect(continueStatement.target, same(forStatement));
}
test_continueTarget_unlabeledContinueFromForEach() async {
addTestFile(r'''
void f() {
for (x in []) {
continue;
}
}
''');
await resolveTestFile();
var forStatement = findNode.forEachStatement('for (');
var continueStatement = findNode.continueStatement('continue;');
expect(continueStatement.target, same(forStatement));
}
test_continueTarget_unlabeledContinueFromWhile() async {
addTestFile(r'''
void f() {
while (true) {
continue;
}
}
''');
await resolveTestFile();
var whileStatement = findNode.whileStatement('while (');
var continueStatement = findNode.continueStatement('continue;');
expect(continueStatement.target, same(whileStatement));
}
test_continueTarget_unlabeledContinueSkipsSwitch() async {
addTestFile(r'''
void f() {
while (true) {
switch (0) {
case 0:
continue;
}
}
}
''');
await resolveTestFile();
var whileStatement = findNode.whileStatement('while (');
var continueStatement = findNode.continueStatement('continue;');
expect(continueStatement.target, same(whileStatement));
}
test_continueTarget_unlabeledContinueToOuterFunction() async {
// Verify that unlabeled continue statements can't resolve to loops in an
// outer function.
addTestFile(r'''
void f() {
while (true) {
void g() {
continue;
}
}
}
''');
await resolveTestFile();
var continueStatement = findNode.continueStatement('continue;');
expect(continueStatement.target, isNull);
}
test_empty() async {
addTestFile('');
await resolveTestFile();
assertNoTestErrors();
}
test_entryPoint_exported() async {
newFile('/test/lib/a.dart', content: r'''
main() {}
''');
addTestFile(r'''
export 'a.dart';
''');
await resolveTestFile();
assertNoTestErrors();
var library = result.libraryElement;
var main = library.entryPoint;
expect(main, isNotNull);
expect(main.library, isNot(same(library)));
}
test_entryPoint_local() async {
addTestFile(r'''
main() {}
''');
await resolveTestFile();
assertNoTestErrors();
var library = result.libraryElement;
var main = library.entryPoint;
expect(main, isNotNull);
expect(main.library, same(library));
}
test_entryPoint_none() async {
addTestFile('');
await resolveTestFile();
assertNoTestErrors();
var library = result.libraryElement;
expect(library.entryPoint, isNull);
}
test_enum_externalLibrary() async {
newFile('/test/lib/a.dart', content: r'''
enum EEE {A, B, C}
''');
addTestFile(r'''
import 'a.dart';
void f(EEE e) {}
''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
test_extractedMethodAsConstant() async {
await assertNoErrorsInCode(r'''
abstract class Comparable<T> {
int compareTo(T other);
static int compare(Comparable a, Comparable b) => a.compareTo(b);
}
class A {
void sort([compare = Comparable.compare]) {}
}''');
verifyTestResolved();
}
test_fieldFormalParameter() async {
addTestFile(r'''
class A {
int x;
int y;
A(this.x) : y = x {}
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var xParameter = findNode.fieldFormalParameter('this.x');
var xParameterElement =
xParameter.declaredElement as FieldFormalParameterElement;
expect(xParameterElement.field, findElement.field('x'));
assertElement(
findNode.simple('x {}'),
xParameterElement,
);
}
test_forEachLoops_nonConflicting() async {
await assertNoErrorsInCode(r'''
f() {
List list = [1,2,3];
for (int x in list) {}
for (int x in list) {}
}''');
verifyTestResolved();
}
test_forLoops_nonConflicting() async {
await assertNoErrorsInCode(r'''
f() {
for (int i = 0; i < 3; i++) {
}
for (int i = 0; i < 3; i++) {
}
}''');
verifyTestResolved();
}
test_functionTypeAlias() async {
await assertNoErrorsInCode(r'''
typedef bool P(e);
class A {
P p;
m(e) {
if (p(e)) {}
}
}''');
verifyTestResolved();
}
test_getter_and_setter_fromMixins_bare_identifier() async {
addTestFile('''
class B {}
class M1 {
get x => null;
set x(value) {}
}
class M2 {
get x => null;
set x(value) {}
}
class C extends B with M1, M2 {
void f() {
x += 1;
}
}
''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
// Verify that both the getter and setter for "x" in C.f() refer to the
// accessors defined in M2.
var leftHandSide = findNode.simple('x +=');
expect(
leftHandSide.staticElement,
findElement.setter('x', of: 'M2'),
);
expect(
leftHandSide.auxiliaryElements.staticElement,
findElement.getter('x', of: 'M2'),
);
}
@failingTest
test_getter_and_setter_fromMixins_property_access() async {
// TODO(paulberry): it appears that auxiliaryElements isn't properly set on
// a SimpleIdentifier that's inside a property access. This bug should be
// fixed.
addTestFile(r'''
class B {}
class M1 {
get x => null;
set x(value) {}
}
class M2 {
get x => null;
set x(value) {}
}
class C extends B with M1, M2 {}
void main() {
new C().x += 1;
}
''');
assertNoTestErrors();
verifyTestResolved();
// Verify that both the getter and setter for "x" in "new C().x" refer to
// the accessors defined in M2.
var leftHandSide = findNode.simple('x +=');
expect(
leftHandSide.staticElement,
findElement.setter('x', of: 'M2'),
);
expect(
leftHandSide.auxiliaryElements.staticElement,
findElement.getter('x', of: 'M2'),
);
}
test_getter_fromMixins_bare_identifier() async {
addTestFile('''
class B {}
class M1 {
get x => null;
}
class M2 {
get x => null;
}
class C extends B with M1, M2 {
f() {
return x;
}
}
''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
// Verify that the getter for "x" in C.f() refers to the getter defined in
// M2.
expect(
findNode.simple('x;').staticElement,
findElement.getter('x', of: 'M2'),
);
}
test_getter_fromMixins_property_access() async {
addTestFile('''
class B {}
class M1 {
get x => null;
}
class M2 {
get x => null;
}
class C extends B with M1, M2 {}
void main() {
var y = new C().x;
}
''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
// Verify that the getter for "x" in "new C().x" refers to the getter
// defined in M2.
expect(
findNode.simple('x;').staticElement,
findElement.getter('x', of: 'M2'),
);
}
test_getterAndSetterWithDifferentTypes() async {
addTestFile(r'''
class A {
int get f => 0;
void set f(String s) {}
}
g (A a) {
a.f = a.f.toString();
}''');
await resolveTestFile();
assertTestErrors([StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES]);
verifyTestResolved();
}
test_hasReferenceToSuper() async {
addTestFile(r'''
class A {}
class B {toString() => super.toString();}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var a = findElement.class_('A');
expect(a.hasReferenceToSuper, isFalse);
var b = findElement.class_('B');
expect(b.hasReferenceToSuper, isTrue);
}
test_import_hide() async {
newFile('/test/lib/lib1.dart', content: r'''
set foo(value) {}
class A {}''');
newFile('/test/lib/lib2.dart', content: r'''
set foo(value) {}''');
addTestFile(r'''
import 'lib1.dart' hide foo;
import 'lib2.dart';
main() {
foo = 0;
}
A a;''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
test_import_prefix() async {
newFile('/test/lib/a.dart', content: r'''
f(int x) {
return x * x;
}''');
addTestFile(r'''
import 'a.dart' as _a;
main() {
_a.f(0);
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
test_import_prefix_doesNotExist() async {
//
// The primary purpose of this test is to ensure that we are only getting a
// single error generated when the only problem is that an imported file
// does not exist.
//
addTestFile('''
import 'missing.dart' as p;
int a = p.q + p.r.s;
String b = p.t(a) + p.u(v: 0);
p.T c = new p.T();
class D<E> extends p.T {
D(int i) : super(i);
p.U f = new p.V();
}
class F implements p.T {
p.T m(p.U u) => null;
}
class G extends Object with p.V {}
class H extends D<p.W> {
H(int i) : super(i);
}
''');
await resolveTestFile();
assertTestErrors([CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
verifyTestResolved();
}
test_import_show_doesNotExist() async {
//
// The primary purpose of this test is to ensure that we are only getting a
// single error generated when the only problem is that an imported file
// does not exist.
//
addTestFile('''
import 'missing.dart' show q, r, t, u, T, U, V, W;
int a = q + r.s;
String b = t(a) + u(v: 0);
T c = new T();
class D<E> extends T {
D(int i) : super(i);
U f = new V();
}
class F implements T {
T m(U u) => null;
}
class G extends Object with V {}
class H extends D<W> {
H(int i) : super(i);
}
''');
await resolveTestFile();
assertTestErrors([CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
verifyTestResolved();
}
@failingTest
test_import_spaceInUri() async {
// TODO(scheglov) Fix this. The problem is in `package` URI resolver.
newFile('/test/lib/sub folder/a.dart', content: r'''
foo() {}''');
await assertNoErrorsInCode(r'''
import 'sub folder/a.dart';
main() {
foo();
}''');
verifyTestResolved();
}
test_indexExpression_typeParameters() async {
await assertNoErrorsInCode(r'''
f() {
List<int> a;
a[0];
List<List<int>> b;
b[0][0];
List<List<List<int>>> c;
c[0][0][0];
}''');
verifyTestResolved();
}
test_indexExpression_typeParameters_invalidAssignmentWarning() async {
addTestFile(r'''
f() {
List<List<int>> b;
b[0][0] = 'hi';
}''');
await resolveTestFile();
assertTestErrors([StaticTypeWarningCode.INVALID_ASSIGNMENT]);
verifyTestResolved();
}
test_indirectOperatorThroughCall() async {
await assertNoErrorsInCode(r'''
class A {
B call() { return new B(); }
}
class B {
int operator [](int i) { return i; }
}
A f = new A();
g(int x) {}
main() {
g(f()[0]);
}''');
verifyTestResolved();
}
test_invoke_dynamicThroughGetter() async {
await assertNoErrorsInCode(r'''
class A {
List get X => [() => 0];
m(A a) {
X.last;
}
}''');
verifyTestResolved();
}
test_isValidMixin_badSuperclass() async {
addTestFile(r'''
class A extends B {}
class B {}
class C = Object with A;''');
await resolveTestFile();
assertTestErrors([CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT]);
verifyTestResolved();
var a = findElement.class_('A');
expect(a.isValidMixin, isFalse);
}
test_isValidMixin_constructor() async {
addTestFile(r'''
class A {
A() {}
}
class C = Object with A;''');
await resolveTestFile();
assertTestErrors(
[CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR],
);
verifyTestResolved();
var a = findElement.class_('A');
expect(a.isValidMixin, isFalse);
}
test_isValidMixin_factoryConstructor() async {
addTestFile(r'''
class A {
factory A() => null;
}
class C = Object with A;''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var a = findElement.class_('A');
expect(a.isValidMixin, isTrue);
}
test_isValidMixin_super() async {
addTestFile(r'''
class A {
toString() {
return super.toString();
}
}
class C = Object with A;''');
await resolveTestFile();
assertTestErrors([CompileTimeErrorCode.MIXIN_REFERENCES_SUPER]);
verifyTestResolved();
var a = findElement.class_('A');
expect(a.isValidMixin, isFalse);
}
test_isValidMixin_valid() async {
await assertNoErrorsInCode('''
class A {}
class C = Object with A;''');
verifyTestResolved();
var a = findElement.class_('A');
expect(a.isValidMixin, isTrue);
}
test_labels_switch() async {
await assertNoErrorsInCode(r'''
void doSwitch(int target) {
switch (target) {
l0: case 0:
continue l1;
l1: case 1:
continue l0;
default:
continue l1;
}
}''');
verifyTestResolved();
}
test_localVariable_types_invoked() async {
addTestFile(r'''
const A = null;
main() {
var myVar = (int p) => 'foo';
myVar(42);
}''');
await resolveTestFile();
var node = findNode.simple('myVar(42)');
assertType(node, '(int) → String');
}
test_metadata_class() async {
addTestFile(r'''
const A = null;
@A class C<A> {}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var annotations = findElement.class_('C').metadata;
expect(annotations, hasLength(1));
var cDeclaration = findNode.classDeclaration('C<A>');
assertElement(
cDeclaration.metadata[0].name,
findElement.topGet('A'),
);
}
test_metadata_field() async {
addTestFile(r'''
const A = null;
class C {
@A int f;
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var metadata = findElement.field('f').metadata;
expect(metadata, hasLength(1));
}
test_metadata_fieldFormalParameter() async {
addTestFile(r'''
const A = null;
class C {
int f;
C(@A this.f);
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var metadata = findElement.fieldFormalParameter('f').metadata;
expect(metadata, hasLength(1));
}
test_metadata_function() async {
addTestFile(r'''
const A = null;
@A f() {}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var annotations = findElement.topFunction('f').metadata;
expect(annotations, hasLength(1));
}
test_metadata_functionTypedParameter() async {
addTestFile(r'''
const A = null;
f(@A int p(int x)) {}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var metadata = findElement.parameter('p').metadata;
expect(metadata, hasLength(1));
}
test_metadata_libraryDirective() async {
addTestFile(r'''
@A library lib;
const A = null;''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var metadata = result.libraryElement.metadata;
expect(metadata, hasLength(1));
}
test_metadata_method() async {
addTestFile(r'''
const A = null;
class C {
@A void m() {}
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var metadata = findElement.method('m').metadata;
expect(metadata, hasLength(1));
}
test_metadata_namedParameter() async {
addTestFile(r'''
const A = null;
f({@A int p : 0}) {}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var metadata = findElement.parameter('p').metadata;
expect(metadata, hasLength(1));
}
test_metadata_positionalParameter() async {
addTestFile(r'''
const A = null;
f([@A int p = 0]) {}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
var metadata = findElement.parameter('p').metadata;
expect(metadata, hasLength(1));
}
test_metadata_simpleParameter() async {
addTestFile(r'''
const A = null;
f(@A p1, @A int p2) {}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
expect(findElement.parameter('p1').metadata, hasLength(1));
expect(findElement.parameter('p2').metadata, hasLength(1));
}
test_metadata_typedef() async {
addTestFile(r'''
const A = null;
@A typedef F<A>();''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
expect(
findElement.genericTypeAlias('F').metadata,
hasLength(1),
);
var actualElement = findNode.annotation('@A').name.staticElement;
expect(actualElement, findElement.topGet('A'));
}
test_method_fromMixin() async {
addTestFile(r'''
class B {
bar() => 1;
}
class A {
foo() => 2;
}
class C extends B with A {
bar() => super.bar();
foo() => super.foo();
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
test_method_fromMixins() async {
addTestFile('''
class B {}
class M1 {
void f() {}
}
class M2 {
void f() {}
}
class C extends B with M1, M2 {}
void main() {
new C().f();
}
''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
expect(
findNode.simple('f();').staticElement,
findElement.method('f', of: 'M2'),
);
}
test_method_fromMixins_bare_identifier() async {
addTestFile('''
class B {}
class M1 {
void f() {}
}
class M2 {
void f() {}
}
class C extends B with M1, M2 {
void g() {
f();
}
}
''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
expect(
findNode.simple('f();').staticElement,
findElement.method('f', of: 'M2'),
);
}
test_method_fromMixins_invoked_from_outside_class() async {
addTestFile('''
class B {}
class M1 {
void f() {}
}
class M2 {
void f() {}
}
class C extends B with M1, M2 {}
void main() {
new C().f();
}
''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
expect(
findNode.simple('f();').staticElement,
findElement.method('f', of: 'M2'),
);
}
test_method_fromSuperclassMixin() async {
addTestFile(r'''
class A {
void m1() {}
}
class B extends Object with A {
}
class C extends B {
}
f(C c) {
c.m1();
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
test_methodCascades() async {
addTestFile(r'''
class A {
void m1() {}
void m2() {}
void m() {
A a = new A();
a..m1()
..m2();
}
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
test_methodCascades_withSetter() async {
addTestFile(r'''
class A {
String name;
void m1() {}
void m2() {}
void m() {
A a = new A();
a..m1()
..name = 'name'
..m2();
}
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
test_resolveAgainstNull() async {
addTestFile(r'''
f(var p) {
return null == p;
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
test_setter_fromMixins_bare_identifier() async {
addTestFile('''
class B {}
class M1 {
set x(value) {}
}
class M2 {
set x(value) {}
}
class C extends B with M1, M2 {
void f() {
x = 1;
}
}
''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
expect(
findNode.simple('x = ').staticElement,
findElement.setter('x', of: 'M2'),
);
}
test_setter_fromMixins_property_access() async {
addTestFile('''
class B {}
class M1 {
set x(value) {}
}
class M2 {
set x(value) {}
}
class C extends B with M1, M2 {}
void main() {
new C().x = 1;
}
''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
expect(
findNode.simple('x = ').staticElement,
findElement.setter('x', of: 'M2'),
);
}
test_setter_inherited() async {
addTestFile(r'''
class A {
int get x => 0;
set x(int p) {}
}
class B extends A {
int get x => super.x == null ? 0 : super.x;
int f() => x = 1;
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
test_setter_static() async {
addTestFile(r'''
set s(x) {
}
main() {
s = 123;
}''');
await resolveTestFile();
assertNoTestErrors();
verifyTestResolved();
}
/**
* Verify that all of the identifiers in the [result] have been resolved.
*/
void verifyTestResolved() {
var verifier = new ResolutionVerifier();
result.unit.accept(verifier);
verifier.assertResolved();
}
/**
* Resolve the test file and verify that the arguments in a specific method
* invocation were correctly resolved.
*
* The file is expected to define a method named `g`, and has exactly one
* [MethodInvocation] in a statement ending with `);`. It is the arguments to
* that method invocation that are tested. The method invocation can contain
* errors.
*
* The arguments were resolved correctly if the number of expressions in the list matches the
* length of the array of indices and if, for each index in the array of indices, the parameter to
* which the argument expression was resolved is the parameter in the invoked method's list of
* parameters at that index. Arguments that should not be resolved to a parameter because of an
* error can be denoted by including a negative index in the array of indices.
*
* @param indices the array of indices used to associate arguments with parameters
* @throws Exception if the source could not be resolved or if the structure of the source is not
* valid
*/
Future<void> _validateArgumentResolution(List<int> indices) async {
await resolveTestFile();
var g = findElement.method('g');
var parameters = g.parameters;
var invocation = findNode.methodInvocation(');');
var arguments = invocation.argumentList.arguments;
var argumentCount = arguments.length;
expect(argumentCount, indices.length);
for (var i = 0; i < argumentCount; i++) {
var argument = arguments[i];
var actualParameter = argument.staticParameterElement;
var index = indices[i];
if (index < 0) {
expect(actualParameter, isNull);
} else {
var expectedParameter = parameters[index];
expect(actualParameter, same(expectedParameter));
}
}
}
}