[bulk fix] report undefined diagnostics

Change-Id: I4abe1e83c56e632f91a81510ec0a35b521cd11d7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/255541
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Phil Quitslund <pquitslund@google.com>
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 7e52568..90b8c0e 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -110,7 +110,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  1.33.2
+  1.33.3
 </h1>
 <p>
   This document contains a specification of the API provided by the
@@ -5653,6 +5653,11 @@
           An "edit.sortMembers" request specified a Dart file that has
           scan or parse errors.
         </p>
+      </dd><dt class="value">UNDEFINED_DIAGNOSTIC_CODE</dt><dd>
+        
+        <p>
+          A request specified a diagnostic code that is undefined.
+        </p>
       </dd><dt class="value">UNKNOWN_REQUEST</dt><dd>
         
         <p>
diff --git a/pkg/analysis_server/lib/protocol/protocol.dart b/pkg/analysis_server/lib/protocol/protocol.dart
index 27ea015..ed74f17 100644
--- a/pkg/analysis_server/lib/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/protocol/protocol.dart
@@ -504,6 +504,13 @@
             error: RequestError(RequestErrorCode.SORT_MEMBERS_PARSE_ERRORS,
                 'Error during `edit.sortMembers`: file has $numErrors scan/parse errors.'));
 
+  /// Initialize a newly created instance to represent the
+  /// UNDEFINED_DIAGNOSTIC_CODE error condition.
+  Response.undefinedDiagnostic(Request request, String code)
+      : this(request.id,
+            error: RequestError(RequestErrorCode.UNDEFINED_DIAGNOSTIC_CODE,
+                "The diagnostic '$code' is undefined."));
+
   /// Initialize a newly created instance to represent an error condition caused
   /// by a [request] that cannot be handled by any known handlers.
   Response.unknownRequest(Request request)
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index 086d0c8..eb4c2a3 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -8,7 +8,7 @@
 
 // ignore_for_file: constant_identifier_names
 
-const String PROTOCOL_VERSION = '1.33.2';
+const String PROTOCOL_VERSION = '1.33.3';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index 6748c45..3162e0d 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -13871,6 +13871,7 @@
 ///   SERVER_ERROR
 ///   SORT_MEMBERS_INVALID_FILE
 ///   SORT_MEMBERS_PARSE_ERRORS
+///   UNDEFINED_DIAGNOSTIC_CODE
 ///   UNKNOWN_REQUEST
 ///   UNSUPPORTED_FEATURE
 /// }
@@ -14037,6 +14038,10 @@
   static const RequestErrorCode SORT_MEMBERS_PARSE_ERRORS =
       RequestErrorCode._('SORT_MEMBERS_PARSE_ERRORS');
 
+  /// A request specified a diagnostic code that is undefined.
+  static const RequestErrorCode UNDEFINED_DIAGNOSTIC_CODE =
+      RequestErrorCode._('UNDEFINED_DIAGNOSTIC_CODE');
+
   /// A request was received which the analysis server does not recognize, or
   /// cannot handle in its current configuration.
   static const RequestErrorCode UNKNOWN_REQUEST =
@@ -14084,6 +14089,7 @@
     SERVER_ERROR,
     SORT_MEMBERS_INVALID_FILE,
     SORT_MEMBERS_PARSE_ERRORS,
+    UNDEFINED_DIAGNOSTIC_CODE,
     UNKNOWN_REQUEST,
     UNSUPPORTED_FEATURE
   ];
@@ -14159,6 +14165,8 @@
         return SORT_MEMBERS_INVALID_FILE;
       case 'SORT_MEMBERS_PARSE_ERRORS':
         return SORT_MEMBERS_PARSE_ERRORS;
+      case 'UNDEFINED_DIAGNOSTIC_CODE':
+        return UNDEFINED_DIAGNOSTIC_CODE;
       case 'UNKNOWN_REQUEST':
         return UNKNOWN_REQUEST;
       case 'UNSUPPORTED_FEATURE':
diff --git a/pkg/analysis_server/lib/src/handler/legacy/edit_bulk_fixes.dart b/pkg/analysis_server/lib/src/handler/legacy/edit_bulk_fixes.dart
index 5246a7f..9d34fe2 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/edit_bulk_fixes.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/edit_bulk_fixes.dart
@@ -4,15 +4,24 @@
 
 import 'dart:async';
 
+import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
 import 'package:analysis_server/src/services/correction/bulk_fix_processor.dart';
 import 'package:analysis_server/src/services/correction/change_workspace.dart';
+import 'package:analyzer/error/error.dart';
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/src/lint/registry.dart';
 
 /// The handler for the `edit.bulkFixes` request.
 class EditBulkFixes extends LegacyHandler {
+  static final Set<String> _errorCodes =
+      errorCodeValues.map((ErrorCode code) => code.name.toLowerCase()).toSet();
+
+  static final Set<String> _lintCodes =
+      Registry.ruleRegistry.rules.map((rule) => rule.name).toSet();
+
   /// Initialize a newly created handler to be able to service requests for the
   /// [server].
   EditBulkFixes(super.server, super.request, super.cancellationToken);
@@ -30,6 +39,16 @@
         }
       }
 
+      var codes = params.codes?.map((e) => e.toLowerCase()).toList();
+      if (codes != null) {
+        for (var code in codes) {
+          if (!_errorCodes.contains(code) && !_lintCodes.contains(code)) {
+            server.sendResponse(Response.undefinedDiagnostic(request, code));
+            return;
+          }
+        }
+      }
+
       var collection = AnalysisContextCollectionImpl(
         includedPaths: params.included,
         resourceProvider: server.resourceProvider,
@@ -38,7 +57,7 @@
       var workspace = DartChangeWorkspace(
           collection.contexts.map((c) => c.currentSession).toList());
       var processor = BulkFixProcessor(server.instrumentationService, workspace,
-          useConfigFiles: params.inTestMode ?? false, codes: params.codes);
+          useConfigFiles: params.inTestMode ?? false, codes: codes);
 
       var changeBuilder = await processor.fixErrors(collection.contexts);
 
