Version 2.19.0-31.0.dev

Merge commit '56dc3e360ac07e9a7a1d952f2e576c73e0f4d92e' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart
index 63bd7e8..4ea4091 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_contains.dart
@@ -6,6 +6,7 @@
 import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/source/source_range.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
@@ -37,6 +38,7 @@
         return;
       }
       var methodName = leftOperand.methodName;
+      var startArgumentRange = _startArgumentRange(leftOperand);
       var deletionRange = range.endEnd(leftOperand, rightOperand);
       var notOffset = -1;
       var style = _negationStyle(comparison.operator.type, value);
@@ -51,6 +53,9 @@
           builder.addSimpleInsertion(notOffset, '!');
         }
         builder.addSimpleReplacement(range.node(methodName), 'contains');
+        if (startArgumentRange != null) {
+          builder.addDeletion(startArgumentRange);
+        }
         builder.addDeletion(deletionRange);
       });
     } else if (_isInteger(leftOperand) && rightOperand is MethodInvocation) {
@@ -59,6 +64,7 @@
         return;
       }
       var methodName = rightOperand.methodName;
+      var startArgumentRange = _startArgumentRange(rightOperand);
       var deletionRange = range.startStart(leftOperand, rightOperand);
       var notOffset = -1;
       var style =
@@ -75,6 +81,9 @@
           builder.addSimpleInsertion(notOffset, '!');
         }
         builder.addSimpleReplacement(range.node(methodName), 'contains');
+        if (startArgumentRange != null) {
+          builder.addDeletion(startArgumentRange);
+        }
       });
     }
   }
@@ -156,6 +165,16 @@
     // so we should never reach this point.
     return NegationStyle.none;
   }
+
+  SourceRange? _startArgumentRange(MethodInvocation invocation) {
+    var arguments = invocation.argumentList.arguments;
+    if (arguments.length == 2) {
+      var firstArgument = arguments[0];
+      var secondArgument = arguments[1];
+      return range.endEnd(firstArgument, secondArgument);
+    }
+    return null;
+  }
 }
 
 /// An indication of whether the `contains` test should be negated, not negated,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_contains_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_contains_test.dart
index d0e335b..6828965 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_contains_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_contains_test.dart
@@ -242,4 +242,30 @@
 }
 ''');
   }
+
+  Future<void> test_twoArguments_left() async {
+    await resolveTestCode('''
+bool f(List<int> list, int value) {
+  return list.indexOf(value, 0) >= 0;
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return list.contains(value);
+}
+''');
+  }
+
+  Future<void> test_twoArguments_right() async {
+    await resolveTestCode('''
+bool f(List<int> list, int value) {
+  return 0 <= list.indexOf(value, 0);
+}
+''');
+    await assertHasFix('''
+bool f(List<int> list, int value) {
+  return list.contains(value);
+}
+''');
+  }
 }
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index 20aa8ab..0ace941 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -467,7 +467,7 @@
   void addAll(Iterable<E> iterable) {}
   Map<int, E> asMap() => throw 0;
   void clear() {}
-  int indexOf(Object element);
+  int indexOf(E element, [int start = 0]);
   bool remove(Object? value);
   E removeLast() => throw 0;
 
diff --git a/tools/VERSION b/tools/VERSION
index e2c5c13..685935a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 30
+PRERELEASE 31
 PRERELEASE_PATCH 0
\ No newline at end of file