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>
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/create_constructor_for_final_fields.dart b/pkg/analysis_server/lib/src/services/correction/dart/create_constructor_for_final_fields.dart
index 865b790..406e801 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/create_constructor_for_final_fields.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/create_constructor_for_final_fields.dart
@@ -15,8 +15,16 @@
 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 @@
         }
         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 @@
     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,
+  });
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 4b28c47..8598cb4 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -694,6 +694,11 @@
     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,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 02f6931..4bd39f9 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1081,7 +1081,8 @@
     ],
     CompileTimeErrorCode.FINAL_NOT_INITIALIZED: [
       AddLate.new,
-      CreateConstructorForFinalFields.new,
+      CreateConstructorForFinalFields.requiredNamed,
+      CreateConstructorForFinalFields.requiredPositional,
     ],
     CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1: [
       AddFieldFormalParameters.new,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_constructor_for_final_fields_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_constructor_for_final_fields_test.dart
index 463e778..b83fd01 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_constructor_for_final_fields_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_constructor_for_final_fields_test.dart
@@ -11,7 +11,9 @@
 
 void main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(CreateConstructorForFinalFieldsTest);
+    defineReflectiveTests(
+        CreateConstructorForFinalFieldsRequiredPositionalTest);
+    defineReflectiveTests(CreateConstructorForFinalFieldsRequiredNamedTest);
     defineReflectiveTests(CreateConstructorForFinalFieldsWithoutNullSafetyTest);
     defineReflectiveTests(
         CreateConstructorForFinalFieldsWithoutSuperParametersTest);
@@ -19,7 +21,99 @@
 }
 
 @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;