Version 2.10.0-42.0.dev

Merge commit '4af6831020f596e44c0ed91da16c47975469dbba' into 'dev'
diff --git a/DEPS b/DEPS
index f16ed79..f6b082a 100644
--- a/DEPS
+++ b/DEPS
@@ -48,7 +48,7 @@
   "co19_2_rev": "e48b3090826cf40b8037648f19d211e8eab1b4b6",
 
   # The internal benchmarks to use. See go/dart-benchmarks-internal
-  "benchmarks_internal_rev": "01b76c69ca61d3184d4896d230c5bfd439b84d27",
+  "benchmarks_internal_rev": "7030a669aa70e2558cdebb3a89b6d11a34d09051",
   "checkout_benchmarks_internal": False,
 
   # As Flutter does, we use Fuchsia's GN and Clang toolchain. These revision
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
new file mode 100644
index 0000000..c105418
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
@@ -0,0 +1,350 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/dart/data_driven.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/change.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/value_extractor.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+import 'package:meta/meta.dart';
+
+/// The addition of a new parameter.
+class AddParameter extends ParameterModification {
+  /// The index of the parameter in the parameter list after the modifications
+  /// have been applied.
+  final int index;
+
+  /// The name of the parameter that was added.
+  final String name;
+
+  /// A flag indicating whether the parameter is a required parameter.
+  final bool isRequired;
+
+  /// A flag indicating whether the parameter is a positional parameter.
+  final bool isPositional;
+
+  /// The default value of the parameter, or `null` if the parameter doesn't
+  /// have a default value.
+  final ValueExtractor defaultValue;
+
+  /// The value of the new argument in invocations of the function, or `null` if
+  /// the parameter is optional and no argument needs to be added. The only time
+  /// an argument needs to be added for an optional parameter is if the
+  /// parameter is positional and there are pre-existing optional positional
+  /// parameters after the ones being added.
+  final ValueExtractor argumentValue;
+
+  /// Initialize a newly created parameter modification to represent the
+  /// addition of a parameter. If provided, the [argumentValue] will be used as
+  /// the value of the new argument in invocations of the function.
+  AddParameter(this.index, this.name, this.isRequired, this.isPositional,
+      this.defaultValue, this.argumentValue)
+      : assert(index >= 0),
+        assert(name != null);
+}
+
+/// The data related to an executable element whose parameters have been
+/// modified.
+class ModifyParameters extends Change<_Data> {
+  /// A list of the modifications being made.
+  final List<ParameterModification> modifications;
+
+  /// Initialize a newly created transform to modifications to the parameter
+  /// list of a function.
+  ModifyParameters({@required this.modifications})
+      : assert(modifications != null),
+        assert(modifications.isNotEmpty);
+
+  @override
+  void apply(DartFileEditBuilder builder, DataDrivenFix fix, _Data data) {
+    if (data is _InvocationSiteData) {
+      _applyToInvocationSite(builder, fix, data);
+    } else if (data is _OverrideData) {
+      _applyToOverride(builder, fix, data);
+    } else {
+      throw StateError('Unsupported class of data: ${data.runtimeType}');
+    }
+  }
+
+  @override
+  _Data validate(DataDrivenFix fix) {
+    var node = fix.node;
+    var parent = node.parent;
+    if (parent is InvocationExpression) {
+      var argumentList = parent.argumentList;
+      return _InvocationSiteData(argumentList);
+    }
+    // TODO(brianwilkerson) Recognize cases where a method that used to be an
+    //  override of a removed method needs to be migrated and return an
+    //  [_OverrideData] to represent that case.
+    return null;
+  }
+
+  void _applyToInvocationSite(DartFileEditBuilder builder, DataDrivenFix fix,
+      _InvocationSiteData data) {
+    var argumentList = data.argumentList;
+    var arguments = argumentList.arguments;
+    var argumentCount = arguments.length;
+    var newNamed = <AddParameter>[];
+    var indexToNewArgumentMap = <int, AddParameter>{};
+    var argumentsToInsert = <int>[];
+    var argumentsToDelete = <int>[];
+    var remainingArguments = [for (var i = 0; i < argumentCount; i++) i];
+    for (var modification in modifications) {
+      if (modification is AddParameter) {
+        var index = modification.index;
+        indexToNewArgumentMap[index] = modification;
+        if (modification.isPositional) {
+          argumentsToInsert.add(index);
+        } else if (modification.isRequired) {
+          newNamed.add(modification);
+        }
+      } else if (modification is RemoveParameter) {
+        var argument = modification.parameter.argumentFrom(argumentList);
+        // If there is no argument corresponding to the parameter then we assume
+        // that the parameter was optional (and absent) and don't try to remove
+        // it.
+        if (argument != null) {
+          var index = arguments.indexOf(_realArgument(argument));
+          argumentsToDelete.add(index);
+          remainingArguments.remove(index);
+        }
+      }
+    }
+    argumentsToInsert.sort();
+    newNamed.sort((first, second) => first.name.compareTo(second.name));
+
+    /// Write to the [builder] the argument associated with a single
+    /// [parameter].
+    void writeArgument(DartEditBuilder builder, AddParameter parameter) {
+      var value = parameter.argumentValue.from(argumentList, fix.utils);
+      if (!parameter.isPositional) {
+        builder.write(parameter.name);
+        builder.write(': ');
+      }
+      builder.write(value);
+    }
+
+    var insertionRanges = argumentsToInsert.contiguousSubRanges.toList();
+    var deletionRanges = argumentsToDelete.contiguousSubRanges.toList();
+    if (insertionRanges.isNotEmpty) {
+      /// Write to the [builder] the new arguments in the [insertionRange]. If
+      /// [needsInitialComma] is `true` then we need to write a comma before the
+      /// first of the new arguments.
+      void writeInsertionRange(DartEditBuilder builder,
+          _IndexRange insertionRange, bool needsInitialComma) {
+        var needsComma = needsInitialComma;
+        for (var argumentIndex = insertionRange.lower;
+            argumentIndex <= insertionRange.upper;
+            argumentIndex++) {
+          if (needsComma) {
+            builder.write(', ');
+          } else {
+            needsComma = true;
+          }
+          var parameter = indexToNewArgumentMap[argumentIndex];
+          writeArgument(builder, parameter);
+        }
+      }
+
+      var nextRemaining = 0;
+      var nextInsertionRange = 0;
+      var insertionCount = 0;
+      while (nextRemaining < remainingArguments.length &&
+          nextInsertionRange < insertionRanges.length) {
+        var remainingIndex = remainingArguments[nextRemaining];
+        var insertionRange = insertionRanges[nextInsertionRange];
+        var insertionIndex = insertionRange.lower;
+        if (insertionIndex <= remainingIndex + insertionCount) {
+          // There are arguments that need to be inserted before the next
+          // remaining argument.
+          var deletionRange =
+              _rangeContaining(deletionRanges, insertionIndex - 1);
+          if (deletionRange == null) {
+            // The insertion range doesn't overlap a deletion range, so insert
+            // the added arguments before the argument whose index is
+            // `remainingIndex`.
+            int offset;
+            var needsInitialComma = false;
+            if (insertionIndex > 0) {
+              offset = arguments[remainingIndex - 1].end;
+              needsInitialComma = true;
+            } else {
+              offset = arguments[remainingIndex].offset;
+            }
+            builder.addInsertion(offset, (builder) {
+              writeInsertionRange(builder, insertionRange, needsInitialComma);
+              if (insertionIndex == 0) {
+                builder.write(', ');
+              }
+            });
+          } else {
+            // The insertion range overlaps a deletion range, so replace the
+            // arguments in the deletion range with the arguments in the
+            // insertion range.
+            var replacementRange = range.argumentRange(
+                argumentList, deletionRange.lower, deletionRange.upper, false);
+            builder.addReplacement(replacementRange, (builder) {
+              writeInsertionRange(builder, insertionRange, false);
+            });
+            deletionRanges.remove(deletionRange);
+          }
+          insertionCount += insertionRange.count;
+          nextInsertionRange++;
+        } else {
+          // There are no arguments that need to be inserted before the next
+          // remaining argument, so just move past the next remaining argument.
+          nextRemaining++;
+        }
+      }
+      // The remaining insertion ranges might include new required arguments
+      // that need to be inserted after the last argument.
+      var offset = arguments[arguments.length - 1].end;
+      while (nextInsertionRange < insertionRanges.length) {
+        var insertionRange = insertionRanges[nextInsertionRange];
+        var lower = insertionRange.lower;
+        var upper = insertionRange.upper;
+        while (upper >= lower && !indexToNewArgumentMap[upper].isRequired) {
+          upper--;
+        }
+        if (upper >= lower) {
+          builder.addInsertion(offset, (builder) {
+            writeInsertionRange(builder, _IndexRange(lower, upper), true);
+          });
+        }
+        nextInsertionRange++;
+      }
+    }
+    //
+    // Insert arguments for required named parameters.
+    //
+    if (newNamed.isNotEmpty) {
+      int offset;
+      var needsInitialComma = false;
+      if (arguments.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) {
+      builder.addDeletion(range.argumentRange(
+          argumentList, subRange.lower, subRange.upper, true));
+    }
+  }
+
+  void _applyToOverride(
+      DartFileEditBuilder builder, DataDrivenFix fix, _OverrideData data) {
+    // TODO(brianwilkerson) Implement this.
+    throw UnsupportedError('Updating override sites is not yet supported.');
+  }
+
+  /// Return the range from the list of [ranges] that contains the given
+  /// [index], or `null` if there is no such range.
+  _IndexRange _rangeContaining(List<_IndexRange> ranges, int index) {
+    for (var range in ranges) {
+      if (index >= range.lower && index <= range.upper) {
+        return range;
+      }
+    }
+    return null;
+  }
+
+  /// Return the element of the argument list whose value is the given
+  /// [argument]. If the argument is the child of a named expression, then that
+  /// will be the named expression, otherwise it will be the argument itself.
+  Expression _realArgument(Expression argument) =>
+      argument.parent is NamedExpression ? argument.parent : argument;
+}
+
+/// A modification related to a parameter.
+abstract class ParameterModification {}
+
+/// The removal of an existing parameter.
+class RemoveParameter extends ParameterModification {
+  /// The parameter that was removed.
+  final ParameterReference parameter;
+
+  /// Initialize a newly created parameter modification to represent the removal
+  /// of an existing [parameter].
+  RemoveParameter(this.parameter) : assert(parameter != null);
+}
+
+/// The data returned when modifying a parameter list.
+class _Data {}
+
+/// A range of indexes within a list.
+class _IndexRange {
+  /// The index of the first element in the range.
+  final int lower;
+
+  /// The index of the last element in the range. This will be the same as the
+  /// [lower] if there is a single element in the range.
+  final int upper;
+
+  /// Initialize a newly created range.
+  _IndexRange(this.lower, this.upper);
+
+  /// Return the number of indices in this range.
+  int get count => upper - lower + 1;
+
+  @override
+  String toString() => '[$lower..$upper]';
+}
+
+/// The data returned when updating an invocation site.
+class _InvocationSiteData extends _Data {
+  /// The argument list to be updated.
+  final ArgumentList argumentList;
+
+  /// Initialize a newly created data object with the data needed to update an
+  /// invocation site.
+  _InvocationSiteData(this.argumentList);
+}
+
+/// The data returned when updating an override of the modified method.
+class _OverrideData extends _Data {
+  /// The parameter list to be updated.
+  final FormalParameterList parameter;
+
+  /// Initialize a newly created data object with the data needed to update an
+  /// override of the modified method.
+  _OverrideData(this.parameter);
+}
+
+extension on List<int> {
+  Iterable<_IndexRange> get contiguousSubRanges sync* {
+    if (isEmpty) {
+      return;
+    }
+    var lower = this[0];
+    var previous = lower;
+    var index = 1;
+    while (index < length) {
+      var current = this[index];
+      if (current == previous + 1) {
+        previous = current;
+      } else {
+        yield _IndexRange(lower, previous);
+        lower = previous = current;
+      }
+      index++;
+    }
+    yield _IndexRange(lower, previous);
+  }
+}
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
new file mode 100644
index 0000000..9ad4435
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
@@ -0,0 +1,849 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/element_descriptor.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/modify_parameters.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/rename_change.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/value_extractor.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'data_driven_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ModifyParameters_DeprecatedMemberUseTest);
+  });
+}
+
+/// In the tests where a required named parameter is being added, the tests
+/// avoid the question of whether the defining library is opted in to the
+/// null-safety feature by omitting both the `required` keyword and annotation.
+/// This works because the information the change needs is taken from the
+/// `AddParameter` object rather than the source code.
+///
+/// The tests for 'function' exist to check that these changes can also be
+/// applied to top-level functions, but are not intended to be exhaustive.
+@reflectiveTest
+class ModifyParameters_DeprecatedMemberUseTest extends _ModifyParameters {
+  Future<void> test_add_function_first_optionalNamed() async {
+    setPackageContent('''
+@deprecated
+void f(int b) {}
+void g(int a, int b) {}
+''');
+    setPackageData(_modify([
+      'f'
+    ], [
+      AddParameter(0, 'a', true, true, null, LiteralExtractor('0')),
+    ], newName: 'g'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void h() {
+  f(1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void h() {
+  g(0, 1);
+}
+''');
+  }
+
+  Future<void> test_add_method_first_optionalNamed() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m({int b}) {}
+  void m2({int a, int b}) {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [AddParameter(1, 'a', false, false, null, null)],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(b: 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(b: 1);
+}
+''');
+  }
+
+  Future<void> test_add_method_first_optionalPositional() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m([int b]) {}
+  void m2([int a, int b]) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      AddParameter(0, 'a', false, true, null, LiteralExtractor('0'))
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0, 1);
+}
+''');
+  }
+
+  Future<void> test_add_method_first_requiredNamed() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m({int b}) {}
+  void m2({int a, int b}) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      AddParameter(0, 'a', true, false, null, LiteralExtractor('0'))
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(b: 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(b: 1, a: 0);
+}
+''');
+  }
+
+  Future<void> test_add_method_first_requiredPositional() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int b) {}
+  void m2(int a, int b) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      AddParameter(0, 'a', true, true, null, LiteralExtractor('0'))
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0, 1);
+}
+''');
+  }
+
+  Future<void> test_add_method_last_optionalNamed() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a) {}
+  void m2(int a, {int b}) {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [AddParameter(1, 'b', false, false, null, null)],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0);
+}
+''');
+  }
+
+  Future<void> test_add_method_last_optionalPositional() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a) {}
+  void m2(int a, [int b]) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      AddParameter(1, 'b', false, true, null, LiteralExtractor('1'))
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0);
+}
+''');
+  }
+
+  Future<void> test_add_method_last_requiredNamed() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a) {}
+  void m2(int a, {int b}) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      AddParameter(1, 'b', true, false, null, LiteralExtractor('1'))
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0, b: 1);
+}
+''');
+  }
+
+  Future<void> test_add_method_last_requiredPositional() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a) {}
+  void m2(int a, int b) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      AddParameter(1, 'b', true, true, null, LiteralExtractor('1'))
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0, 1);
+}
+''');
+  }
+
+  Future<void> test_add_method_multiple() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a, int d, int f) {}
+  void m2(int a, int b, int c, int d, int e, int f) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      AddParameter(1, 'b', true, true, null, LiteralExtractor('1')),
+      AddParameter(2, 'c', true, true, null, LiteralExtractor('2')),
+      AddParameter(4, 'e', true, true, null, LiteralExtractor('4')),
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0, 3, 5);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0, 1, 2, 3, 4, 5);
+}
+''');
+  }
+
+  Future<void> test_mixed_method_noOverlap_removedFirst() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a, int b) {}
+  void m2(int b, int c) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      RemoveParameter(PositionalParameterReference(0)),
+      AddParameter(2, 'c', true, true, null, LiteralExtractor('2'))
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0, 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(1, 2);
+}
+''');
+  }
+
+  Future<void> test_mixed_method_noOverlap_removedLast() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int b, int c) {}
+  void m2(int a, int b) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      RemoveParameter(PositionalParameterReference(1)),
+      AddParameter(0, 'a', true, true, null, LiteralExtractor('0'))
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(1, 2);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0, 1);
+}
+''');
+  }
+
+  Future<void> test_mixed_method_overlap_first() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m1(int a, int b, int d) {}
+  void m2(       int c, int d) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm1'
+    ], [
+      RemoveParameter(PositionalParameterReference(0)),
+      RemoveParameter(PositionalParameterReference(1)),
+      AddParameter(0, 'c', true, true, null, LiteralExtractor('2')),
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m1(0, 1, 3);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(2, 3);
+}
+''');
+  }
+
+  Future<void> test_mixed_method_overlap_last() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m1(int a, int b, int c) {}
+  void m2(int a,        int d) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm1'
+    ], [
+      RemoveParameter(PositionalParameterReference(1)),
+      RemoveParameter(PositionalParameterReference(2)),
+      AddParameter(1, 'd', true, true, null, LiteralExtractor('3')),
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m1(0, 1, 2);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0, 3);
+}
+''');
+  }
+
+  Future<void> test_mixed_method_overlap_middle() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m1(       int b, int c, int e, int f, int g) {}
+  void m2(int a, int b, int d, int e,        int g) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm1'
+    ], [
+      AddParameter(0, 'a', true, true, null, LiteralExtractor('0')),
+      RemoveParameter(PositionalParameterReference(1)),
+      RemoveParameter(PositionalParameterReference(3)),
+      AddParameter(2, 'd', true, true, null, LiteralExtractor('3')),
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m1(1, 2, 4, 5, 6);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0, 1, 3, 4, 6);
+}
+''');
+  }
+
+  Future<void> test_remove_function_first_requiredPositional() async {
+    setPackageContent('''
+@deprecated
+void f(int a, int b) {}
+void g(int b) {}
+''');
+    setPackageData(_modify(
+        ['f'], [RemoveParameter(PositionalParameterReference(0))],
+        newName: 'g'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void h() {
+  f(0, 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void h() {
+  g(1);
+}
+''');
+  }
+
+  Future<void> test_remove_method_first_optionalNamed() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m({int a, int b}) {}
+  void m2({int b}) {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(NamedParameterReference('a'))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(a: 0, b: 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(b: 1);
+}
+''');
+  }
+
+  Future<void> test_remove_method_first_optionalPositional() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m([int a, int b]) {}
+  void m2([int b]) {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(PositionalParameterReference(0))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0, 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(1);
+}
+''');
+  }
+
+  Future<void> test_remove_method_first_requiredPositional() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a, int b) {}
+  void m2(int b) {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(PositionalParameterReference(0))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0, 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(1);
+}
+''');
+  }
+
+  Future<void> test_remove_method_last_optionalNamed() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m({int a, int b}) {}
+  void m2({int b}) {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(NamedParameterReference('b'))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(a: 0, b: 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(a: 0);
+}
+''');
+  }
+
+  Future<void> test_remove_method_last_optionalPositional() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m([int a, int b]) {}
+  void m2([int b]) {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(PositionalParameterReference(1))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0, 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0);
+}
+''');
+  }
+
+  Future<void> test_remove_method_last_requiredPositional() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a, int b) {}
+  void m2(int b) {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(PositionalParameterReference(1))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0, 1);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(0);
+}
+''');
+  }
+
+  Future<void> test_remove_method_multiple() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a, int b, int c, int d) {}
+  void m2(int b) {}
+}
+''');
+    setPackageData(_modify([
+      'C',
+      'm'
+    ], [
+      RemoveParameter(PositionalParameterReference(0)),
+      RemoveParameter(PositionalParameterReference(2)),
+      RemoveParameter(PositionalParameterReference(3)),
+    ], newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0, 1, 2, 3);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2(1);
+}
+''');
+  }
+
+  Future<void> test_remove_method_only_optionalNamed_withArg() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m({int a}) {}
+  void m2() {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(NamedParameterReference('a'))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(a: 0);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2();
+}
+''');
+  }
+
+  Future<void> test_remove_method_only_optionalNamed_withoutArg() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m({int a}) {}
+  void m2() {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(NamedParameterReference('a'))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m();
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2();
+}
+''');
+  }
+
+  Future<void> test_remove_method_only_optionalPositional_withArg() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m([int a]) {}
+  void m2() {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(PositionalParameterReference(0))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2();
+}
+''');
+  }
+
+  Future<void> test_remove_method_only_optionalPositional_withoutArg() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m([int a]) {}
+  void m2() {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(PositionalParameterReference(0))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m();
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2();
+}
+''');
+  }
+
+  Future<void> test_remove_method_only_requiredPositional() async {
+    setPackageContent('''
+class C {
+  @deprecated
+  void m(int a) {}
+  void m2() {}
+}
+''');
+    setPackageData(_modify(
+        ['C', 'm'], [RemoveParameter(PositionalParameterReference(0))],
+        newName: 'm2'));
+    await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+  c.m(0);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+  c.m2();
+}
+''');
+  }
+}
+
+abstract class _ModifyParameters extends DataDrivenFixProcessorTest {
+  Transform _modify(List<String> originalComponents,
+          List<ParameterModification> modifications, {String newName}) =>
+      Transform(
+          title: 'title',
+          element: ElementDescriptor(
+              libraryUris: [importUri], components: originalComponents),
+          changes: [
+            ModifyParameters(modifications: modifications),
+            if (newName != null) RenameChange(newName: newName),
+          ]);
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
index dd6eaea..8773441 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
@@ -5,11 +5,13 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'add_type_parameter_change_test.dart' as add_type_parameter_change;
+import 'modify_parameters_test.dart' as modify_parameters;
 import 'rename_change_test.dart' as rename_change;
 
 void main() {
   defineReflectiveSuite(() {
     add_type_parameter_change.main();
+    modify_parameters.main();
     rename_change.main();
   });
 }
diff --git a/pkg/analyzer_plugin/lib/utilities/range_factory.dart b/pkg/analyzer_plugin/lib/utilities/range_factory.dart
index c791818..fbcbaa3 100644
--- a/pkg/analyzer_plugin/lib/utilities/range_factory.dart
+++ b/pkg/analyzer_plugin/lib/utilities/range_factory.dart
@@ -15,6 +15,51 @@
 /// A factory used to create instances of [SourceRange] based on various
 /// syntactic and semantic entities.
 class RangeFactory {
+  /// Return a source range that covers all of the arguments in the
+  /// [argumentList] between the [lower] and [upper] indices, inclusive. The
+  /// flag [forDeletion] controls whether a comma between the given indices and
+  /// the neighboring arguments should be included in the range. If the flag is
+  /// `true`, then the range can be deleted to delete the covered arguments and
+  /// leave a valid argument list. If the flag is `false`, then the range can be
+  /// replaced with different argument values.
+  ///
+  /// For example, given an argument list of `(a, b, c, d)`, a lower index of
+  /// `1` and an upper index of `2`, the range will cover the text `'b, c'` if
+  /// [forDeletion] is `false` and the text `', b, c'` if [forDeletion] is
+  /// `true`.
+  ///
+  /// Throws and exception if either the [lower] or [upper] bound is not a valid
+  /// index into the [argumentList] or if the [upper] bound is less than the
+  /// [lower] bound.
+  SourceRange argumentRange(
+      ArgumentList argumentList, int lower, int upper, bool forDeletion) {
+    var arguments = argumentList.arguments;
+    assert(lower >= 0 && lower < arguments.length);
+    assert(upper >= lower && upper < arguments.length);
+    if (lower == upper) {
+      // Remove a single argument.
+      if (forDeletion) {
+        return nodeInList(arguments, arguments[lower]);
+      }
+      return node(arguments[lower]);
+    } else if (!forDeletion) {
+      return startEnd(arguments[lower], arguments[upper]);
+    } else if (lower == 0) {
+      if (upper == arguments.length - 1) {
+        // Remove all of the arguments.
+        return endStart(
+            argumentList.leftParenthesis, argumentList.rightParenthesis);
+      } else {
+        // Remove a subset of the arguments starting with the first argument.
+        return startStart(arguments[lower], arguments[upper + 1]);
+      }
+    } else {
+      // Remove a subset of the arguments starting in the middle of the
+      // arguments.
+      return endEnd(arguments[lower - 1], arguments[upper]);
+    }
+  }
+
   /// Return a source range that covers the name of the given [element].
   SourceRange elementName(Element element) {
     return SourceRange(element.nameOffset, element.nameLength);
diff --git a/pkg/analyzer_plugin/test/utilities/range_factory_test.dart b/pkg/analyzer_plugin/test/utilities/range_factory_test.dart
index 9ab8590..a2ac201 100644
--- a/pkg/analyzer_plugin/test/utilities/range_factory_test.dart
+++ b/pkg/analyzer_plugin/test/utilities/range_factory_test.dart
@@ -31,6 +31,146 @@
     return invocation.argumentList.arguments;
   }
 
+  Future<void> test_argumentRange_all_mixed_noTrailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1, c: 2);
+}
+void g(int a, int b, {int c}) {}
+''');
+    _assertArgumentRange(0, 2, SourceRange(15, 10), SourceRange(15, 10));
+  }
+
+  Future<void> test_argumentRange_all_mixed_trailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1, c: 2, );
+}
+void g(int a, int b, {int c}) {}
+''');
+    _assertArgumentRange(0, 2, SourceRange(15, 12), SourceRange(15, 10));
+  }
+
+  Future<void> test_argumentRange_all_named_noTrailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(a: 0, b: 1, c: 2);
+}
+void g({int a, int b, int c}) {}
+''');
+    _assertArgumentRange(0, 2, SourceRange(15, 16), SourceRange(15, 16));
+  }
+
+  Future<void> test_argumentRange_all_named_trailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(a: 0, b: 1, c: 2, );
+}
+void g({int a, int b, int c}) {}
+''');
+    _assertArgumentRange(0, 2, SourceRange(15, 18), SourceRange(15, 16));
+  }
+
+  Future<void> test_argumentRange_all_positional_noTrailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1, 2);
+}
+void g(int a, int b, int c) {}
+''');
+    _assertArgumentRange(0, 2, SourceRange(15, 7), SourceRange(15, 7));
+  }
+
+  Future<void> test_argumentRange_all_positional_trailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1, 2, );
+}
+void g(int a, int b, int c) {}
+''');
+    _assertArgumentRange(0, 2, SourceRange(15, 9), SourceRange(15, 7));
+  }
+
+  Future<void> test_argumentRange_first_noTrailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1);
+}
+void g(int a, int b) {}
+''');
+    _assertArgumentRange(0, 0, SourceRange(15, 3), SourceRange(15, 1));
+  }
+
+  Future<void> test_argumentRange_first_trailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1, );
+}
+void g(int a, int b) {}
+''');
+    _assertArgumentRange(0, 0, SourceRange(15, 3), SourceRange(15, 1));
+  }
+
+  Future<void> test_argumentRange_last_noTrailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1);
+}
+void g(int a, int b) {}
+''');
+    _assertArgumentRange(1, 1, SourceRange(16, 3), SourceRange(18, 1));
+  }
+
+  Future<void> test_argumentRange_last_trailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1, );
+}
+void g(int a, int b) {}
+''');
+    _assertArgumentRange(1, 1, SourceRange(16, 3), SourceRange(18, 1));
+  }
+
+  Future<void> test_argumentRange_middle_noTrailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1, 2, 3);
+}
+void g(int a, int b, int c, int d) {}
+''');
+    _assertArgumentRange(1, 2, SourceRange(16, 6), SourceRange(18, 4));
+  }
+
+  Future<void> test_argumentRange_middle_trailingComma() async {
+    await resolveTestUnit('''
+void f() {
+  g(0, 1, 2, 3, );
+}
+void g(int a, int b, int c, int d) {}
+''');
+    _assertArgumentRange(1, 2, SourceRange(16, 6), SourceRange(18, 4));
+  }
+
+  Future<void> test_argumentRange_only_named() async {
+    await resolveTestUnit('''
+void f() {
+  g(a: 0);
+}
+void g({int a}) {}
+''');
+    _assertArgumentRange(0, 0, SourceRange(15, 4), SourceRange(15, 4));
+  }
+
+  Future<void> test_argumentRange_only_positional() async {
+    await resolveTestUnit('''
+void f() {
+  g(0);
+}
+void g(int a) {}
+''');
+    _assertArgumentRange(0, 0, SourceRange(15, 1), SourceRange(15, 1));
+  }
+
   Future<void> test_elementName() async {
     await resolveTestUnit('class ABC {}');
     var element = findElement('ABC');
@@ -233,4 +373,22 @@
     var mainName = mainFunction.name;
     expect(range.token(mainName.beginToken), SourceRange(1, 4));
   }
+
+  /// Assuming that the test code starts with a function whose block body starts
+  /// with a method invocation, compute the range for the arguments in the
+  /// invocation's argument list between [lower] and [upper]. Validate that the
+  /// range for deletion matches [expectedForDeletion] and that the range not
+  /// for deletion matches [expectedNoDeletion].
+  void _assertArgumentRange(int lower, int upper,
+      SourceRange expectedForDeletion, SourceRange expectedNoDeletion) {
+    var f = testUnit.declarations[0] as FunctionDeclaration;
+    var body = f.functionExpression.body as BlockFunctionBody;
+    var statement = body.block.statements[0] as ExpressionStatement;
+    var invocation = statement.expression as MethodInvocation;
+    var argumentList = invocation.argumentList;
+    expect(range.argumentRange(argumentList, lower, upper, true),
+        expectedForDeletion);
+    expect(range.argumentRange(argumentList, lower, upper, false),
+        expectedNoDeletion);
+  }
 }
diff --git a/tools/VERSION b/tools/VERSION
index 686f446..433cea6 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 10
 PATCH 0
-PRERELEASE 41
+PRERELEASE 42
 PRERELEASE_PATCH 0
\ No newline at end of file