| // 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:analysis_server/src/services/correction/fix/data_driven/add_type_parameter.dart'; |
| import 'package:analysis_server/src/services/correction/fix/data_driven/changes_selector.dart'; |
| import 'package:analysis_server/src/services/correction/fix/data_driven/element_descriptor.dart'; |
| import 'package:analysis_server/src/services/correction/fix/data_driven/element_kind.dart'; |
| import 'package:analysis_server/src/services/correction/fix/data_driven/transform.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'data_driven_test_support.dart'; |
| |
| void main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(AddTypeParameterToClassTest); |
| defineReflectiveTests(AddTypeParameterToExtensionTest); |
| defineReflectiveTests(AddTypeParameterToMethodTest); |
| defineReflectiveTests(AddTypeParameterToMixinTest); |
| defineReflectiveTests(AddTypeParameterToTopLevelFunctionTest); |
| defineReflectiveTests(AddTypeParameterToTypedefTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class AddTypeParameterToClassTest extends _AddTypeParameterChange { |
| @override |
| String get _kind => 'class'; |
| |
| Future<void> test_constructorInvocation_removed() async { |
| setPackageContent(''' |
| class C<S, T> { |
| void C() {} |
| } |
| '''); |
| setPackageData(_add(0, components: ['C'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| C f() { |
| return C<int>(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| C f() { |
| return C<String, int>(); |
| } |
| '''); |
| } |
| |
| Future<void> test_inExtends_removed() async { |
| setPackageContent(''' |
| class A<S, T> {} |
| '''); |
| setPackageData(_add(0, components: ['A'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| class B extends A<int> {} |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| class B extends A<String, int> {} |
| '''); |
| } |
| |
| Future<void> test_inImplements_removed() async { |
| setPackageContent(''' |
| class A<S, T> {} |
| '''); |
| setPackageData(_add(0, components: ['A'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| class B implements A<int> {} |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| class B implements A<String, int> {} |
| '''); |
| } |
| |
| Future<void> test_inOn_removed() async { |
| setPackageContent(''' |
| class A<S, T> {} |
| '''); |
| setPackageData(_add(0, components: ['A'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| extension E on A<int> {} |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| extension E on A<String, int> {} |
| '''); |
| } |
| |
| Future<void> test_inTypeAnnotation_removed() async { |
| setPackageContent(''' |
| class C<S, T> {} |
| '''); |
| setPackageData(_add(0, components: ['C'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void f(C<int> c) {} |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void f(C<String, int> c) {} |
| '''); |
| } |
| |
| Future<void> test_inWith_removed() async { |
| setPackageContent(''' |
| mixin A<S, T> {} |
| '''); |
| setPackageData(_add(0, components: ['A'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| class B with A<int> {} |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| class B with A<String, int> {} |
| '''); |
| } |
| } |
| |
| @reflectiveTest |
| class AddTypeParameterToExtensionTest extends _AddTypeParameterChange { |
| @override |
| String get _kind => 'extension'; |
| |
| Future<void> test_override_removed() async { |
| setPackageContent(''' |
| class C {} |
| extension E<S, T> on C { |
| void m() {} |
| } |
| '''); |
| setPackageData(_add(0, components: ['E'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| E<int>(c).m(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| E<String, int>(c).m(); |
| } |
| '''); |
| } |
| } |
| |
| @reflectiveTest |
| class AddTypeParameterToMethodTest extends _AddTypeParameterChange { |
| @override |
| String get _kind => 'method'; |
| |
| Future<void> test_first_deprecated() async { |
| setPackageContent(''' |
| class C { |
| @deprecated |
| void m<T>() {} |
| } |
| '''); |
| setPackageData(_add(0)); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m<int>(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m<String, int>(); |
| } |
| '''); |
| } |
| |
| Future<void> test_first_removed() async { |
| setPackageContent(''' |
| class C { |
| void m<S, T>() {} |
| } |
| '''); |
| setPackageData(_add(0)); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m<int>(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m<String, int>(); |
| } |
| '''); |
| } |
| |
| Future<void> test_last_deprecated() async { |
| setPackageContent(''' |
| class C { |
| @deprecated |
| void m<S, T>() {} |
| } |
| '''); |
| setPackageData(_add(2)); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m<int, double>(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m<int, double, String>(); |
| } |
| '''); |
| } |
| |
| Future<void> test_middle_deprecated() async { |
| setPackageContent(''' |
| class C { |
| @deprecated |
| void m<S, U>() {} |
| } |
| '''); |
| setPackageData(_add(1)); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m<int, double>(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m<int, String, double>(); |
| } |
| '''); |
| } |
| |
| Future<void> test_only_deprecated() async { |
| setPackageContent(''' |
| class C { |
| @deprecated |
| void m() {} |
| } |
| '''); |
| setPackageData(_add(0)); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void f(C c) { |
| c.m<String>(); |
| } |
| '''); |
| } |
| |
| Future<void> test_override_withBound_removed() async { |
| setPackageContent(''' |
| class C { |
| void m<T extends num>() {} |
| } |
| '''); |
| setPackageData(_add(0, extendedType: 'num')); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| class D extends C { |
| @override |
| void m() {} |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| class D extends C { |
| @override |
| void m<T extends num>() {} |
| } |
| '''); |
| } |
| |
| Future<void> test_override_withoutBound_removed() async { |
| setPackageContent(''' |
| class C { |
| void m<T>() {} |
| } |
| '''); |
| setPackageData(_add(0)); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| class D extends C { |
| @override |
| void m() {} |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| class D extends C { |
| @override |
| void m<T>() {} |
| } |
| '''); |
| } |
| } |
| |
| @reflectiveTest |
| class AddTypeParameterToMixinTest extends _AddTypeParameterChange { |
| @override |
| String get _kind => 'mixin'; |
| |
| Future<void> test_inWith_removed() async { |
| setPackageContent(''' |
| mixin M<S, T> {} |
| '''); |
| setPackageData(_add(0, components: ['M'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| class B with M<int> {} |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| class B with M<String, int> {} |
| '''); |
| } |
| } |
| |
| @reflectiveTest |
| class AddTypeParameterToTopLevelFunctionTest extends _AddTypeParameterChange { |
| @override |
| String get _kind => 'function'; |
| |
| Future<void> test_only_deprecated() async { |
| setPackageContent(''' |
| @deprecated |
| void f() {} |
| '''); |
| setPackageData(_add(0, components: ['f'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void g() { |
| f(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void g() { |
| f<String>(); |
| } |
| '''); |
| } |
| } |
| |
| @reflectiveTest |
| class AddTypeParameterToTypedefTest extends _AddTypeParameterChange { |
| @override |
| String get _kind => 'typedef'; |
| |
| @failingTest |
| Future<void> test_functionType_removed() async { |
| // The test fails because the change is to the typedef `F`, not to the |
| // parameter `f`, so we don't see that the change might apply. |
| // |
| // Note, however, that there isn't currently any way to specify that the |
| // type parameter belongs to the function type being declared rather than to |
| // the typedef, so even if we fixed the problem above we would apply the |
| // change in the wrong places. |
| setPackageContent(''' |
| typedef F = T Function<S, T>(); |
| '''); |
| setPackageData(_add(0, components: ['F'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void g(F f) { |
| f<int>(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void g(F f) { |
| f<String, int>(); |
| } |
| '''); |
| } |
| |
| Future<void> test_typedef_first_removed() async { |
| setPackageContent(''' |
| typedef F<S, T> = T Function(); |
| '''); |
| setPackageData(_add(0, components: ['F'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void g(F<int> f) { |
| f(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void g(F<String, int> f) { |
| f(); |
| } |
| '''); |
| } |
| |
| @failingTest |
| Future<void> test_typedef_only_removed() async { |
| // The test fails because there is no diagnostic generated when there were |
| // no type arguments before the change; the type arguments are silently |
| // inferred to be `dynamic`. |
| setPackageContent(''' |
| typedef F<T> = T Function(); |
| '''); |
| setPackageData(_add(0, components: ['F'])); |
| await resolveTestCode(''' |
| import '$importUri'; |
| |
| void g(F f) { |
| f(); |
| } |
| '''); |
| await assertHasFix(''' |
| import '$importUri'; |
| |
| void g(F<String> f) { |
| f(); |
| } |
| '''); |
| } |
| } |
| |
| abstract class _AddTypeParameterChange extends DataDrivenFixProcessorTest { |
| /// Return the kind of element whose parameters are being modified. |
| String get _kind; |
| |
| Transform _add(int index, |
| {List<String>? components, |
| String? extendedType, |
| bool isStatic = false}) => |
| Transform( |
| title: 'title', |
| date: DateTime.now(), |
| element: ElementDescriptor( |
| libraryUris: [Uri.parse(importUri)], |
| kind: ElementKindUtilities.fromName(_kind)!, |
| isStatic: isStatic, |
| components: components ?? ['m', 'C']), |
| bulkApply: false, |
| changesSelector: UnconditionalChangesSelector([ |
| AddTypeParameter( |
| index: index, |
| name: 'T', |
| extendedType: |
| extendedType == null ? null : codeTemplate(extendedType), |
| argumentValue: codeTemplate('String')), |
| ])); |
| } |