Improve the placement of added named parameters

Change-Id: I8ed588c14402a3d85d134dc75c324d9e3d96f532
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/181820
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
index 32d0b8e..3c49589 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
@@ -60,7 +60,7 @@
     var arguments = argumentList.arguments;
     var argumentCount = arguments.length;
     var templateContext = TemplateContext(argumentList.parent, fix.utils);
-    var newNamed = <AddParameter>[];
+
     var indexToNewArgumentMap = <int, AddParameter>{};
     var argumentsToInsert = <int>[];
     var argumentsToDelete = <int>[];
@@ -69,16 +69,14 @@
       if (modification is AddParameter) {
         var index = modification.index;
         indexToNewArgumentMap[index] = modification;
-        if (modification.isPositional) {
+        if (modification.isPositional || modification.isRequired) {
           argumentsToInsert.add(index);
-        } else if (modification.isRequired) {
-          newNamed.add(modification);
         } else {
           var requiredIfCondition =
               modification.argumentValue?.requiredIfCondition;
           if (requiredIfCondition != null &&
               requiredIfCondition.evaluateIn(templateContext)) {
-            newNamed.add(modification);
+            argumentsToInsert.add(index);
           }
         }
       } else if (modification is RemoveParameter) {
@@ -94,7 +92,6 @@
       }
     }
     argumentsToInsert.sort();
-    newNamed.sort((first, second) => first.name.compareTo(second.name));
 
     /// Write to the [builder] the argument associated with a single
     /// [parameter].
@@ -185,39 +182,21 @@
         var insertionRange = insertionRanges[nextInsertionRange];
         var lower = insertionRange.lower;
         var upper = insertionRange.upper;
-        while (upper >= lower && !indexToNewArgumentMap[upper].isRequired) {
+        var parameter = indexToNewArgumentMap[upper];
+        while (upper >= lower &&
+            (parameter.isPositional && !parameter.isRequired)) {
           upper--;
         }
         if (upper >= lower) {
           builder.addInsertion(offset, (builder) {
-            writeInsertionRange(builder, _IndexRange(lower, upper), true);
+            writeInsertionRange(builder, _IndexRange(lower, upper),
+                nextRemaining > 0 || insertionCount > 0);
           });
         }
         nextInsertionRange++;
       }
     }
     //
-    // Insert arguments for required named parameters.
-    //
-    if (newNamed.isNotEmpty) {
-      int offset;
-      var needsInitialComma = false;
-      if (remainingArguments.isEmpty && argumentsToInsert.isEmpty) {
-        offset = argumentList.rightParenthesis.offset;
-      } else {
-        offset = arguments[arguments.length - 1].end;
-        needsInitialComma = true;
-      }
-      builder.addInsertion(offset, (builder) {
-        for (var i = 0; i < newNamed.length; i++) {
-          if (i > 0 || needsInitialComma) {
-            builder.write(', ');
-          }
-          writeArgument(builder, newNamed[i]);
-        }
-      });
-    }
-    //
     // The remaining deletion ranges are now ready to be removed.
     //
     for (var subRange in deletionRanges) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
index f6359cd..ee6c688 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
@@ -2526,6 +2526,152 @@
 ''');
   }
 
+  Future<void> test_widgets_Stack_overflow_clip() async {
+    setPackageContent('''
+class Stack {
+  const Stack({
+    @deprecated Overflow overflow: Overflow.clip,
+    Clip clipBehavior: Clip.hardEdge,
+    List<Widget> children: const <Widget>[]});
+}
+class Overflow {
+  static const Overflow clip = Overflow();
+  static const Overflow visible = Overflow();
+  const Overflow();
+}
+class Clip {
+  static const Clip hardEdge = Clip();
+  static const Clip none = Clip();
+  const Clip();
+}
+class Widget {}
+''');
+    addPackageDataFile('''
+version: 1
+transforms:
+  - title: "Migrate to 'clipBehavior'"
+    date: 2020-09-22
+    element:
+      uris: ['$importUri']
+      constructor: ''
+      inClass: 'Stack'
+    oneOf:
+      - if: "overflow == 'Overflow.clip'"
+        changes:
+          - kind: 'addParameter'
+            index: 0
+            name: 'clipBehavior'
+            style: optional_named
+            argumentValue:
+              expression: 'Clip.hardEdge'
+              requiredIf: "overflow == 'Overflow.clip'"
+          - kind: 'removeParameter'
+            name: 'overflow'
+      - if: "overflow == 'Overflow.visible'"
+        changes:
+          - kind: 'addParameter'
+            index: 0
+            name: 'clipBehavior'
+            style: optional_named
+            argumentValue:
+              expression: 'Clip.none'
+              requiredIf: "overflow == 'Overflow.visible'"
+          - kind: 'removeParameter'
+            name: 'overflow'
+    variables:
+      overflow:
+        kind: 'fragment'
+        value: 'arguments[overflow]'
+''');
+    await resolveTestCode('''
+import '$importUri';
+
+void f() {
+  const Stack(overflow: Overflow.clip, children: []);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f() {
+  const Stack(clipBehavior: Clip.hardEdge, children: []);
+}
+''');
+  }
+
+  Future<void> test_widgets_Stack_overflow_visible() async {
+    setPackageContent('''
+class Stack {
+  const Stack({
+    @deprecated Overflow overflow: Overflow.clip,
+    Clip clipBehavior: Clip.hardEdge,
+    List<Widget> children: const <Widget>[]});
+}
+class Overflow {
+  static const Overflow clip = Overflow();
+  static const Overflow visible = Overflow();
+  const Overflow();
+}
+class Clip {
+  static const Clip hardEdge = Clip();
+  static const Clip none = Clip();
+  const Clip();
+}
+class Widget {}
+''');
+    addPackageDataFile('''
+version: 1
+transforms:
+  - title: "Migrate to 'clipBehavior'"
+    date: 2020-09-22
+    element:
+      uris: ['$importUri']
+      constructor: ''
+      inClass: 'Stack'
+    oneOf:
+      - if: "overflow == 'Overflow.clip'"
+        changes:
+          - kind: 'addParameter'
+            index: 0
+            name: 'clipBehavior'
+            style: optional_named
+            argumentValue:
+              expression: 'Clip.hardEdge'
+              requiredIf: "overflow == 'Overflow.clip'"
+          - kind: 'removeParameter'
+            name: 'overflow'
+      - if: "overflow == 'Overflow.visible'"
+        changes:
+          - kind: 'addParameter'
+            index: 0
+            name: 'clipBehavior'
+            style: optional_named
+            argumentValue:
+              expression: 'Clip.none'
+              requiredIf: "overflow == 'Overflow.visible'"
+          - kind: 'removeParameter'
+            name: 'overflow'
+    variables:
+      overflow:
+        kind: 'fragment'
+        value: 'arguments[overflow]'
+''');
+    await resolveTestCode('''
+import '$importUri';
+
+void f() {
+  const Stack(overflow: Overflow.visible, children: []);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f() {
+  const Stack(clipBehavior: Clip.none, children: []);
+}
+''');
+  }
+
   Future<void>
       test_widgets_StatefulElement_inheritFromElement_deprecated() async {
     setPackageContent('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
index d67d30e..77e7e1f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
@@ -101,7 +101,7 @@
 import '$importUri';
 
 void f(C c) {
-  c.m2(b: 1, a: 0);
+  c.m2(a: 0, b: 1);
 }
 ''');
   }