diff --git a/pkg/analysis_server/test/edit/bulk_fixes_test.dart b/pkg/analysis_server/test/edit/bulk_fixes_test.dart
index ef67835..aefa5fc 100644
--- a/pkg/analysis_server/test/edit/bulk_fixes_test.dart
+++ b/pkg/analysis_server/test/edit/bulk_fixes_test.dart
@@ -2,6 +2,7 @@
 // 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/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/services/linter/lint_names.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -140,6 +141,16 @@
     expect(fix.code, 'unnecessary_new');
     expect(fix.occurrences, 2);
   }
+
+  Future<void> test_undefinedDiagnostic() async {
+    addDiagnosticCode('foo_bar');
+    addTestFile('''
+''');
+
+    var request = _getRequest();
+    var response = await handleRequest(request);
+    expect(response.error?.message, "The diagnostic 'foo_bar' is undefined.");
+  }
 }
 
 @reflectiveTest
@@ -395,9 +406,11 @@
   }
 
   Future<EditBulkFixesResult> _getBulkFixes() async {
-    var request =
-        EditBulkFixesParams([workspaceRoot.path], codes: codes).toRequest('0');
+    var request = _getRequest();
     var response = await handleSuccessfulRequest(request);
     return EditBulkFixesResult.fromResponse(response);
   }
+
+  Request _getRequest() =>
+      EditBulkFixesParams([workspaceRoot.path], codes: codes).toRequest('0');
 }
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index c8b6c26..5ed04d7 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -1447,6 +1447,7 @@
 ///   SERVER_ERROR
 ///   SORT_MEMBERS_INVALID_FILE
 ///   SORT_MEMBERS_PARSE_ERRORS
+///   UNDEFINED_DIAGNOSTIC_CODE
 ///   UNKNOWN_REQUEST
 ///   UNSUPPORTED_FEATURE
 /// }
@@ -1483,6 +1484,7 @@
   'SERVER_ERROR',
   'SORT_MEMBERS_INVALID_FILE',
   'SORT_MEMBERS_PARSE_ERRORS',
+  'UNDEFINED_DIAGNOSTIC_CODE',
   'UNKNOWN_REQUEST',
   'UNSUPPORTED_FEATURE'
 ]);
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index 66c6210..41ad28d 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -198,6 +198,11 @@
   public static final String SORT_MEMBERS_PARSE_ERRORS = "SORT_MEMBERS_PARSE_ERRORS";
 
   /**
+   * A request specified a diagnostic code that is undefined.
+   */
+  public static final String UNDEFINED_DIAGNOSTIC_CODE = "UNDEFINED_DIAGNOSTIC_CODE";
+
+  /**
    * A request was received which the analysis server does not recognize, or cannot handle in its
    * current configuration.
    */
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 3bb1feb..c58450e 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -7,7 +7,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  <version>1.33.2</version>
+  <version>1.33.3</version>
 </h1>
 <p>
   This document contains a specification of the API provided by the
@@ -5342,6 +5342,12 @@
         </p>
       </value>
       <value>
+        <code>UNDEFINED_DIAGNOSTIC_CODE</code>
+        <p>
+          A request specified a diagnostic code that is undefined.
+        </p>
+      </value>
+      <value>
         <code>UNKNOWN_REQUEST</code>
         <p>
           A request was received which the analysis server does
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index 086d0c8..eb4c2a3 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -8,7 +8,7 @@
 
 // ignore_for_file: constant_identifier_names
 
-const String PROTOCOL_VERSION = '1.33.2';
+const String PROTOCOL_VERSION = '1.33.3';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
index 94a247f..61e139a 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
@@ -13871,6 +13871,7 @@
 ///   SERVER_ERROR
 ///   SORT_MEMBERS_INVALID_FILE
 ///   SORT_MEMBERS_PARSE_ERRORS
+///   UNDEFINED_DIAGNOSTIC_CODE
 ///   UNKNOWN_REQUEST
 ///   UNSUPPORTED_FEATURE
 /// }
@@ -14037,6 +14038,10 @@
   static const RequestErrorCode SORT_MEMBERS_PARSE_ERRORS =
       RequestErrorCode._('SORT_MEMBERS_PARSE_ERRORS');
 
+  /// A request specified a diagnostic code that is undefined.
+  static const RequestErrorCode UNDEFINED_DIAGNOSTIC_CODE =
+      RequestErrorCode._('UNDEFINED_DIAGNOSTIC_CODE');
+
   /// A request was received which the analysis server does not recognize, or
   /// cannot handle in its current configuration.
   static const RequestErrorCode UNKNOWN_REQUEST =
@@ -14084,6 +14089,7 @@
     SERVER_ERROR,
     SORT_MEMBERS_INVALID_FILE,
     SORT_MEMBERS_PARSE_ERRORS,
+    UNDEFINED_DIAGNOSTIC_CODE,
     UNKNOWN_REQUEST,
     UNSUPPORTED_FEATURE
   ];
@@ -14159,6 +14165,8 @@
         return SORT_MEMBERS_INVALID_FILE;
       case 'SORT_MEMBERS_PARSE_ERRORS':
         return SORT_MEMBERS_PARSE_ERRORS;
+      case 'UNDEFINED_DIAGNOSTIC_CODE':
+        return UNDEFINED_DIAGNOSTIC_CODE;
       case 'UNKNOWN_REQUEST':
         return UNKNOWN_REQUEST;
       case 'UNSUPPORTED_FEATURE':