blob: a10b0e1690d8ba323ee63155877411e7f03563ba [file] [log] [blame]
// Copyright (c) 2018, 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 'driver_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(MethodInvocationResolutionTest);
});
}
@reflectiveTest
class MethodInvocationResolutionTest extends DriverResolutionTest {
test_error_abstractSuperMemberReference() async {
addTestFile(r'''
abstract class A {
void foo(int _);
}
abstract class B extends A {
void bar() {
super.foo(0);
}
void foo(int _) {} // does not matter
}
''');
await resolveTestFile();
assertTestErrors([CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE]);
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.method('foo', of: 'A'),
'(int) → void',
);
assertSuperExpression(invocation.target);
}
test_error_abstractSuperMemberReference_mixinHasNoSuchMethod() async {
addTestFile('''
class A {
int foo();
noSuchMethod(im) => 42;
}
class B extends Object with A {
foo() => super.foo(); // ref
noSuchMethod(im) => 87;
}
''');
await resolveTestFile();
assertTestErrors([CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE]);
var invocation = findNode.methodInvocation('foo(); // ref');
assertMethodInvocation(
invocation,
findElement.method('foo', of: 'A'),
'() → int',
);
assertSuperExpression(invocation.target);
}
test_error_abstractSuperMemberReference_OK_mixinHasConcrete() async {
addTestFile('''
class A {}
class M {
void foo(int _) {}
}
class B = A with M;
class C extends B {
void bar() {
super.foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.method('foo', of: 'M'),
'(int) → void',
);
assertSuperExpression(invocation.target);
}
test_error_abstractSuperMemberReference_OK_superHasNoSuchMethod() async {
addTestFile(r'''
class A {
int foo();
noSuchMethod(im) => 42;
}
class B extends A {
int foo() => super.foo(); // ref
noSuchMethod(im) => 87;
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('super.foo(); // ref');
assertMethodInvocation(
invocation,
findElement.method('foo', of: 'A'),
'() → int',
);
assertSuperExpression(invocation.target);
}
test_error_abstractSuperMemberReference_OK_superSuperHasConcrete() async {
addTestFile('''
abstract class A {
void foo(int _) {}
}
abstract class B extends A {
void foo(int _);
}
class C extends B {
void bar() {
super.foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.method('foo', of: 'A'),
'(int) → void',
);
assertSuperExpression(invocation.target);
}
test_error_ambiguousImport_topFunction() async {
newFile('/test/lib/a.dart', content: r'''
void foo(int _) {}
''');
newFile('/test/lib/b.dart', content: r'''
void foo(int _) {}
''');
addTestFile(r'''
import 'a.dart';
import 'b.dart';
main() {
foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.AMBIGUOUS_IMPORT,
]);
var invocation = findNode.methodInvocation('foo(0)');
assertInvokeType(invocation, '(int) → void');
assertType(invocation, 'void');
}
test_error_ambiguousImport_topFunction_prefixed() async {
newFile('/test/lib/a.dart', content: r'''
void foo(int _) {}
''');
newFile('/test/lib/b.dart', content: r'''
void foo(int _) {}
''');
addTestFile(r'''
import 'a.dart' as p;
import 'b.dart' as p;
main() {
p.foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.AMBIGUOUS_IMPORT,
]);
var invocation = findNode.methodInvocation('foo(0)');
assertInvokeType(invocation, '(int) → void');
assertType(invocation, 'void');
}
test_error_instanceAccessToStaticMember_method() async {
addTestFile(r'''
class A {
static void foo(int _) {}
}
main(A a) {
a.foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
]);
_assertInvalidInvocation(
'a.foo(0)',
findElement.method('foo'),
expectedNameType: '(int) → void',
);
}
test_error_invocationOfNonFunction_interface_hasCall_field() async {
addTestFile(r'''
class C {
void Function() call;
}
main(C c) {
c();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION,
]);
_assertInvalidInvocation(
'c()',
findElement.parameter('c'),
);
}
test_error_invocationOfNonFunction_localVariable() async {
addTestFile(r'''
main() {
Object foo;
foo();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION,
]);
_assertInvalidInvocation(
'foo()',
findElement.localVar('foo'),
expectedNameType: 'Object',
);
}
test_error_invocationOfNonFunction_OK_dynamic_localVariable() async {
addTestFile(r'''
main() {
var foo;
foo();
}
''');
await resolveTestFile();
assertNoTestErrors();
_assertInvalidInvocation('foo();', findElement.localVar('foo'));
}
test_error_invocationOfNonFunction_OK_dynamicGetter_instance() async {
addTestFile(r'''
class C {
var foo;
}
main(C c) {
c.foo();
}
''');
await resolveTestFile();
assertNoTestErrors();
_assertInvalidInvocation(
'c.foo();',
findElement.getter('foo'),
expectedMethodNameType: '() → dynamic',
);
}
test_error_invocationOfNonFunction_OK_dynamicGetter_superClass() async {
addTestFile(r'''
class A {
var foo;
}
class B extends A {
main() {
foo();
}
}
''');
await resolveTestFile();
assertNoTestErrors();
_assertInvalidInvocation(
'foo();',
findElement.getter('foo'),
expectedMethodNameType: '() → dynamic',
);
}
test_error_invocationOfNonFunction_OK_dynamicGetter_thisClass() async {
addTestFile(r'''
class C {
var foo;
main() {
foo();
}
}
''');
await resolveTestFile();
assertNoTestErrors();
_assertInvalidInvocation(
'foo();',
findElement.getter('foo'),
expectedMethodNameType: '() → dynamic',
);
}
test_error_invocationOfNonFunction_OK_Function() async {
addTestFile(r'''
f(Function foo) {
foo(1, 2);
}
''');
await resolveTestFile();
assertNoTestErrors();
_assertInvalidInvocation('foo(1, 2);', findElement.parameter('foo'));
}
test_error_invocationOfNonFunction_OK_functionTypeTypeParameter() async {
addTestFile(r'''
typedef MyFunction = double Function(int _);
class C<T extends MyFunction> {
T foo;
main() {
foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
assertMethodInvocation(
findNode.methodInvocation('foo(0)'),
findElement.getter('foo'),
'(int) → double',
expectedMethodNameType: '() → T',
);
}
test_error_invocationOfNonFunction_static_hasTarget() async {
addTestFile(r'''
class C {
static int foo;
}
main() {
C.foo();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION,
]);
_assertInvalidInvocation(
'foo()',
findElement.getter('foo'),
expectedMethodNameType: '() → int',
);
}
test_error_invocationOfNonFunction_static_noTarget() async {
addTestFile(r'''
class C {
static int foo;
main() {
foo();
}
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION,
]);
_assertInvalidInvocation(
'foo()',
findElement.getter('foo'),
expectedMethodNameType: '() → int',
);
}
test_error_invocationOfNonFunction_super_getter() async {
addTestFile(r'''
class A {
int get foo => 0;
}
class B extends A {
main() {
super.foo();
}
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION,
]);
_assertInvalidInvocation(
'foo()',
findElement.getter('foo'),
expectedMethodNameType: '() → int',
);
}
test_error_prefixIdentifierNotFollowedByDot() async {
newFile('/test/lib/a.dart', content: r'''
void foo() {}
''');
addTestFile(r'''
import 'a.dart' as prefix;
main() {
prefix?.foo();
}
''');
await resolveTestFile();
assertTestErrors([
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
]);
var import = _importFinder('package:test/a.dart');
var invocation = findNode.methodInvocation('foo();');
assertMethodInvocation(
invocation,
import.topFunction('foo'),
'() → void',
);
assertImportPrefix(invocation.target, import.prefix);
}
test_error_prefixIdentifierNotFollowedByDot_deferred() async {
addTestFile(r'''
import 'dart:math' deferred as math;
main() {
math?.loadLibrary();
}
''');
await resolveTestFile();
assertTestErrors([
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
]);
var import = _importFinder('dart:math');
var invocation = findNode.methodInvocation('loadLibrary()');
assertMethodInvocation(
invocation,
import.importedLibrary.loadLibraryFunction,
'() → Future<dynamic>',
);
assertImportPrefix(invocation.target, import.prefix);
}
test_error_prefixIdentifierNotFollowedByDot_invoke() async {
addTestFile(r'''
import 'dart:math' as foo;
main() {
foo();
}
''');
await resolveTestFile();
assertTestErrors([
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
]);
_assertInvalidInvocation(
'foo()',
findElement.import('dart:math').prefix,
dynamicNameType: true,
);
}
test_error_undefinedFunction() async {
addTestFile(r'''
main() {
foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_FUNCTION,
]);
_assertUnresolvedMethodInvocation('foo(0)');
}
test_error_undefinedFunction_hasTarget_importPrefix() async {
addTestFile(r'''
import 'dart:math' as math;
main() {
math.foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_FUNCTION,
]);
_assertUnresolvedMethodInvocation('foo(0);');
}
test_error_undefinedIdentifier_target() async {
addTestFile(r'''
main() {
bar.foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.UNDEFINED_IDENTIFIER,
]);
_assertUnresolvedMethodInvocation('foo(0);');
}
test_error_undefinedMethod_hasTarget_class() async {
addTestFile(r'''
class C {}
main() {
C.foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
_assertUnresolvedMethodInvocation('foo(0);');
}
test_error_undefinedMethod_hasTarget_class_arguments() async {
addTestFile(r'''
class C {}
int x;
main() {
C.foo(x);
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
_assertUnresolvedMethodInvocation('foo(x);');
assertTopGetRef('x)', 'x');
}
test_error_undefinedMethod_hasTarget_class_inSuperclass() async {
addTestFile(r'''
class S {
static void foo(int _) {}
}
class C extends S {}
main() {
C.foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
_assertUnresolvedMethodInvocation('foo(0);');
}
test_error_undefinedMethod_hasTarget_class_typeArguments() async {
addTestFile(r'''
class C {}
main() {
C.foo<int>();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
_assertUnresolvedMethodInvocation('foo<int>();');
assertTypeName(findNode.typeName('int>'), intElement, 'int');
}
test_error_undefinedMethod_hasTarget_class_typeParameter() async {
addTestFile(r'''
class C<T> {
static main() => C.T();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
_assertUnresolvedMethodInvocation('C.T();');
}
test_error_undefinedMethod_hasTarget_instance() async {
addTestFile(r'''
main() {
42.foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
_assertUnresolvedMethodInvocation('foo(0);');
}
test_error_undefinedMethod_hasTarget_localVariable_function() async {
addTestFile(r'''
main() {
var v = () {};
v.foo(0);
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
_assertUnresolvedMethodInvocation('foo(0);');
}
test_error_undefinedMethod_noTarget() async {
addTestFile(r'''
class C {
main() {
foo(0);
}
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
_assertUnresolvedMethodInvocation('foo(0);');
}
test_error_undefinedMethod_object_call() async {
addTestFile(r'''
main(Object o) {
o.call();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
}
test_error_undefinedMethod_OK_null() async {
addTestFile(r'''
main() {
null.foo();
}
''');
await resolveTestFile();
assertNoTestErrors();
_assertUnresolvedMethodInvocation('foo();');
}
test_error_undefinedMethod_private() async {
newFile('/test/lib/a.dart', content: r'''
class A {
void _foo(int _) {}
}
''');
addTestFile(r'''
import 'a.dart';
class B extends A {
main() {
_foo(0);
}
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
_assertUnresolvedMethodInvocation('_foo(0);');
}
test_error_undefinedMethod_typeLiteral_cascadeTarget() async {
addTestFile(r'''
class C {
static void foo() {}
}
main() {
C..foo();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
}
test_error_undefinedMethod_typeLiteral_conditional() async {
// When applied to a type literal, the conditional access operator '?.'
// cannot be used to access instance methods of Type.
addTestFile(r'''
class A {}
main() {
A?.toString();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_METHOD,
]);
}
test_error_undefinedSuperMethod() async {
addTestFile(r'''
class A {}
class B extends A {
void foo(int _) {
super.foo(0);
}
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNDEFINED_SUPER_METHOD,
]);
_assertUnresolvedMethodInvocation('foo(0);');
assertSuperExpression(findNode.super_('super.foo'));
}
test_error_unqualifiedReferenceToNonLocalStaticMember_method() async {
addTestFile(r'''
class A {
static void foo() {}
}
class B extends A {
main() {
foo(0);
}
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
]);
_assertInvalidInvocation(
'foo(0)',
findElement.method('foo'),
expectedNameType: '(int) → void',
);
}
/// 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.
test_error_uriDoesNotExist_prefixed() async {
addTestFile(r'''
import 'missing.dart' as p;
main() {
p.foo(1);
p.bar(2);
}
''');
await resolveTestFile();
assertTestErrors([
CompileTimeErrorCode.URI_DOES_NOT_EXIST,
]);
_assertUnresolvedMethodInvocation('foo(1);');
_assertUnresolvedMethodInvocation('bar(2);');
}
/// 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.
test_error_uriDoesNotExist_show() async {
addTestFile(r'''
import 'missing.dart' show foo, bar;
main() {
foo(1);
bar(2);
}
''');
await resolveTestFile();
assertTestErrors([
CompileTimeErrorCode.URI_DOES_NOT_EXIST,
]);
_assertUnresolvedMethodInvocation('foo(1);');
_assertUnresolvedMethodInvocation('bar(2);');
}
test_error_useOfVoidResult_name_getter() async {
addTestFile(r'''
class C<T>{
T foo;
}
main(C<void> c) {
c.foo();
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.USE_OF_VOID_RESULT,
]);
_assertInvalidInvocation(
'c.foo()',
findElement.getter('foo'),
expectedNameType: 'void',
expectedMethodNameType: '() → void',
);
}
test_error_useOfVoidResult_name_localVariable() async {
addTestFile(r'''
main() {
void foo;
foo();
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.USE_OF_VOID_RESULT,
]);
_assertInvalidInvocation(
'foo()',
findElement.localVar('foo'),
expectedNameType: 'void',
);
}
test_error_useOfVoidResult_name_topFunction() async {
addTestFile(r'''
void foo() {}
main() {
foo()();
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.USE_OF_VOID_RESULT,
]);
assertMethodInvocation(
findNode.methodInvocation('foo()()'),
findElement.topFunction('foo'),
'() → void',
);
}
test_error_useOfVoidResult_name_topVariable() async {
addTestFile(r'''
void foo;
main() {
foo();
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.USE_OF_VOID_RESULT,
]);
_assertInvalidInvocation(
'foo()',
findElement.topGet('foo'),
expectedNameType: 'void',
expectedMethodNameType: '() → void',
);
}
test_error_useOfVoidResult_receiver() async {
addTestFile(r'''
main() {
void foo;
foo.toString();
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.USE_OF_VOID_RESULT,
]);
// TODO(scheglov) Resolve fully, or don't resolve at all.
assertMethodInvocation(
findNode.methodInvocation('toString()'),
null,
'() → String',
);
}
test_error_useOfVoidResult_receiver_cascade() async {
addTestFile(r'''
main() {
void foo;
foo..toString();
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.USE_OF_VOID_RESULT,
]);
// TODO(scheglov) Resolve fully, or don't resolve at all.
assertMethodInvocation(
findNode.methodInvocation('toString()'),
null,
'() → String',
);
}
test_error_useOfVoidResult_receiver_withNull() async {
addTestFile(r'''
main() {
void foo;
foo?.toString();
}
''');
await resolveTestFile();
assertTestErrors([
StaticWarningCode.USE_OF_VOID_RESULT,
]);
// TODO(scheglov) Resolve fully, or don't resolve at all.
assertMethodInvocation(
findNode.methodInvocation('toString()'),
null,
'() → String',
);
}
test_error_wrongNumberOfTypeArgumentsMethod_01() async {
addTestFile(r'''
void foo() {}
main() {
foo<int>();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
]);
assertMethodInvocation(
findNode.methodInvocation('foo<int>()'),
findElement.topFunction('foo'),
'() → void',
);
assertTypeName(findNode.typeName('int>'), intElement, 'int');
}
test_error_wrongNumberOfTypeArgumentsMethod_21() async {
addTestFile(r'''
Map<T, U> foo<T extends num, U>() => null;
main() {
foo<int>();
}
''');
await resolveTestFile();
assertTestErrors([
StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD,
]);
assertMethodInvocation(
findNode.methodInvocation('foo<int>()'),
findElement.topFunction('foo'),
'() → Map<num, dynamic>',
);
assertTypeName(findNode.typeName('int>'), intElement, 'int');
}
test_hasReceiver_class_staticGetter() async {
addTestFile(r'''
class C {
static double Function(int) get foo => null;
}
main() {
C.foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0);');
assertMethodInvocation(
invocation,
findElement.getter('foo'),
'(int) → double',
expectedMethodNameType: '() → (int) → double',
);
assertClassRef(invocation.target, findElement.class_('C'));
}
test_hasReceiver_class_staticMethod() async {
addTestFile(r'''
class C {
static void foo(int _) {}
}
main() {
C.foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0);');
assertMethodInvocation(
invocation,
findElement.method('foo'),
'(int) → void',
);
assertClassRef(invocation.target, findElement.class_('C'));
}
test_hasReceiver_deferredImportPrefix_loadLibrary() async {
addTestFile(r'''
import 'dart:math' deferred as math;
main() {
math.loadLibrary();
}
''');
await resolveTestFile();
assertNoTestErrors();
var import = _importFinder('dart:math');
var invocation = findNode.methodInvocation('loadLibrary()');
assertMethodInvocation(
invocation,
import.importedLibrary.loadLibraryFunction,
'() → Future<dynamic>',
);
assertImportPrefix(invocation.target, import.prefix);
}
test_hasReceiver_functionTyped_call() async {
addTestFile(r'''
void foo(int _) {}
main() {
foo.call(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('call(0)');
assertMethodInvocation(
invocation,
null,
'(int) → void',
);
assertElement(invocation.target, findElement.topFunction('foo'));
assertType(invocation.target, '(int) → void');
}
test_hasReceiver_importPrefix_topFunction() async {
newFile('/test/lib/a.dart', content: r'''
T foo<T extends num>(T a, T b) => a;
''');
addTestFile(r'''
import 'a.dart' as prefix;
main() {
prefix.foo(1, 2);
}
''');
await resolveTestFile();
assertNoTestErrors();
var import = _importFinder('package:test/a.dart');
var invocation = findNode.methodInvocation('foo(1, 2)');
assertMethodInvocation(
invocation,
import.topFunction('foo'),
'(int, int) → int',
);
assertImportPrefix(invocation.target, import.prefix);
}
test_hasReceiver_importPrefix_topGetter() async {
newFile('/test/lib/a.dart', content: r'''
T Function<T>(T a, T b) get foo => null;
''');
addTestFile(r'''
import 'a.dart' as prefix;
main() {
prefix.foo(1, 2);
}
''');
await resolveTestFile();
assertNoTestErrors();
var import = _importFinder('package:test/a.dart');
var invocation = findNode.methodInvocation('foo(1, 2)');
assertMethodInvocation(
invocation,
import.topGetter('foo'),
'(int, int) → int',
expectedMethodNameType: '() → <T>(T, T) → T',
);
assertImportPrefix(invocation.target, import.prefix);
}
test_hasReceiver_instance_Function_call_localVariable() async {
addTestFile(r'''
void main() {
Function foo;
foo.call(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
_assertInvalidInvocation('call(0)', null);
}
test_hasReceiver_instance_Function_call_topVariable() async {
addTestFile(r'''
Function foo;
void main() {
foo.call(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
_assertInvalidInvocation('call(0)', null);
}
test_hasReceiver_instance_getter() async {
addTestFile(r'''
class C {
double Function(int) get foo => null;
}
main(C c) {
c.foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0);');
assertMethodInvocation(
invocation,
findElement.getter('foo'),
'(int) → double',
expectedMethodNameType: '() → (int) → double',
);
}
test_hasReceiver_instance_method() async {
addTestFile(r'''
class C {
void foo(int _) {}
}
main(C c) {
c.foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0);');
assertMethodInvocation(
invocation,
findElement.method('foo'),
'(int) → void',
expectedMethodNameType: '(int) → void',
);
}
test_hasReceiver_instance_method_generic() async {
addTestFile(r'''
class C {
T foo<T>(T a) {
return a;
}
}
main(C c) {
c.foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0);');
assertMethodInvocation(
invocation,
findElement.method('foo'),
'(int) → int',
expectedMethodNameType: '(int) → int',
);
}
test_hasReceiver_instance_method_issue30552() async {
addTestFile(r'''
abstract class I1 {
void foo(int i);
}
abstract class I2 {
void foo(Object o);
}
abstract class C implements I1, I2 {}
class D extends C {
void foo(Object o) {}
}
void main(C c) {
c.foo('hi');
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation("foo('hi')");
assertMethodInvocation(
invocation,
findElement.method('foo', of: 'I2'),
'(Object) → void',
);
}
test_hasReceiver_instance_typeParameter() async {
addTestFile(r'''
class A {
void foo(int _) {}
}
class C<T extends A> {
T a;
main() {
a.foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0);');
assertMethodInvocation(
invocation,
findElement.method('foo'),
'(int) → void',
);
}
test_hasReceiver_prefixed_class_staticGetter() async {
newFile('/test/lib/a.dart', content: r'''
class C {
static double Function(int) get foo => null;
}
''');
addTestFile(r'''
import 'a.dart' as prefix;
main() {
prefix.C.foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var import = _importFinder('package:test/a.dart');
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
import.class_('C').getGetter('foo'),
'(int) → double',
expectedMethodNameType: '() → (int) → double',
);
PrefixedIdentifier target = invocation.target;
assertImportPrefix(target.prefix, import.prefix);
assertClassRef(target.identifier, import.class_('C'));
}
test_hasReceiver_prefixed_class_staticMethod() async {
newFile('/test/lib/a.dart', content: r'''
class C {
static void foo(int _) => null;
}
''');
addTestFile(r'''
import 'a.dart' as prefix;
main() {
prefix.C.foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var import = _importFinder('package:test/a.dart');
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
import.class_('C').getMethod('foo'),
'(int) → void',
);
PrefixedIdentifier target = invocation.target;
assertImportPrefix(target.prefix, import.prefix);
assertClassRef(target.identifier, import.class_('C'));
}
test_hasReceiver_super_getter() async {
addTestFile(r'''
class A {
double Function(int) get foo => null;
}
class B extends A {
void bar() {
super.foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0);');
assertMethodInvocation(
invocation,
findElement.getter('foo', of: 'A'),
'(int) → double',
expectedMethodNameType: '() → (int) → double',
);
assertSuperExpression(invocation.target);
}
test_hasReceiver_super_method() async {
addTestFile(r'''
class A {
void foo(int _) {}
}
class B extends A {
void foo(int _) {
super.foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0);');
assertMethodInvocation(
invocation,
findElement.method('foo', of: 'A'),
'(int) → void',
);
assertSuperExpression(invocation.target);
}
test_namedArgument() async {
addTestFile(r'''
void foo({int a, bool b}) {}
main() {
foo(b: false, a: 0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(b:');
assertMethodInvocation(
invocation,
findElement.topFunction('foo'),
'({a: int, b: bool}) → void',
);
assertNamedParameterRef('b: false', 'b');
assertNamedParameterRef('a: 0', 'a');
}
test_noReceiver_getter_superClass() async {
addTestFile(r'''
class A {
double Function(int) get foo => null;
}
class B extends A {
void bar() {
foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.getter('foo'),
'(int) → double',
expectedMethodNameType: '() → (int) → double',
);
}
test_noReceiver_getter_thisClass() async {
addTestFile(r'''
class C {
double Function(int) get foo => null;
void bar() {
foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.getter('foo'),
'(int) → double',
expectedMethodNameType: '() → (int) → double',
);
}
test_noReceiver_importPrefix() async {
addTestFile(r'''
import 'dart:math' as math;
main() {
math();
}
''');
await resolveTestFile();
assertTestErrors([
CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
]);
assertElement(findNode.simple('math()'), findElement.prefix('math'));
}
test_noReceiver_localFunction() async {
addTestFile(r'''
main() {
void foo(int _) {}
foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.localFunction('foo'),
'(int) → void',
);
}
test_noReceiver_localVariable() async {
addTestFile(r'''
main() {
void Function(int) foo;
foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.localVar('foo'),
'(int) → void',
);
}
test_noReceiver_localVariable_call() async {
addTestFile(r'''
class C {
void call(int _) {}
}
main(C c) {
c(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('c(0);');
assertMethodInvocation(
invocation,
findElement.parameter('c'),
'(int) → void',
);
}
test_noReceiver_localVariable_promoted() async {
addTestFile(r'''
main() {
var foo;
if (foo is void Function(int)) {
foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.localVar('foo'),
'(int) → void',
);
}
test_noReceiver_method_superClass() async {
addTestFile(r'''
class A {
void foo(int _) {}
}
class B extends A {
void bar() {
foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.method('foo'),
'(int) → void',
);
}
test_noReceiver_method_thisClass() async {
addTestFile(r'''
class C {
void foo(int _) {}
void bar() {
foo(0);
}
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.method('foo'),
'(int) → void',
);
}
test_noReceiver_topFunction() async {
addTestFile(r'''
void foo(int _) {}
main() {
foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.topFunction('foo'),
'(int) → void',
expectedMethodNameType: '(int) → void',
);
}
test_noReceiver_topGetter() async {
addTestFile(r'''
double Function(int) get foo => null;
main() {
foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.topGet('foo'),
'(int) → double',
expectedMethodNameType: '() → (int) → double',
);
}
test_noReceiver_topVariable() async {
addTestFile(r'''
void Function(int) foo;
main() {
foo(0);
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('foo(0)');
assertMethodInvocation(
invocation,
findElement.topGet('foo'),
'(int) → void',
expectedMethodNameType: '() → (int) → void',
);
}
test_objectMethodOnDynamic() async {
addTestFile(r'''
main() {
var v;
v.toString(42);
}
''');
await resolveTestFile();
assertNoTestErrors();
_assertUnresolvedMethodInvocation('toString(42);');
}
test_objectMethodOnFunction() async {
addTestFile(r'''
void f() {}
main() {
f.toString();
}
''');
await resolveTestFile();
assertNoTestErrors();
var invocation = findNode.methodInvocation('toString();');
assertMethodInvocation(
invocation,
typeProvider.objectType.getMethod('toString'),
'() → String',
);
}
void _assertInvalidInvocation(String search, Element expectedElement,
{String expectedMethodNameType,
String expectedNameType,
bool dynamicNameType: false}) {
var invocation = findNode.methodInvocation(search);
if (dynamicNameType) {
assertTypeDynamic(invocation.methodName);
}
// TODO(scheglov) I think `invokeType` should be `null`.
assertMethodInvocation(
invocation,
expectedElement,
'dynamic',
expectedMethodNameType: expectedMethodNameType,
expectedNameType: expectedNameType,
expectedType: 'dynamic',
);
}
void _assertUnresolvedMethodInvocation(String search) {
// TODO(scheglov) clean up
_assertInvalidInvocation(search, null);
// var invocation = findNode.methodInvocation(search);
// assertTypeDynamic(invocation.methodName);
// // TODO(scheglov) I think `invokeType` should be `null`.
// assertMethodInvocation(
// invocation,
// null,
// 'dynamic',
// expectedType: 'dynamic',
// );
}
_ImportElementFinder _importFinder(String targetUri) {
var import = findElement.import(targetUri);
return _ImportElementFinder(import);
}
}
class _ImportElementFinder {
final ImportElement import;
_ImportElementFinder(this.import);
CompilationUnitElement get definingUnit {
return importedLibrary.definingCompilationUnit;
}
LibraryElement get importedLibrary => import.importedLibrary;
PrefixElement get prefix => import.prefix;
ClassElement class_(String name) {
for (var class_ in definingUnit.types) {
if (class_.name == name) {
return class_;
}
}
fail('Not found class: $name');
}
FunctionElement topFunction(String name) {
for (var function in definingUnit.functions) {
if (function.name == name) {
return function;
}
}
fail('Not found top-level function: $name');
}
PropertyAccessorElement topGetter(String name) {
for (var accessor in definingUnit.accessors) {
if (accessor.name == name && accessor.isGetter) {
return accessor;
}
}
fail('Not found top-level getter: $name');
}
}