Enhance CreateConstructorForFinalFields to suggest also required named formal parameters.

Change-Id: I64db6eb4ced756e7b261abaa0c8b058c98fdd5d1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/308522
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2023-06-11 15:25:40 +00:00 committed by Commit Queue
parent 70da08865b
commit fa5d596d6d
4 changed files with 147 additions and 11 deletions

View file

@ -15,8 +15,16 @@ import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:collection/collection.dart';
class CreateConstructorForFinalFields extends CorrectionProducer {
final _Style _style;
CreateConstructorForFinalFields.requiredNamed()
: _style = _Style.requiredNamed;
CreateConstructorForFinalFields.requiredPositional()
: _style = _Style.requiredPositional;
@override
FixKind get fixKind => DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS;
FixKind get fixKind => _style.fixKind;
FieldDeclaration? get _errorFieldDeclaration {
if (node is VariableDeclaration) {
@ -219,13 +227,26 @@ class CreateConstructorForFinalFields extends CorrectionProducer {
}
builder.write(fixContext.containerName);
builder.write('(');
fields.forEachIndexed((index, field) {
if (index > 0) {
builder.write(', ');
}
builder.write('this.');
builder.write(field.name);
});
switch (_style) {
case _Style.requiredNamed:
builder.write('{');
fields.forEachIndexed((index, field) {
if (index > 0) {
builder.write(', ');
}
builder.write('required this.');
builder.write(field.name);
});
builder.write('}');
case _Style.requiredPositional:
fields.forEachIndexed((index, field) {
if (index > 0) {
builder.write(', ');
}
builder.write('this.');
builder.write(field.name);
});
}
builder.write(');');
builder.write(location.suffix);
});
@ -290,3 +311,18 @@ class _FixContext {
required this.variableLists,
});
}
enum _Style {
requiredNamed(
fixKind: DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS_REQUIRED_NAMED,
),
requiredPositional(
fixKind: DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS,
);
final FixKind fixKind;
const _Style({
required this.fixKind,
});
}

View file

@ -694,6 +694,11 @@ class DartFixKind {
DartFixKindPriority.DEFAULT,
'Create constructor for final fields',
);
static const CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS_REQUIRED_NAMED = FixKind(
'dart.fix.create.constructorForFinalFields.requiredNamed',
DartFixKindPriority.DEFAULT,
'Create constructor for final fields, required named',
);
static const CREATE_CONSTRUCTOR_SUPER = FixKind(
'dart.fix.create.constructorSuper',
DartFixKindPriority.DEFAULT,

View file

@ -1081,7 +1081,8 @@ class FixProcessor extends BaseProcessor {
],
CompileTimeErrorCode.FINAL_NOT_INITIALIZED: [
AddLate.new,
CreateConstructorForFinalFields.new,
CreateConstructorForFinalFields.requiredNamed,
CreateConstructorForFinalFields.requiredPositional,
],
CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1: [
AddFieldFormalParameters.new,

View file

@ -11,7 +11,9 @@ import 'fix_processor.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(CreateConstructorForFinalFieldsTest);
defineReflectiveTests(
CreateConstructorForFinalFieldsRequiredPositionalTest);
defineReflectiveTests(CreateConstructorForFinalFieldsRequiredNamedTest);
defineReflectiveTests(CreateConstructorForFinalFieldsWithoutNullSafetyTest);
defineReflectiveTests(
CreateConstructorForFinalFieldsWithoutSuperParametersTest);
@ -19,7 +21,99 @@ void main() {
}
@reflectiveTest
class CreateConstructorForFinalFieldsTest extends FixProcessorTest {
class CreateConstructorForFinalFieldsRequiredNamedTest
extends FixProcessorTest {
@override
FixKind get kind =>
DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS_REQUIRED_NAMED;
Future<void> test_class_excludesLate() async {
await resolveTestCode('''
class Test {
final int a;
late final int b;
}
''');
await assertHasFix('''
class Test {
final int a;
late final int b;
Test({required this.a});
}
''');
}
Future<void> test_class_lint_sortConstructorsFirst() async {
createAnalysisOptionsFile(lints: [LintNames.sort_constructors_first]);
await resolveTestCode('''
class Test {
final int a;
final int b = 2;
final int c;
}
''');
await assertHasFix('''
class Test {
Test({required this.a, required this.c});
final int a;
final int b = 2;
final int c;
}
''', errorFilter: (error) {
return error.message.contains("'a'");
});
}
Future<void> test_class_simple() async {
await resolveTestCode('''
class Test {
final int a;
final int b = 2;
final int c;
}
''');
await assertHasFix('''
class Test {
final int a;
final int b = 2;
final int c;
Test({required this.a, required this.c});
}
''', errorFilter: (error) {
return error.message.contains("'a'");
});
}
Future<void> test_enum_simple() async {
await resolveTestCode('''
enum E {
v(a: 0, c: 2);
final int a;
final int b = 1;
final int c;
}
''');
await assertHasFix('''
enum E {
v(a: 0, c: 2);
final int a;
final int b = 1;
final int c;
const E({required this.a, required this.c});
}
''', errorFilter: (error) {
return error.offset == 38;
});
}
}
@reflectiveTest
class CreateConstructorForFinalFieldsRequiredPositionalTest
extends FixProcessorTest {
@override
FixKind get kind => DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS;