[analysis_server] fix `RemoveDeadCode` with `forParts`

Bug #43511

Change-Id: I82854382928cd29bfc7c646f0c202d28603f8836
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271200
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_dead_code.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_dead_code.dart
index 845fcdf..d880ccd 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/remove_dead_code.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_dead_code.dart
@@ -57,25 +57,7 @@
       } else if (parent is ForParts) {
         var forStatement = parent.parent;
         if (forStatement is! ForStatement) return;
-
-        var updaters = parent.updaters;
-        if (updaters.contains(coveredNode)) {
-          var isFirstNode = updaters.first == coveredNode;
-          var rightParenthesis = forStatement.rightParenthesis;
-          var isComma = !isFirstNode &&
-              rightParenthesis.previous?.type == TokenType.COMMA;
-
-          var previous = coveredNode.beginToken.previous!;
-
-          var deletionRange = isComma
-              ? range.endStart(previous, rightParenthesis)
-              : range.startStart(
-                  isFirstNode ? coveredNode : previous, rightParenthesis);
-
-          await builder.addDartFileEdit(file, (builder) {
-            builder.addDeletion(deletionRange);
-          });
-        }
+        await _computeForStatementParts(builder, forStatement, parent);
       }
     } else if (coveredNode is Block) {
       var block = coveredNode;
@@ -121,18 +103,7 @@
       var forStatement = coveredNode.parent;
       if (forStatement is! ForStatement) return;
 
-      var problemMessage = diagnostic?.problemMessage;
-      if (problemMessage == null) return;
-
-      var updaters = coveredNode.updaters;
-      var beginOffset = updaters.beginToken!.offset;
-      if (problemMessage.offset == beginOffset &&
-          problemMessage.length == updaters.endToken!.end - beginOffset) {
-        await builder.addDartFileEdit(file, (builder) {
-          builder.addDeletion(range.startOffsetEndOffset(
-              beginOffset, forStatement.rightParenthesis.offset));
-        });
-      }
+      await _computeForStatementParts(builder, forStatement, coveredNode);
     }
   }
 
@@ -197,6 +168,47 @@
     return false;
   }
 
+  Future<void> _computeForStatementParts(ChangeBuilder builder,
+      ForStatement forStatement, ForParts forParts) async {
+    var beginNode = coveredNode;
+    if (beginNode == null) return;
+    var updaters = forParts.updaters;
+    if (!updaters.contains(beginNode)) {
+      var problemMessage = diagnostic?.problemMessage;
+      if (problemMessage == null) return;
+
+      beginNode = null;
+      var problemOffset = problemMessage.offset;
+      var problemLength = problemMessage.length;
+      var updatersEnd = updaters.endToken!.end;
+
+      for (var node in updaters) {
+        var nodeOffset = node.offset;
+        if (problemOffset == nodeOffset &&
+            problemLength == updatersEnd - nodeOffset) {
+          beginNode = node;
+          break;
+        }
+      }
+      if (beginNode == null) return;
+    }
+    var isFirstNode = updaters.first == beginNode;
+    var rightParenthesis = forStatement.rightParenthesis;
+    var isComma =
+        !isFirstNode && rightParenthesis.previous?.type == TokenType.COMMA;
+
+    var previous = beginNode.beginToken.previous!;
+
+    var deletionRange = isComma
+        ? range.endStart(previous, rightParenthesis)
+        : range.startStart(
+            isFirstNode ? beginNode : previous, rightParenthesis);
+
+    await builder.addDartFileEdit(file, (builder) {
+      builder.addDeletion(deletionRange);
+    });
+  }
+
   void _deleteLineRange(DartFileEditBuilder builder, SourceRange sourceRange) {
     builder.addDeletion(utils.getLinesRange(sourceRange));
   }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_dead_code_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_dead_code_test.dart
index 08dd1ce..0b87da7 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_dead_code_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_dead_code_test.dart
@@ -412,6 +412,32 @@
 ''');
   }
 
+  Future<void> test_forParts_updaters_throw_multiple() async {
+    await resolveTestCode('''
+void f() {
+  for (;; 0, throw 1, 2, 3) {}
+}
+''');
+    await assertHasFix('''
+void f() {
+  for (;; 0, throw 1) {}
+}
+''');
+  }
+
+  Future<void> test_forParts_updaters_throw_multiple_comma() async {
+    await resolveTestCode('''
+void f() {
+  for (;; 0, throw 1, 2, 3,) {}
+}
+''');
+    await assertHasFix('''
+void f() {
+  for (;; 0, throw 1,) {}
+}
+''');
+  }
+
   Future<void> test_statements_one() async {
     await resolveTestCode('''
 int f() {