[analysis_server] Validate server includes all used commands in ServerCapabilities
Change-Id: I03855b7528d8199ceb140b0f0c59dd21c025dc90
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/309260
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index 1516405..24536d6 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -61,6 +61,7 @@
fixAll,
sendWorkspaceEdit,
performRefactor,
+ validateRefactor,
logAction,
// Add commands for each of the new refactorings.
...RefactoringProcessor.generators.keys,
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/dart.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/dart.dart
index f73911e..a54d1bc5 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/dart.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/dart.dart
@@ -56,21 +56,26 @@
CodeActionKind actionKind,
String title,
String command,
- ) =>
- _commandOrCodeAction(
- actionKind,
- Command(
- title: title,
- command: command,
- arguments: [
- {
- 'path': path,
- if (triggerKind == CodeActionTriggerKind.Automatic)
- 'autoTriggered': true,
- }
- ],
- ),
- );
+ ) {
+ assert(
+ (() => Commands.serverSupportedCommands.contains(command))(),
+ 'serverSupportedCommands did not contain $command',
+ );
+ return _commandOrCodeAction(
+ actionKind,
+ Command(
+ title: title,
+ command: command,
+ arguments: [
+ {
+ 'path': path,
+ if (triggerKind == CodeActionTriggerKind.Automatic)
+ 'autoTriggered': true,
+ }
+ ],
+ ),
+ );
+ }
/// Helper to create refactors that execute commands provided with
/// the current file, location and document version.
@@ -79,24 +84,31 @@
String name,
RefactoringKind refactorKind, [
Map<String, dynamic>? options,
- ]) =>
- _commandOrCodeAction(
- actionKind,
- Command(
- title: name,
- command: Commands.performRefactor,
- arguments: [
- // TODO(dantup): Change this to a single entry that is a Map once
- // enough time has passed that old versions of Dart-Code prior to
- // to June 2022 need not be supported against newer SDKs.
- refactorKind.toJson(),
- path,
- docIdentifier.version,
- offset,
- length,
- options,
- ],
- ));
+ ]) {
+ final command = Commands.performRefactor;
+ assert(
+ (() => Commands.serverSupportedCommands.contains(command))(),
+ 'serverSupportedCommands did not contain $command',
+ );
+
+ return _commandOrCodeAction(
+ actionKind,
+ Command(
+ title: name,
+ command: command,
+ arguments: [
+ // TODO(dantup): Change this to a single entry that is a Map once
+ // enough time has passed that old versions of Dart-Code prior to
+ // to June 2022 need not be supported against newer SDKs.
+ refactorKind.toJson(),
+ path,
+ docIdentifier.version,
+ offset,
+ length,
+ options,
+ ],
+ ));
+ }
@override
Future<List<CodeActionWithPriority>> getAssistActions() async {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/framework/refactoring_processor.dart b/pkg/analysis_server/lib/src/services/refactoring/framework/refactoring_processor.dart
index 1c8ee12..0fe8680 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/framework/refactoring_processor.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/framework/refactoring_processor.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/src/lsp/constants.dart';
import 'package:analysis_server/src/services/refactoring/convert_formal_parameters.dart';
import 'package:analysis_server/src/services/refactoring/framework/refactoring_context.dart';
import 'package:analysis_server/src/services/refactoring/framework/refactoring_producer.dart';
@@ -54,12 +55,18 @@
'that are not supported by the client',
);
+ final command = entry.key;
+ assert(
+ (() => Commands.serverSupportedCommands.contains(command))(),
+ 'serverSupportedCommands did not contain $command',
+ );
+
refactorings.add(
CodeAction(
title: producer.title,
kind: producer.kind,
command: Command(
- command: entry.key,
+ command: command,
title: producer.title,
arguments: [
{
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index 7927660..2bfda56 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -726,6 +726,12 @@
/// null if an initialization request has not yet been sent.
ClientCapabilities? _clientCapabilities;
+ /// The capabilities returned from the server during initialization.
+ ///
+ /// `null` if the server is not initialized, or returned an error during
+ /// initialize.
+ ServerCapabilities? _serverCapabilities;
+
final validProgressTokens = <ProgressToken>{};
/// Whether to include 'clientRequestTime' fields in outgoing messages.
@@ -986,6 +992,12 @@
T Function(Map<String, Object?>)? decoder,
ProgressToken? workDoneToken,
}) async {
+ final supportedCommands =
+ _serverCapabilities?.executeCommandProvider?.commands ?? [];
+ if (!supportedCommands.contains(command.command)) {
+ throw ArgumentError('Server does not support ${command.command}. '
+ 'Is it missing from serverSupportedCommands?');
+ }
final request = makeRequest(
Method.workspace_executeCommand,
ExecuteCommandParams(
@@ -1610,6 +1622,10 @@
final error = response.error;
if (error == null) {
+ final result =
+ InitializeResult.fromJson(response.result as Map<String, Object?>);
+ _serverCapabilities = result.capabilities;
+
final notification =
makeNotification(Method.initialized, InitializedParams());
await sendNotificationToServer(notification);