| // 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/src/dart/error/syntactic_errors.dart'; |
| import 'package:analyzer/src/error/codes.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'context_collection_resolution.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(InstanceCreationTest); |
| defineReflectiveTests(InstanceCreationWithoutConstructorTearoffsTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class InstanceCreationTest extends PubPackageResolutionTest |
| with InstanceCreationTestCases {} |
| |
| mixin InstanceCreationTestCases on PubPackageResolutionTest { |
| test_class_generic_named_inferTypeArguments() async { |
| await assertNoErrorsInCode(r''' |
| class A<T> { |
| A.named(T t); |
| } |
| |
| void f() { |
| A.named(0); |
| } |
| |
| '''); |
| |
| var creation = findNode.instanceCreation('A.named(0)'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<int>', |
| constructorName: 'named', |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'int'}, |
| ); |
| } |
| |
| test_class_generic_named_withTypeArguments() async { |
| await assertNoErrorsInCode(r''' |
| class A<T> { |
| A.named(); |
| } |
| |
| void f() { |
| A<int>.named(); |
| } |
| |
| '''); |
| |
| var creation = findNode.instanceCreation('A<int>'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<int>', |
| constructorName: 'named', |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'int'}, |
| ); |
| assertNamedType(findNode.namedType('int>'), intElement, 'int'); |
| } |
| |
| test_class_generic_unnamed_inferTypeArguments() async { |
| await assertNoErrorsInCode(r''' |
| class A<T> { |
| A(T t); |
| } |
| |
| void f() { |
| A(0); |
| } |
| |
| '''); |
| |
| var creation = findNode.instanceCreation('A(0)'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<int>', |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'int'}, |
| ); |
| } |
| |
| test_class_generic_unnamed_withTypeArguments() async { |
| await assertNoErrorsInCode(r''' |
| class A<T> {} |
| |
| void f() { |
| A<int>(); |
| } |
| |
| '''); |
| |
| var creation = findNode.instanceCreation('A<int>'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<int>', |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'int'}, |
| ); |
| assertNamedType(findNode.namedType('int>'), intElement, 'int'); |
| } |
| |
| test_class_notGeneric() async { |
| await assertNoErrorsInCode(r''' |
| class A { |
| A(int a); |
| } |
| |
| void f() { |
| A(0); |
| } |
| |
| '''); |
| |
| var creation = findNode.instanceCreation('A(0)'); |
| assertInstanceCreation(creation, findElement.class_('A'), 'A'); |
| } |
| |
| test_demoteType() async { |
| await assertNoErrorsInCode(r''' |
| class A<T> { |
| A(T t); |
| } |
| |
| void f<S>(S s) { |
| if (s is int) { |
| A(s); |
| } |
| } |
| |
| '''); |
| |
| assertType( |
| findNode.instanceCreation('A(s)'), |
| 'A<S>', |
| ); |
| } |
| |
| test_error_newWithInvalidTypeParameters_implicitNew_inference_top() async { |
| await assertErrorsInCode(r''' |
| final foo = Map<int>(); |
| ''', [ |
| error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 12, 8), |
| ]); |
| |
| var creation = findNode.instanceCreation('Map<int>'); |
| assertInstanceCreation( |
| creation, |
| mapElement, |
| 'Map<dynamic, dynamic>', |
| expectedConstructorMember: true, |
| expectedSubstitution: {'K': 'dynamic', 'V': 'dynamic'}, |
| ); |
| } |
| |
| test_error_wrongNumberOfTypeArgumentsConstructor_explicitNew() async { |
| await assertErrorsInCode(r''' |
| class Foo<X> { |
| Foo.bar(); |
| } |
| |
| main() { |
| new Foo.bar<int>(); |
| } |
| ''', [ |
| error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 53, |
| 5, |
| messageContains: ["The constructor 'Foo.bar'"]), |
| ]); |
| |
| var creation = findNode.instanceCreation('Foo.bar<int>'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('Foo'), |
| 'Foo<dynamic>', |
| constructorName: 'bar', |
| expectedConstructorMember: true, |
| expectedSubstitution: {'X': 'dynamic'}, |
| ); |
| } |
| |
| test_error_wrongNumberOfTypeArgumentsConstructor_explicitNew_new() async { |
| await assertErrorsInCode(r''' |
| class Foo<X> { |
| Foo.new(); |
| } |
| |
| main() { |
| new Foo.new<int>(); |
| } |
| ''', [ |
| error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 53, |
| 5, |
| messageContains: ["The constructor 'Foo.new'"]), |
| ]); |
| |
| var creation = findNode.instanceCreation('Foo.new<int>'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('Foo'), |
| 'Foo<dynamic>', |
| expectedConstructorMember: true, |
| expectedSubstitution: {'X': 'dynamic'}, |
| ); |
| } |
| |
| test_error_wrongNumberOfTypeArgumentsConstructor_explicitNew_prefix() async { |
| newFile('$testPackageLibPath/a.dart', content: ''' |
| class Foo<X> { |
| Foo.bar(); |
| } |
| '''); |
| await assertErrorsInCode(''' |
| import 'a.dart' as p; |
| |
| main() { |
| new p.Foo.bar<int>(); |
| } |
| ''', [ |
| error(ParserErrorCode.CONSTRUCTOR_WITH_TYPE_ARGUMENTS, 44, 3), |
| ]); |
| |
| // TODO(brianwilkerson) Test this more carefully after we can re-write the |
| // AST to reflect the expected structure. |
| // var creation = findNode.instanceCreation('Foo.bar<int>'); |
| // var import = findElement.import('package:test/a.dart'); |
| // assertInstanceCreation( |
| // creation, |
| // import.importedLibrary.getType('Foo'), |
| // 'Foo', |
| // constructorName: 'bar', |
| // expectedPrefix: import.prefix, |
| // ); |
| } |
| |
| test_error_wrongNumberOfTypeArgumentsConstructor_implicitNew() async { |
| await assertErrorsInCode(r''' |
| class Foo<X> { |
| Foo.bar(); |
| } |
| |
| main() { |
| Foo.bar<int>(); |
| } |
| ''', [ |
| error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 49, |
| 5), |
| ]); |
| |
| var creation = findNode.instanceCreation('Foo.bar<int>'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('Foo'), |
| // TODO(scheglov) Move type arguments |
| 'Foo<dynamic>', |
| // 'Foo<int>', |
| constructorName: 'bar', |
| expectedConstructorMember: true, |
| // TODO(scheglov) Move type arguments |
| expectedSubstitution: {'X': 'dynamic'}, |
| // expectedSubstitution: {'X': 'int'}, |
| ); |
| } |
| |
| test_error_wrongNumberOfTypeArgumentsConstructor_implicitNew_prefix() async { |
| newFile('$testPackageLibPath/a.dart', content: ''' |
| class Foo<X> { |
| Foo.bar(); |
| } |
| '''); |
| await assertErrorsInCode(''' |
| import 'a.dart' as p; |
| |
| main() { |
| p.Foo.bar<int>(); |
| } |
| ''', [ |
| error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, 43, |
| 5), |
| ]); |
| |
| var import = findElement.import('package:test/a.dart'); |
| |
| var creation = findNode.instanceCreation('Foo.bar<int>'); |
| assertInstanceCreation( |
| creation, |
| import.importedLibrary!.getType('Foo')!, |
| 'Foo<int>', |
| constructorName: 'bar', |
| expectedConstructorMember: true, |
| expectedPrefix: import.prefix, |
| expectedSubstitution: {'X': 'int'}, |
| ); |
| } |
| |
| test_namedArgument_anywhere() async { |
| await assertNoErrorsInCode(''' |
| class A { |
| A(int a, double b, {bool? c, bool? d}); |
| } |
| |
| void f() { |
| A(0, c: true, 1.2, d: true); |
| } |
| '''); |
| |
| assertInstanceCreation( |
| findNode.instanceCreation('A(0'), |
| findElement.class_('A'), |
| 'A', |
| ); |
| |
| assertParameterElement( |
| findNode.integerLiteral('0'), |
| findElement.parameter('a'), |
| ); |
| |
| assertParameterElement( |
| findNode.doubleLiteral('1.2'), |
| findElement.parameter('b'), |
| ); |
| |
| assertParameterElement( |
| findNode.namedExpression('c: true'), |
| findElement.parameter('c'), |
| ); |
| assertNamedParameterRef('c: true', 'c'); |
| |
| assertParameterElement( |
| findNode.namedExpression('d: true'), |
| findElement.parameter('d'), |
| ); |
| assertNamedParameterRef('d: true', 'd'); |
| } |
| |
| test_typeAlias_generic_class_generic_named_infer_all() async { |
| await assertNoErrorsInCode(r''' |
| class A<T> { |
| A.named(T t); |
| } |
| |
| typedef B<U> = A<U>; |
| |
| void f() { |
| B.named(0); |
| } |
| '''); |
| |
| var creation = findNode.instanceCreation('B.named(0)'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<int>', |
| constructorName: 'named', |
| expectedTypeNameElement: findElement.typeAlias('B'), |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'int'}, |
| ); |
| } |
| |
| test_typeAlias_generic_class_generic_named_infer_partial() async { |
| await assertNoErrorsInCode(r''' |
| class A<T, U> { |
| A.named(T t, U u); |
| } |
| |
| typedef B<V> = A<V, String>; |
| |
| void f() { |
| B.named(0, ''); |
| } |
| '''); |
| |
| var creation = findNode.instanceCreation('B.named(0, '); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<int, String>', |
| constructorName: 'named', |
| expectedTypeNameElement: findElement.typeAlias('B'), |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'int', 'U': 'String'}, |
| ); |
| } |
| |
| test_typeAlias_generic_class_generic_unnamed_infer_all() async { |
| await assertNoErrorsInCode(r''' |
| class A<T> { |
| A(T t); |
| } |
| |
| typedef B<U> = A<U>; |
| |
| void f() { |
| B(0); |
| } |
| '''); |
| |
| var creation = findNode.instanceCreation('B(0)'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<int>', |
| expectedTypeNameElement: findElement.typeAlias('B'), |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'int'}, |
| ); |
| } |
| |
| test_typeAlias_generic_class_generic_unnamed_infer_partial() async { |
| await assertNoErrorsInCode(r''' |
| class A<T, U> { |
| A(T t, U u); |
| } |
| |
| typedef B<V> = A<V, String>; |
| |
| void f() { |
| B(0, ''); |
| } |
| '''); |
| |
| var creation = findNode.instanceCreation('B(0, '); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<int, String>', |
| expectedTypeNameElement: findElement.typeAlias('B'), |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'int', 'U': 'String'}, |
| ); |
| } |
| |
| test_typeAlias_notGeneric_class_generic_named_argumentTypeMismatch() async { |
| await assertErrorsInCode(r''' |
| class A<T> { |
| A.named(T t); |
| } |
| |
| typedef B = A<String>; |
| |
| void f() { |
| B.named(0); |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 77, 1), |
| ]); |
| |
| var creation = findNode.instanceCreation('B.named(0)'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<String>', |
| constructorName: 'named', |
| expectedTypeNameElement: findElement.typeAlias('B'), |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'String'}, |
| ); |
| } |
| |
| test_typeAlias_notGeneric_class_generic_unnamed_argumentTypeMismatch() async { |
| await assertErrorsInCode(r''' |
| class A<T> { |
| A(T t); |
| } |
| |
| typedef B = A<String>; |
| |
| void f() { |
| B(0); |
| } |
| ''', [ |
| error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 65, 1), |
| ]); |
| |
| var creation = findNode.instanceCreation('B(0)'); |
| assertInstanceCreation( |
| creation, |
| findElement.class_('A'), |
| 'A<String>', |
| expectedTypeNameElement: findElement.typeAlias('B'), |
| expectedConstructorMember: true, |
| expectedSubstitution: {'T': 'String'}, |
| ); |
| } |
| |
| test_unnamed_declaredNew() async { |
| await assertNoErrorsInCode(''' |
| class A { |
| A.new(int a); |
| } |
| |
| void f() { |
| A(0); |
| } |
| |
| '''); |
| |
| var creation = findNode.instanceCreation('A(0)'); |
| assertInstanceCreation(creation, findElement.class_('A'), 'A'); |
| } |
| |
| test_unnamedViaNew_declaredNew() async { |
| await assertNoErrorsInCode(''' |
| class A { |
| A.new(int a); |
| } |
| |
| void f() { |
| A.new(0); |
| } |
| |
| '''); |
| |
| var creation = findNode.instanceCreation('A.new(0)'); |
| assertInstanceCreation(creation, findElement.class_('A'), 'A'); |
| } |
| |
| test_unnamedViaNew_declaredUnnamed() async { |
| await assertNoErrorsInCode(''' |
| class A { |
| A(int a); |
| } |
| |
| void f() { |
| A.new(0); |
| } |
| |
| '''); |
| |
| var creation = findNode.instanceCreation('A.new(0)'); |
| assertInstanceCreation(creation, findElement.class_('A'), 'A'); |
| } |
| } |
| |
| @reflectiveTest |
| class InstanceCreationWithoutConstructorTearoffsTest |
| extends PubPackageResolutionTest with WithoutConstructorTearoffsMixin { |
| test_unnamedViaNew() async { |
| await assertErrorsInCode(''' |
| class A { |
| A(int a); |
| } |
| |
| void f() { |
| A.new(0); |
| } |
| |
| ''', [ |
| error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 40, 3), |
| ]); |
| |
| // Resolution should continue even though the experiment is not enabled. |
| var creation = findNode.instanceCreation('A.new(0)'); |
| assertInstanceCreation(creation, findElement.class_('A'), 'A'); |
| } |
| } |