| // Copyright (c) 2020, 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/src/error/codes.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import '../dart/resolution/context_collection_resolution.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(AbstractSuperMemberReferenceTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class AbstractSuperMemberReferenceTest extends PubPackageResolutionTest { |
| test_methodInvocation_mixin_implements() async { |
| await assertErrorsInCode(r''' |
| class A { |
| void foo(int _) {} |
| } |
| |
| mixin M implements A { |
| void bar() { |
| super.foo(0); |
| } |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 82, 3), |
| ]); |
| |
| var node = findNode.methodInvocation('super.foo(0)'); |
| assertResolvedNodeText(node, r''' |
| MethodInvocation |
| target: SuperExpression |
| superKeyword: super |
| staticType: M |
| operator: . |
| methodName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@method::foo |
| staticType: void Function(int) |
| argumentList: ArgumentList |
| leftParenthesis: ( |
| arguments |
| IntegerLiteral |
| literal: 0 |
| parameter: <testLibraryFragment>::@class::A::@method::foo::@parameter::_ |
| staticType: int |
| rightParenthesis: ) |
| staticInvokeType: void Function(int) |
| staticType: void |
| '''); |
| } |
| |
| test_methodInvocation_mixinHasConcrete() async { |
| await assertNoErrorsInCode(''' |
| class A {} |
| |
| mixin M { |
| void foo() {} |
| } |
| |
| class B = A with M; |
| |
| class C extends B { |
| void bar() { |
| super.foo(); |
| } |
| } |
| '''); |
| |
| var node = findNode.methodInvocation('super.foo()'); |
| assertResolvedNodeText(node, r''' |
| MethodInvocation |
| target: SuperExpression |
| superKeyword: super |
| staticType: C |
| operator: . |
| methodName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@mixin::M::@method::foo |
| staticType: void Function() |
| argumentList: ArgumentList |
| leftParenthesis: ( |
| rightParenthesis: ) |
| staticInvokeType: void Function() |
| staticType: void |
| '''); |
| } |
| |
| test_methodInvocation_mixinHasNoSuchMethod() async { |
| await assertErrorsInCode(''' |
| mixin A { |
| void foo(); |
| noSuchMethod(im) => 42; |
| } |
| |
| class B extends Object with A { |
| void foo() => super.foo(); // ref |
| noSuchMethod(im) => 87; |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 107, 3), |
| ]); |
| |
| var node = findNode.methodInvocation('super.foo()'); |
| assertResolvedNodeText(node, r''' |
| MethodInvocation |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| methodName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@mixin::A::@method::foo |
| staticType: void Function() |
| argumentList: ArgumentList |
| leftParenthesis: ( |
| rightParenthesis: ) |
| staticInvokeType: void Function() |
| staticType: void |
| '''); |
| } |
| |
| test_methodInvocation_superHasAbstract() async { |
| await assertErrorsInCode(r''' |
| abstract class A { |
| void foo(int _); |
| } |
| |
| abstract class B extends A { |
| void bar() { |
| super.foo(0); |
| } |
| |
| void foo(int _) {} // does not matter |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 95, 3), |
| ]); |
| |
| var node = findNode.methodInvocation('super.foo(0)'); |
| assertResolvedNodeText(node, r''' |
| MethodInvocation |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| methodName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@method::foo |
| staticType: void Function(int) |
| argumentList: ArgumentList |
| leftParenthesis: ( |
| arguments |
| IntegerLiteral |
| literal: 0 |
| parameter: <testLibraryFragment>::@class::A::@method::foo::@parameter::_ |
| staticType: int |
| rightParenthesis: ) |
| staticInvokeType: void Function(int) |
| staticType: void |
| '''); |
| } |
| |
| test_methodInvocation_superHasConcrete_mixinHasAbstract() async { |
| await assertNoErrorsInCode(''' |
| class A { |
| void foo() {} |
| } |
| |
| mixin B { |
| void foo(); |
| } |
| |
| class C extends A with B { |
| void bar() { |
| super.foo(); // ref |
| } |
| } |
| '''); |
| |
| var node = findNode.methodInvocation('foo(); // ref'); |
| assertResolvedNodeText(node, r''' |
| MethodInvocation |
| target: SuperExpression |
| superKeyword: super |
| staticType: C |
| operator: . |
| methodName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@method::foo |
| staticType: void Function() |
| argumentList: ArgumentList |
| leftParenthesis: ( |
| rightParenthesis: ) |
| staticInvokeType: void Function() |
| staticType: void |
| '''); |
| } |
| |
| test_methodInvocation_superHasNoSuchMethod() async { |
| await assertNoErrorsInCode(r''' |
| class A { |
| int foo(); |
| noSuchMethod(im) => 42; |
| } |
| |
| class B extends A { |
| int foo() => super.foo(); // ref |
| noSuchMethod(im) => 87; |
| } |
| '''); |
| |
| var node = findNode.methodInvocation('super.foo()'); |
| assertResolvedNodeText(node, r''' |
| MethodInvocation |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| methodName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@method::foo |
| staticType: int Function() |
| argumentList: ArgumentList |
| leftParenthesis: ( |
| rightParenthesis: ) |
| staticInvokeType: int Function() |
| staticType: int |
| '''); |
| } |
| |
| test_methodInvocation_superSuperHasConcrete() async { |
| await assertNoErrorsInCode(''' |
| abstract class A { |
| void foo() {} |
| } |
| |
| abstract class B extends A { |
| void foo(); |
| } |
| |
| class C extends B { |
| void bar() { |
| super.foo(); |
| } |
| } |
| '''); |
| |
| var node = findNode.methodInvocation('super.foo()'); |
| assertResolvedNodeText(node, r''' |
| MethodInvocation |
| target: SuperExpression |
| superKeyword: super |
| staticType: C |
| operator: . |
| methodName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@method::foo |
| staticType: void Function() |
| argumentList: ArgumentList |
| leftParenthesis: ( |
| rightParenthesis: ) |
| staticInvokeType: void Function() |
| staticType: void |
| '''); |
| } |
| |
| test_propertyAccess_getter() async { |
| await assertErrorsInCode(r''' |
| abstract class A { |
| int get foo; |
| } |
| |
| abstract class B extends A { |
| bar() { |
| super.foo; // ref |
| } |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 86, 3), |
| ]); |
| |
| var node = findNode.singlePropertyAccess; |
| assertResolvedNodeText(node, r''' |
| PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@getter::foo |
| staticType: int |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_getter_mixin_implements() async { |
| await assertErrorsInCode(r''' |
| class A { |
| int get foo => 0; |
| } |
| |
| mixin M implements A { |
| void bar() { |
| super.foo; |
| } |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 81, 3), |
| ]); |
| |
| var node = findNode.singlePropertyAccess; |
| assertResolvedNodeText(node, r''' |
| PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: M |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@getter::foo |
| staticType: int |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_getter_mixinHasNoSuchMethod() async { |
| await assertErrorsInCode(''' |
| mixin A { |
| int get foo; |
| noSuchMethod(im) => 1; |
| } |
| |
| class B extends Object with A { |
| int get foo => super.foo; // ref |
| noSuchMethod(im) => 2; |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 108, 3), |
| ]); |
| |
| var node = findNode.singlePropertyAccess; |
| assertResolvedNodeText(node, r''' |
| PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@mixin::A::@getter::foo |
| staticType: int |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_getter_superHasNoSuchMethod() async { |
| await assertNoErrorsInCode(r''' |
| class A { |
| int get foo; |
| noSuchMethod(im) => 1; |
| } |
| |
| class B extends A { |
| get foo => super.foo; // ref |
| noSuchMethod(im) => 2; |
| } |
| '''); |
| |
| var node = findNode.singlePropertyAccess; |
| assertResolvedNodeText(node, r''' |
| PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@getter::foo |
| staticType: int |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_getter_superImplements() async { |
| await assertErrorsInCode(r''' |
| class A { |
| int get foo => 0; |
| } |
| |
| abstract class B implements A { |
| } |
| |
| class C extends B { |
| int get foo => super.foo; // ref |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 111, 3), |
| ]); |
| |
| var node = findNode.singlePropertyAccess; |
| assertResolvedNodeText(node, r''' |
| PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: C |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@getter::foo |
| staticType: int |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_getter_superSuperHasConcrete() async { |
| await assertNoErrorsInCode(''' |
| abstract class A { |
| int get foo => 0; |
| } |
| |
| abstract class B extends A { |
| int get foo; |
| } |
| |
| class C extends B { |
| int get bar => super.foo; // ref |
| } |
| '''); |
| |
| var node = findNode.singlePropertyAccess; |
| assertResolvedNodeText(node, r''' |
| PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: C |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@getter::foo |
| staticType: int |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_method_tearOff_abstract() async { |
| await assertErrorsInCode(r''' |
| abstract class A { |
| void foo(); |
| } |
| |
| abstract class B extends A { |
| void bar() { |
| super.foo; // ref |
| } |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 90, 3), |
| ]); |
| |
| var node = findNode.singlePropertyAccess; |
| assertResolvedNodeText(node, r''' |
| PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <testLibraryFragment>::@class::A::@method::foo |
| staticType: void Function() |
| staticType: void Function() |
| '''); |
| } |
| |
| test_propertyAccess_setter() async { |
| await assertErrorsInCode(r''' |
| abstract class A { |
| set foo(int _); |
| } |
| |
| abstract class B extends A { |
| void bar() { |
| super.foo = 0; |
| } |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 94, 3), |
| ]); |
| |
| assertResolvedNodeText(findNode.assignment('foo ='), r''' |
| AssignmentExpression |
| leftHandSide: PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <null> |
| staticType: null |
| staticType: null |
| operator: = |
| rightHandSide: IntegerLiteral |
| literal: 0 |
| parameter: <testLibraryFragment>::@class::A::@setter::foo::@parameter::_ |
| staticType: int |
| readElement: <null> |
| readType: null |
| writeElement: <testLibraryFragment>::@class::A::@setter::foo |
| writeType: int |
| staticElement: <null> |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_setter_mixin_implements() async { |
| await assertErrorsInCode(r''' |
| class A { |
| set foo(int _) {} |
| } |
| |
| mixin M implements A { |
| void bar() { |
| super.foo = 0; |
| } |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 81, 3), |
| ]); |
| |
| assertResolvedNodeText(findNode.assignment('foo ='), r''' |
| AssignmentExpression |
| leftHandSide: PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: M |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <null> |
| staticType: null |
| staticType: null |
| operator: = |
| rightHandSide: IntegerLiteral |
| literal: 0 |
| parameter: <testLibraryFragment>::@class::A::@setter::foo::@parameter::_ |
| staticType: int |
| readElement: <null> |
| readType: null |
| writeElement: <testLibraryFragment>::@class::A::@setter::foo |
| writeType: int |
| staticElement: <null> |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_setter_mixinHasNoSuchMethod() async { |
| await assertErrorsInCode(''' |
| mixin A { |
| set foo(int a); |
| noSuchMethod(im) {} |
| } |
| |
| class B extends Object with A { |
| set foo(int a) => super.foo = a; // ref |
| noSuchMethod(im) {} |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE, 111, 3), |
| ]); |
| |
| assertResolvedNodeText(findNode.assignment('foo ='), r''' |
| AssignmentExpression |
| leftHandSide: PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <null> |
| staticType: null |
| staticType: null |
| operator: = |
| rightHandSide: SimpleIdentifier |
| token: a |
| parameter: <testLibraryFragment>::@mixin::A::@setter::foo::@parameter::a |
| staticElement: <testLibraryFragment>::@class::B::@setter::foo::@parameter::a |
| staticType: int |
| readElement: <null> |
| readType: null |
| writeElement: <testLibraryFragment>::@mixin::A::@setter::foo |
| writeType: int |
| staticElement: <null> |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_setter_superHasNoSuchMethod() async { |
| await assertNoErrorsInCode(r''' |
| class A { |
| set foo(int a); |
| noSuchMethod(im) => 1; |
| } |
| |
| class B extends A { |
| set foo(int a) => super.foo = a; // ref |
| noSuchMethod(im) => 2; |
| } |
| '''); |
| |
| assertResolvedNodeText(findNode.assignment('foo ='), r''' |
| AssignmentExpression |
| leftHandSide: PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: B |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <null> |
| staticType: null |
| staticType: null |
| operator: = |
| rightHandSide: SimpleIdentifier |
| token: a |
| parameter: <testLibraryFragment>::@class::A::@setter::foo::@parameter::a |
| staticElement: <testLibraryFragment>::@class::B::@setter::foo::@parameter::a |
| staticType: int |
| readElement: <null> |
| readType: null |
| writeElement: <testLibraryFragment>::@class::A::@setter::foo |
| writeType: int |
| staticElement: <null> |
| staticType: int |
| '''); |
| } |
| |
| test_propertyAccess_setter_superSuperHasConcrete() async { |
| await assertNoErrorsInCode(''' |
| abstract class A { |
| void set foo(int _) {} |
| } |
| |
| abstract class B extends A { |
| void set foo(int _); |
| } |
| |
| class C extends B { |
| void bar() { |
| super.foo = 0; |
| } |
| } |
| '''); |
| |
| assertResolvedNodeText(findNode.assignment('foo ='), r''' |
| AssignmentExpression |
| leftHandSide: PropertyAccess |
| target: SuperExpression |
| superKeyword: super |
| staticType: C |
| operator: . |
| propertyName: SimpleIdentifier |
| token: foo |
| staticElement: <null> |
| staticType: null |
| staticType: null |
| operator: = |
| rightHandSide: IntegerLiteral |
| literal: 0 |
| parameter: <testLibraryFragment>::@class::A::@setter::foo::@parameter::_ |
| staticType: int |
| readElement: <null> |
| readType: null |
| writeElement: <testLibraryFragment>::@class::A::@setter::foo |
| writeType: int |
| staticElement: <null> |
| staticType: int |
| '''); |
| } |
| } |