Version 2.12.0-277.0.dev

Merge commit '53f5179b45911fd1f937239f91e55ec8badd7975' into 'dev'
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);
 }
 ''');
   }
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index 370e772..9544b3a 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -381,7 +381,12 @@
         useHotReload = useHotReload ?? false,
         useHotReloadRollback = useHotReloadRollback ?? false,
         useSdk = useSdk ?? false,
-        useQemu = useQemu ?? false;
+        useQemu = useQemu ?? false {
+    if (name.contains(" ")) {
+      throw ArgumentError(
+          "Name of test configuration cannot contain spaces: $name");
+    }
+  }
 
   /// Returns `true` if this configuration's options all have the same values
   /// as [other].
diff --git a/pkg/smith/test/configuration_test.dart b/pkg/smith/test/configuration_test.dart
index d558cc2..7a5b424 100644
--- a/pkg/smith/test/configuration_test.dart
+++ b/pkg/smith/test/configuration_test.dart
@@ -303,7 +303,7 @@
       );
 
       var debugWithAsserts2 = Configuration(
-        "different name",
+        "different-name",
         Architecture.x64,
         Compiler.dart2js,
         Mode.debug,
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 7c51016..af07581a 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -854,7 +854,7 @@
             for (var sanitizerName in sanitizers.split(",")) {
               var sanitizer = Sanitizer.find(sanitizerName);
               var configuration = Configuration(
-                  "custom configuration_${configurationNumber++}",
+                  "custom-configuration-${configurationNumber++}",
                   architecture,
                   compiler,
                   mode,
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index dc2404f..347484e 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -124,7 +124,7 @@
   /// If [growable] is `false`, which is the default,
   /// the list is a fixed-length list of length zero.
   /// If [growable] is `true`, the list is growable and equivalent to `<E>[]`.
-  @Since("2.8")
+  @Since("2.9")
   external factory List.empty({bool growable = false});
 
   /// Creates a list containing all [elements].
diff --git a/tests/language/operator/operator_triple_shift_error_test.dart b/tests/language/operator/operator_triple_shift_error_test.dart
new file mode 100644
index 0000000..ffe2632
--- /dev/null
+++ b/tests/language/operator/operator_triple_shift_error_test.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2021, 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.
+
+// SharedOptions=--enable-experiment=triple-shift
+
+// Can only be declared with exactly one required positional parameter.
+class C2 {
+  Object? operator >>>(arg1, arg2) => arg1;
+  //               ^
+  // [cfe] Operator '>>>' should have exactly one parameter.
+  //               ^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR
+}
+
+class CO1 {
+  Object? operator >>>([arg1]) => arg1;
+  //                    ^^^^
+  // [cfe] An operator can't have optional parameters.
+  // [analyzer] COMPILE_TIME_ERROR.OPTIONAL_PARAMETER_IN_OPERATOR
+}
+
+class C1O1 {
+  Object? operator >>>(arg1, [arg2]) => arg1;
+  //               ^
+  // [cfe] Operator '>>>' should have exactly one parameter.
+  //                          ^^^^
+  // [analyzer] COMPILE_TIME_ERROR.OPTIONAL_PARAMETER_IN_OPERATOR
+}
+
+class C1N1 {
+  Object? operator >>>(arg1, {arg2}) => arg1;
+  //               ^
+  // [cfe] Operator '>>>' should have exactly one parameter.
+  //                          ^^^^
+  // [analyzer] COMPILE_TIME_ERROR.OPTIONAL_PARAMETER_IN_OPERATOR
+}
+
+class C0 {
+  Object? operator >>>() => 0;
+  //               ^
+  // [cfe] Operator '>>>' should have exactly one parameter.
+  //               ^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR
+}
+
+// Operators cannot be generic.
+class Gen {
+  Object? operator >>> <T>(T arg1) => arg1;
+  //                    ^
+  // [cfe] Types parameters aren't allowed when defining an operator.
+  //                   ^^^
+  // [analyzer] SYNTACTIC_ERROR.TYPE_PARAMETERS_ON_OPERATOR
+}
+
+// Operators cannot be static.
+class Static {
+  /**/ static Object? operator >>>(arg) => arg;
+  //   ^^^^^^
+  // [cfe] Operators can't be static.
+  // [analyzer] SYNTACTIC_ERROR.STATIC_OPERATOR
+}
+
+main() {
+  C0();
+  CO1();
+  C1O1();
+  C1N1();
+  C2();
+  Gen();
+  Static();
+}
diff --git a/tests/language/operator/operator_triple_shift_test.dart b/tests/language/operator/operator_triple_shift_test.dart
new file mode 100644
index 0000000..2bbb811
--- /dev/null
+++ b/tests/language/operator/operator_triple_shift_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2021, 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.
+
+// SharedOptions=--enable-experiment=triple-shift
+
+import "package:expect/expect.dart";
+
+class C {
+  static int ctr = 0;
+  final Object? _text;
+  C([Object? text]) : _text = text ?? "${++ctr}";
+
+  // It's possible to declare a `>>>` operator.
+  C operator >>>(arg) => C("(${++ctr}:$_text>>>$arg)");
+
+  // + binds more strongly than `>>`, `>>>` and `<<`.
+  C operator +(arg) => C("(${++ctr}:$_text+$arg)");
+  // Both `>>` and `<<` binds exactly as strongly as `>>>`.
+  C operator >>(arg) => C("(${++ctr}:$_text>>$arg)");
+  C operator <<(arg) => C("(${++ctr}:$_text<<$arg)");
+  // & binds less strongly than `>>`, `>>>` and `<<`.
+  C operator &(arg) =>  C("(${++ctr}:$_text&$arg)");
+
+  String toString() => "${_text}";
+}
+
+class NSM {
+  noSuchMethod(i) => i.memberName;
+}
+
+// Valid in extensions too.
+extension ShiftIt<T> on T {
+  List<T> operator >>>(int count) => List<T>.filled(count, this);
+}
+
+main() {
+  // It's possible to use the `>>>` operator.
+  // Evaluation is left-to-right.
+  Expect.equals("(3:1>>>2)", "${C() >>> C()}");
+
+  var c = C();
+  Expect.equals("4", "$c");
+  c >>>= C();
+  Expect.equals("(6:4>>>5)", "$c");
+
+  // Precedence is as expected.
+  // Different precedence than + (which binds stronger) and & (which doesn't).
+  Expect.equals("(11:(9:7+8)>>>10)", "${C() + C() >>> C()}");
+  Expect.equals("(16:12>>>(15:13+14))", "${C() >>> C() + C()}");
+  Expect.equals("(23:(19:17+18)>>>(22:20+21))", "${C() + C() >>> C() + C()}");
+  Expect.equals("(28:(26:24>>>25)&27)", "${C() >>> C() & C()}");
+  Expect.equals("(33:29&(32:30>>>31))", "${C() & C() >>> C()}");
+  Expect.equals("(40:(38:34&(37:35>>>36))&39)", "${C() & C() >>> C() & C()}");
+
+  // Same precedence as `>>` and `<<`, left associative.
+  Expect.equals("(45:(43:41>>>42)>>44)", "${C() >>> C() >> C()}");
+  Expect.equals("(50:(48:46>>47)>>>49)", "${C() >> C() >>> C()}");
+  Expect.equals("(55:(53:51>>>52)<<54)", "${C() >>> C() << C()}");
+  Expect.equals("(60:(58:56<<57)>>>59)", "${C() << C() >>> C()}");
+  Expect.equals("(67:(65:(63:61<<62)>>>64)>>66)",
+      "${C() << C() >>> C() >> C()}");
+
+  /// The `>>>` Symbol works.
+  var literalSymbol = #>>>;
+  var constSymbol = const Symbol(">>>");
+  var newSymbol = new Symbol(">>>");
+  Expect.identical(literalSymbol, constSymbol);
+  Expect.equals(literalSymbol, newSymbol);
+
+  dynamic n = NSM();
+  var nsmSymbol = n >>> 42;
+  Expect.equals(nsmSymbol, literalSymbol);
+
+  var o = Object();
+  Expect.listEquals([o, o, o, o, o], o >>> 5);
+}
diff --git a/tools/VERSION b/tools/VERSION
index e6d915e..5527eb6 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 276
+PRERELEASE 277
 PRERELEASE_PATCH 0
\ No newline at end of file