Include named super formal parameters into CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS_REQUIRED_NAMED.

This is convenient feature when building hierarchies of data classes.

Change-Id: Id4c7040e0515150661165079ad01d9d05e0c1185
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/308541
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 406e801..1e6c3a8 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
@@ -8,7 +8,9 @@
 import 'package:analysis_server/src/utilities/extensions/object.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@@ -84,6 +86,7 @@
     final fixContext = _FixContext(
       builder: builder,
       containerName: className,
+      superType: superType,
       location: targetLocation,
       variableLists: variableLists,
     );
@@ -115,6 +118,7 @@
       fixContext: _FixContext(
         builder: builder,
         containerName: enumName,
+        superType: null,
         location: targetLocation,
         variableLists: variableLists,
       ),
@@ -230,22 +234,40 @@
         switch (_style) {
           case _Style.requiredNamed:
             builder.write('{');
-            fields.forEachIndexed((index, field) {
-              if (index > 0) {
+            var hasWritten = false;
+            final superNamed = fixContext.superNamed;
+            if (superNamed != null) {
+              for (final formalParameter in superNamed) {
+                if (hasWritten) {
+                  builder.write(', ');
+                }
+                if (formalParameter.isRequiredNamed) {
+                  builder.write('required ');
+                }
+                builder.write('super.');
+                builder.write(formalParameter.name);
+                hasWritten = true;
+              }
+            }
+            for (final field in fields) {
+              if (hasWritten) {
                 builder.write(', ');
               }
               builder.write('required this.');
               builder.write(field.name);
-            });
+              hasWritten = true;
+            }
             builder.write('}');
           case _Style.requiredPositional:
-            fields.forEachIndexed((index, field) {
-              if (index > 0) {
+            var hasWritten = false;
+            for (final field in fields) {
+              if (hasWritten) {
                 builder.write(', ');
               }
               builder.write('this.');
               builder.write(field.name);
-            });
+              hasWritten = true;
+            }
         }
         builder.write(');');
         builder.write(location.suffix);
@@ -301,15 +323,27 @@
 class _FixContext {
   final ChangeBuilder builder;
   final String containerName;
+  final InterfaceType? superType;
   final InsertionLocation location;
   final List<VariableDeclarationList> variableLists;
 
   _FixContext({
     required this.builder,
     required this.containerName,
+    required this.superType,
     required this.location,
     required this.variableLists,
   });
+
+  List<ParameterElement>? get superNamed {
+    final superConstructor = superType?.constructors.singleOrNull;
+    if (superConstructor != null) {
+      final superAll = superConstructor.parameters;
+      final superNamed = superAll.where((e) => e.isNamed).toList();
+      return superNamed.length == superAll.length ? superNamed : null;
+    }
+    return null;
+  }
 }
 
 enum _Style {
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 b83fd01..d01b995 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
@@ -44,6 +44,72 @@
 ''');
   }
 
+  Future<void> test_class_hasSuperClass_withOptionalNamed() async {
+    await resolveTestCode('''
+class A {
+  final int? f11;
+  final int? f12;
+
+  A({this.f11, this.f12})
+}
+
+class B extends A {
+  final int f21;
+  final int f22;
+}
+''');
+    await assertHasFix('''
+class A {
+  final int? f11;
+  final int? f12;
+
+  A({this.f11, this.f12})
+}
+
+class B extends A {
+  final int f21;
+  final int f22;
+
+  B({super.f11, super.f12, required this.f21, required this.f22});
+}
+''', errorFilter: (error) {
+      return error.message.contains("'f21'");
+    });
+  }
+
+  Future<void> test_class_hasSuperClass_withRequiredNamed() async {
+    await resolveTestCode('''
+class A {
+  final int f11;
+  final int f12;
+
+  A({required this.f11, required this.f12})
+}
+
+class B extends A {
+  final int f21;
+  final int f22;
+}
+''');
+    await assertHasFix('''
+class A {
+  final int f11;
+  final int f12;
+
+  A({required this.f11, required this.f12})
+}
+
+class B extends A {
+  final int f21;
+  final int f22;
+
+  B({required super.f11, required super.f12, required this.f21, required this.f22});
+}
+''', errorFilter: (error) {
+      return error.message.contains("'f21'");
+    });
+  }
+
   Future<void> test_class_lint_sortConstructorsFirst() async {
     createAnalysisOptionsFile(lints: [LintNames.sort_constructors_first]);
     await resolveTestCode('''