From 9831fc4e9842c377f6f7747663da3bde3e76db5d Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Tue, 29 Apr 2025 20:54:58 -0700 Subject: [PATCH] [analysis_server] Rename "CodeAction" to CodeActionLiteral" The term "CodeAction" is a bit overloaded. It could mean both an individual result from the `textDocument/codeAction` request (which is a `Command` or a `CodeAction`), or the `CodeAction` type defined in the spec (which the spec refers to as a "Code Action literal"). To reduce confusion where we have similar APIs that operate on "Code Actions" (CodeAction|Command), this renames the `CodeAction` class to `CodeActionLiteral` and we will use the term `CodeAction` to mean either of those types. To make things simpler to review, this change _only_ renames the class, and also swaps the order of the types in some places that used `Either2` (which is opposite to the spec and some other code). Some further clean up will be done in a separate change. Change-Id: Idcd8265f9229c3450004e68334e98a7b530330a4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425300 Reviewed-by: Samuel Rawlins Commit-Queue: Brian Wilkerson Reviewed-by: Brian Wilkerson --- .../abstract_code_actions_producer.dart | 18 +- .../code_actions/analysis_options.dart | 7 +- .../src/lsp/handlers/code_actions/dart.dart | 26 +- .../lsp/handlers/code_actions/plugins.dart | 7 +- .../lsp/handlers/code_actions/pubspec.dart | 7 +- .../lsp/handlers/handler_code_actions.dart | 17 +- .../framework/refactoring_processor.dart | 6 +- .../test/lsp/code_actions_abstract.dart | 24 +- .../test/lsp/code_actions_fixes_test.dart | 2 +- .../test/lsp/code_actions_refactor_test.dart | 2 +- .../test/lsp/code_actions_source_test.dart | 6 +- .../test/lsp/request_helpers_mixin.dart | 6 +- .../test/lsp/server_abstract.dart | 6 +- .../move_top_level_to_file_test.dart | 2 +- .../refactoring/refactoring_test_support.dart | 16 +- .../tool/lsp_spec/generate_all.dart | 6 +- .../tool/lsp_spec/meta_model_cleaner.dart | 11 +- .../lib/protocol_custom_generated.dart | 2 +- .../lib/protocol_generated.dart | 417 +++++++++--------- 19 files changed, 302 insertions(+), 286 deletions(-) diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart index c257af759c5..a43fd7e1591 100644 --- a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart +++ b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart @@ -20,12 +20,12 @@ import 'package:analyzer/src/dart/analysis/results.dart' as engine; import 'package:analyzer/src/util/performance/operation_performance.dart'; import 'package:meta/meta.dart'; -typedef CodeActionWithPriority = ({CodeAction action, int priority}); +typedef CodeActionWithPriority = ({CodeActionLiteral action, int priority}); typedef CodeActionWithPriorityAndIndex = - ({CodeAction action, int priority, int index}); + ({CodeActionLiteral action, int priority, int index}); -/// A base for classes that produce [CodeAction]s for the LSP handler. +/// A base for classes that produce [CodeActionLiteral]s for the LSP handler. abstract class AbstractCodeActionsProducer with RequestHandlerMixin { final File file; @@ -68,13 +68,13 @@ abstract class AbstractCodeActionsProducer /// immediately after computing edits to ensure the document is not modified /// before the version number is read. @protected - CodeAction createAssistAction( + CodeActionLiteral createAssistAction( protocol.SourceChange change, String? loggedAssistId, String path, LineInfo lineInfo, ) { - return CodeAction( + return CodeActionLiteral( title: change.message, kind: toCodeActionKind(change.id, CodeActionKind.Refactor), diagnostics: const [], @@ -111,14 +111,14 @@ abstract class AbstractCodeActionsProducer /// immediately after computing edits to ensure the document is not modified /// before the version number is read. @protected - CodeAction createFixAction( + CodeActionLiteral createFixAction( protocol.SourceChange change, String? loggedFixId, Diagnostic diagnostic, String path, LineInfo lineInfo, ) { - return CodeAction( + return CodeActionLiteral( title: change.message, kind: toCodeActionKind(change.id, CodeActionKind.QuickFix), diagnostics: [diagnostic], @@ -180,11 +180,11 @@ abstract class AbstractCodeActionsProducer OperationPerformance? performance, ); - Future>> getRefactorActions( + Future>> getRefactorActions( OperationPerformance? performance, ); - Future>> getSourceActions(); + Future>> getSourceActions(); /// Return the contents of the [file], or `null` if the file does not exist or /// cannot be read. diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/analysis_options.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/analysis_options.dart index 26bc88e222a..f0a6223a7e7 100644 --- a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/analysis_options.dart +++ b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/analysis_options.dart @@ -16,7 +16,7 @@ import 'package:analyzer/src/util/performance/operation_performance.dart'; import 'package:analyzer/src/workspace/pub.dart'; import 'package:yaml/yaml.dart'; -/// Produces [CodeAction]s from analysis options fixes. +/// Produces [CodeActionLiteral]s from analysis options fixes. class AnalysisOptionsCodeActionsProducer extends AbstractCodeActionsProducer { AnalysisOptionsCodeActionsProducer( super.server, @@ -111,12 +111,13 @@ class AnalysisOptionsCodeActionsProducer extends AbstractCodeActionsProducer { } @override - Future>> getRefactorActions( + Future>> getRefactorActions( OperationPerformance? performance, ) async => []; @override - Future>> getSourceActions() async => []; + Future>> getSourceActions() async => + []; YamlMap? _getOptions(SourceFactory sourceFactory, String content) { var optionsProvider = AnalysisOptionsProvider(sourceFactory); 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 186f980249a..c40c42ff6e3 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 @@ -30,7 +30,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/src/util/performance/operation_performance.dart'; import 'package:analyzer/utilities/extensions/ast.dart'; -/// Produces [CodeAction]s from Dart source commands, fixes, assists and +/// Produces [CodeActionLiteral]s from Dart source commands, fixes, assists and /// refactors from the server. class DartCodeActionsProducer extends AbstractCodeActionsProducer { ResolvedLibraryResult libraryResult; @@ -58,9 +58,9 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer { @override String get name => 'ServerDartActionsComputer'; - /// Helper to create a [CodeAction] or [Command] for the given arguments in + /// Helper to create a [CodeActionLiteral] or [Command] for the given arguments in /// the current file based on client capabilities. - Either2 createCommand( + Either2 createCommand( CodeActionKind actionKind, String title, String command, @@ -87,7 +87,7 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer { /// Helper to create refactors that execute commands provided with /// the current file, location and document version. - Either2 createRefactor( + Either2 createRefactor( CodeActionKind actionKind, String name, RefactoringKind refactorKind, [ @@ -263,7 +263,7 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer { } @override - Future>> getRefactorActions( + Future>> getRefactorActions( OperationPerformance? performance, ) async { // If the client does not support workspace/applyEdit, we won't be able to @@ -272,7 +272,7 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer { return const []; } - var refactorActions = >[]; + var refactorActions = >[]; var performanceTracker = RefactoringPerformance(); try { @@ -293,7 +293,9 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer { performance: performanceTracker, ); var actions = await processor.compute(); - refactorActions.addAll(actions.map(Either2.t1)); + refactorActions.addAll( + actions.map(Either2.t1), + ); // Extracts if (shouldIncludeKind(CodeActionKind.RefactorExtract)) { @@ -469,7 +471,7 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer { /// Gets "Source" CodeActions, which are actions that apply to whole files of /// source such as Sort Members and Organise Imports. @override - Future>> getSourceActions() async { + Future>> getSourceActions() async { // If the client does not support workspace/applyEdit, we won't be able to // run any of these. if (!supportsApplyEdit) { @@ -496,15 +498,15 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer { /// Wraps a command in a CodeAction if the client supports it so that a /// CodeActionKind can be supplied. - Either2 _commandOrCodeAction( + Either2 _commandOrCodeAction( CodeActionKind kind, Command command, ) { return supportsLiterals - ? Either2.t1( - CodeAction(title: command.title, kind: kind, command: command), + ? Either2.t1( + CodeActionLiteral(title: command.title, kind: kind, command: command), ) - : Either2.t2(command); + : Either2.t2(command); } } diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/plugins.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/plugins.dart index 4362f3e2b9c..f62e4a72707 100644 --- a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/plugins.dart +++ b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/plugins.dart @@ -14,7 +14,7 @@ import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin; import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin; import 'package:collection/collection.dart'; -/// Produces [CodeAction]s from Plugin fixes and assists. +/// Produces [CodeActionLiteral]s from Plugin fixes and assists. class PluginCodeActionsProducer extends AbstractCodeActionsProducer { final AnalysisDriver? driver; @@ -71,12 +71,13 @@ class PluginCodeActionsProducer extends AbstractCodeActionsProducer { } @override - Future>> getRefactorActions( + Future>> getRefactorActions( OperationPerformance? performance, ) async => []; @override - Future>> getSourceActions() async => []; + Future>> getSourceActions() async => + []; CodeActionWithPriority _convertAssist(plugin.PrioritizedSourceChange assist) { return ( diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/pubspec.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/pubspec.dart index d3e075aa541..0e31303768d 100644 --- a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/pubspec.dart +++ b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/pubspec.dart @@ -13,7 +13,7 @@ import 'package:analyzer/src/pubspec/pubspec_validator.dart'; import 'package:analyzer/src/util/performance/operation_performance.dart'; import 'package:yaml/yaml.dart'; -/// Produces [CodeAction]s from Pubspec fixes. +/// Produces [CodeActionLiteral]s from Pubspec fixes. class PubspecCodeActionsProducer extends AbstractCodeActionsProducer { PubspecCodeActionsProducer( super.server, @@ -97,10 +97,11 @@ class PubspecCodeActionsProducer extends AbstractCodeActionsProducer { } @override - Future>> getRefactorActions( + Future>> getRefactorActions( OperationPerformance? performance, ) async => []; @override - Future>> getSourceActions() async => []; + Future>> getSourceActions() async => + []; } diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart index 2e9d7c0699a..aa405d6258b 100644 --- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart +++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart @@ -219,7 +219,7 @@ class CodeActionHandler ]; var sorter = _CodeActionSorter(params.range, shouldIncludeKind); - var allActions = >[ + var allActions = >[ // Like-kinded actions are grouped (and prioritized) together // regardless of which producer they came from. @@ -306,7 +306,7 @@ class _CodeActionSorter { _CodeActionSorter(this.range, this.shouldIncludeKind); - List> sort( + List> sort( List actions, ) { var dedupedActions = _dedupeActions(actions, range.start); @@ -325,16 +325,15 @@ class _CodeActionSorter { return dedupedActionsWithIndex .where((action) => shouldIncludeKind(action.action.kind)) - .map((action) => Either2.t1(action.action)) + .map((action) => Either2.t1(action.action)) .toList(); } - /// Creates a comparer for [CodeAction]s that compares the column distance from + /// Creates a comparer for [CodeActionLiteral]s that compares the column distance from /// [pos]. - int Function(CodeAction a, CodeAction b) _codeActionColumnDistanceComparer( - Position pos, - ) { - Position posOf(CodeAction action) { + int Function(CodeActionLiteral a, CodeActionLiteral b) + _codeActionColumnDistanceComparer(Position pos) { + Position posOf(CodeActionLiteral action) { var diagnostics = action.diagnostics; return diagnostics != null && diagnostics.isNotEmpty ? diagnostics.first.range.start @@ -423,7 +422,7 @@ class _CodeActionSorter { // Build a new CodeAction that merges the diagnostics from each same // code action onto a single one. return ( - action: CodeAction( + action: CodeActionLiteral( title: first.title, kind: first.kind, // Merge diagnostics from all of the matching CodeActions. 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 4e904bcdaf4..8404441cb0d 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 @@ -40,9 +40,9 @@ class RefactoringProcessor { /// Return a list containing one code action for each of the refactorings that /// are available in the current context. - Future> compute() async { + Future> compute() async { _timer.start(); - var refactorings = []; + var refactorings = []; for (var entry in RefactoringProcessor.generators.entries) { var generator = entry.value; var producer = generator(context); @@ -83,7 +83,7 @@ class RefactoringProcessor { ); refactorings.add( - CodeAction( + CodeActionLiteral( title: producer.title, kind: producer.kind, command: Command( diff --git a/pkg/analysis_server/test/lsp/code_actions_abstract.dart b/pkg/analysis_server/test/lsp/code_actions_abstract.dart index 0ae89238f09..4a9e85cb613 100644 --- a/pkg/analysis_server/test/lsp/code_actions_abstract.dart +++ b/pkg/analysis_server/test/lsp/code_actions_abstract.dart @@ -15,8 +15,8 @@ import 'server_abstract.dart'; abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest { /// Initializes the server with some basic configuration and expects to find - /// a [CodeAction] with [kind]/[command]/[title]. - Future expectAction( + /// a [CodeActionLiteral] with [kind]/[command]/[title]. + Future expectAction( String content, { CodeActionKind? kind, String? command, @@ -69,7 +69,7 @@ abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest { } /// Initializes the server with some basic configuration and expects not to - /// find a [CodeAction] with [kind]/[command]/[title]. + /// find a [CodeActionLiteral] with [kind]/[command]/[title]. Future expectNoAction( String content, { String? filePath, @@ -106,8 +106,8 @@ abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest { /// a matching command/args. /// /// Throws if zero or more than one actions match. - CodeAction? findAction( - List> actions, { + CodeActionLiteral? findAction( + List> actions, { String? title, CodeActionKind? kind, String? command, @@ -122,15 +122,15 @@ abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest { ).singleOrNull; } - List findActions( - List> actions, { + List findActions( + List> actions, { String? title, CodeActionKind? kind, String? command, List? commandArgs, }) { return actions - .map((action) => action.map((cmd) => null, (action) => action)) + .map((action) => action.map((action) => action, (cmd) => null)) .where((action) => title == null || action?.title == title) .where((action) => kind == null || action?.kind == kind) // Some tests filter by only supplying a command, so if there is no @@ -165,15 +165,15 @@ abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest { .toList(); } - Either2? findCommand( - List> actions, + Either2? findCommand( + List> actions, String commandID, [ String? wantedTitle, ]) { for (var codeAction in actions) { var id = codeAction.map( - (cmd) => cmd.command, (action) => action.command?.command, + (cmd) => cmd.command, ); var title = codeAction.map((cmd) => cmd.title, (action) => action.title); if (id == commandID && (wantedTitle == null || wantedTitle == title)) { @@ -199,7 +199,7 @@ abstract class AbstractCodeActionsTest extends AbstractLspAnalysisServerTest { } /// Initializes the server with some basic configuration and expects to find - /// a [CodeAction] with [kind]/[title] that applies edits resulting in + /// a [CodeActionLiteral] with [kind]/[title] that applies edits resulting in /// [expected]. Future verifyActionEdits( String content, diff --git a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart index 02e383aeb06..d615bd68875 100644 --- a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart +++ b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart @@ -450,7 +450,7 @@ void main() { var codeActions = await getCodeActions(mainFileUri, range: range); var codeActionKinds = codeActions.map( (item) => - item.map((command) => null, (action) => action.kind?.toString()), + item.map((action) => action.kind?.toString(), (command) => null), ); expect( diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart index 3e97cef4c8f..0cb88d84890 100644 --- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart +++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart @@ -261,8 +261,8 @@ void f() { var results = await ofKind(kind); for (var result in results) { var resultKind = result.map( - (cmd) => throw 'Expected CodeAction, got Command: ${cmd.title}', (action) => action.kind, + (cmd) => throw 'Expected CodeAction, got Command: ${cmd.title}', ); expect('$resultKind', anyOf([equals('$kind'), startsWith('$kind.')])); } diff --git a/pkg/analysis_server/test/lsp/code_actions_source_test.dart b/pkg/analysis_server/test/lsp/code_actions_source_test.dart index 7a7000a1c58..923f0b02ae0 100644 --- a/pkg/analysis_server/test/lsp/code_actions_source_test.dart +++ b/pkg/analysis_server/test/lsp/code_actions_source_test.dart @@ -26,7 +26,7 @@ abstract class AbstractSourceCodeActionsTest extends AbstractCodeActionsTest { /// one must be provided), uses [startOfDocPos] to avoid every test needing /// to include a '^' marker. @override - Future>> getCodeActions( + Future>> getCodeActions( Uri fileUri, { Range? range, Position? position, @@ -385,8 +385,8 @@ int minified(int x, int y) => min(x, y); var actions = await getCodeActions(mainFileUri); var action = findCommand(actions, Commands.organizeImports)!; action.map( - (command) {}, (codeActionLiteral) => throw 'Expected command, got codeActionLiteral', + (command) {}, ); } @@ -524,8 +524,8 @@ String b; var actions = await getCodeActions(mainFileUri); var action = findCommand(actions, Commands.sortMembers)!; action.map( - (command) {}, (codeActionLiteral) => throw 'Expected command, got codeActionLiteral', + (command) {}, ); } diff --git a/pkg/analysis_server/test/lsp/request_helpers_mixin.dart b/pkg/analysis_server/test/lsp/request_helpers_mixin.dart index e571bb69acc..69cc921a729 100644 --- a/pkg/analysis_server/test/lsp/request_helpers_mixin.dart +++ b/pkg/analysis_server/test/lsp/request_helpers_mixin.dart @@ -320,7 +320,7 @@ mixin LspRequestHelpersMixin { return expectSuccessfulResponseTo(request, Location.fromJson); } - Future>> getCodeActions( + Future>> getCodeActions( Uri fileUri, { Range? range, Position? position, @@ -352,10 +352,10 @@ mixin LspRequestHelpersMixin { request, _fromJsonList( _generateFromJsonFor( + CodeActionLiteral.canParse, + CodeActionLiteral.fromJson, Command.canParse, Command.fromJson, - CodeAction.canParse, - CodeAction.fromJson, ), ), ); diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart index 4004b4c87e1..1cbef540bdd 100644 --- a/pkg/analysis_server/test/lsp/server_abstract.dart +++ b/pkg/analysis_server/test/lsp/server_abstract.dart @@ -1038,10 +1038,12 @@ mixin LspAnalysisServerTestMixin on LspRequestHelpersMixin, LspEditHelpersMixin await sendNotificationToServer(notification); } - Future executeCodeAction(Either2 codeAction) { + Future executeCodeAction( + Either2 codeAction, + ) { var command = codeAction.map( - (command) => command, (codeAction) => codeAction.command!, + (command) => command, ); return executeCommand(command); } diff --git a/pkg/analysis_server/test/src/services/refactoring/move_top_level_to_file_test.dart b/pkg/analysis_server/test/src/services/refactoring/move_top_level_to_file_test.dart index 36aa4143c56..52e2ca83c81 100644 --- a/pkg/analysis_server/test/src/services/refactoring/move_top_level_to_file_test.dart +++ b/pkg/analysis_server/test/src/services/refactoring/move_top_level_to_file_test.dart @@ -32,7 +32,7 @@ class ^A {} String get refactoringName => MoveTopLevelToFile.commandName; /// Replaces the "Save URI" argument in [action]. - void replaceSaveUriArgument(CodeAction action, Uri newFileUri) { + void replaceSaveUriArgument(CodeActionLiteral action, Uri newFileUri) { var arguments = getRefactorCommandArguments(action); // The filename is the first item we prompt for so is first in the // arguments. diff --git a/pkg/analysis_server/test/src/services/refactoring/refactoring_test_support.dart b/pkg/analysis_server/test/src/services/refactoring/refactoring_test_support.dart index 9ab8506e954..c1ab1e03ec7 100644 --- a/pkg/analysis_server/test/src/services/refactoring/refactoring_test_support.dart +++ b/pkg/analysis_server/test/src/services/refactoring/refactoring_test_support.dart @@ -44,27 +44,27 @@ abstract class RefactoringTest extends AbstractCodeActionsTest { } /// Executes the refactor in [action]. - Future executeRefactor(CodeAction action) async { + Future executeRefactor(CodeActionLiteral action) async { await executeCommandForEdits(action.command!); } - /// Expects to find a refactor [CodeAction] in [mainFileUri] at the offset of + /// Expects to find a refactor [CodeActionLiteral] in [mainFileUri] at the offset of /// the marker with the title [title]. - Future expectCodeAction(String title) async { + Future expectCodeAction(String title) async { var action = await getCodeAction(title); expect(action, isNotNull, reason: "Action '$title' should be included"); return action!; } - /// Expects to not find a refactor [CodeAction] in [mainFileUri] at the offset + /// Expects to not find a refactor [CodeActionLiteral] in [mainFileUri] at the offset /// of the marker with the title [title]. Future expectNoCodeAction(String? title) async { expect(await getCodeAction(title), isNull); } - /// Attempts to find a refactor [CodeAction] in [mainFileUri] at the offset of + /// Attempts to find a refactor [CodeActionLiteral] in [mainFileUri] at the offset of /// the marker with the title [title]. - Future getCodeAction(String? title) async { + Future getCodeAction(String? title) async { var codeActions = await getCodeActions( mainFileUri, position: _position, @@ -73,15 +73,15 @@ abstract class RefactoringTest extends AbstractCodeActionsTest { ); var commandOrCodeAction = findCommand(codeActions, refactoringName, title); var codeAction = commandOrCodeAction?.map( - (command) => throw 'Expected CodeAction, got Command', (codeAction) => codeAction, + (command) => throw 'Expected CodeAction, got Command', ); return codeAction; } /// Unwraps the 'arguments' field from the arguments object (which is the /// single argument for the command). - List getRefactorCommandArguments(CodeAction action) { + List getRefactorCommandArguments(CodeActionLiteral action) { var commandArguments = action.command!.arguments as List; // Our refactor command uses a single object in its arguments so we can have diff --git a/pkg/analysis_server/tool/lsp_spec/generate_all.dart b/pkg/analysis_server/tool/lsp_spec/generate_all.dart index de8c249fb2a..bd05f049cef 100644 --- a/pkg/analysis_server/tool/lsp_spec/generate_all.dart +++ b/pkg/analysis_server/tool/lsp_spec/generate_all.dart @@ -566,9 +566,9 @@ List getCustomClasses() { 'Information about one of the arguments needed by the command.' '\n\n' 'A list of parameters is sent in the `data` field of the ' - '`CodeAction` returned by the server. The values of the parameters ' - 'should appear in the `args` field of the `Command` sent to the ' - 'server in the same order as the corresponding parameters.', + '`CodeActionLiteral` returned by the server. The values of the ' + 'parameters should appear in the `args` field of the `Command` sent ' + 'to the server in the same order as the corresponding parameters.', ), interface( 'SaveUriCommandParameter', diff --git a/pkg/analysis_server/tool/lsp_spec/meta_model_cleaner.dart b/pkg/analysis_server/tool/lsp_spec/meta_model_cleaner.dart index bf0caddbd41..cf113b8482a 100644 --- a/pkg/analysis_server/tool/lsp_spec/meta_model_cleaner.dart +++ b/pkg/analysis_server/tool/lsp_spec/meta_model_cleaner.dart @@ -433,7 +433,16 @@ class LspMetaModelCleaner { 'SignatureInformationParameterInformation', 'Pattern': 'LspPattern', 'URI': 'LSPUri', - + // The term "CodeAction" is a bit overloaded. It could mean both an + // individual result from the textDocument/codeAction request (which is a + // `Command` or a `CodeAction`), or the `CodeAction` type defined in + // the spec (which the spec also refers to as a "Code Action literal"). + // + // To reduce confusion where we have similar APIs that operate on + // "Code Actions" (CodeAction|Command), we rename `CodeAction` to + // `CodeActionLiteral` and use the term `CodeAction` to mean either of + // those types. + 'CodeAction': 'CodeActionLiteral', // In LSP 3.18, many types that were previously inline and got generated // names have been extracted to their own definitions with hand-written // names. diff --git a/third_party/pkg/language_server_protocol/lib/protocol_custom_generated.dart b/third_party/pkg/language_server_protocol/lib/protocol_custom_generated.dart index 94c6d6981c4..656b67b7793 100644 --- a/third_party/pkg/language_server_protocol/lib/protocol_custom_generated.dart +++ b/third_party/pkg/language_server_protocol/lib/protocol_custom_generated.dart @@ -849,7 +849,7 @@ class ClosingLabel implements ToJsonable { /// Information about one of the arguments needed by the command. /// -/// A list of parameters is sent in the `data` field of the `CodeAction` +/// A list of parameters is sent in the `data` field of the `CodeActionLiteral` /// returned by the server. The values of the parameters should appear in the /// `args` field of the `Command` sent to the server in the same order as the /// corresponding parameters. diff --git a/third_party/pkg/language_server_protocol/lib/protocol_generated.dart b/third_party/pkg/language_server_protocol/lib/protocol_generated.dart index 9be3454867d..71263d06291 100644 --- a/third_party/pkg/language_server_protocol/lib/protocol_generated.dart +++ b/third_party/pkg/language_server_protocol/lib/protocol_generated.dart @@ -7441,7 +7441,8 @@ typedef ProgressToken = Either2; /// Result for a request to provide commands for the given text document and /// range. -typedef TextDocumentCodeActionResult = List>?; +typedef TextDocumentCodeActionResult + = List>?; /// Result for a request to provide code lens for the given text document. typedef TextDocumentCodeLensResult = List?; @@ -9428,213 +9429,6 @@ class ClientSemanticTokensRequestOptions implements ToJsonable { } } -/// A code action represents a change that can be performed in code, e.g. to fix -/// a problem or to refactor code. -/// -/// A CodeAction must set either `edit` and/or a `command`. If both are -/// supplied, the `edit` is applied first, then the `command` is executed. -class CodeAction implements ToJsonable { - static const jsonHandler = LspJsonHandler( - CodeAction.canParse, - CodeAction.fromJson, - ); - - /// A command this code action executes. If a code action provides an edit and - /// a command, first the edit is executed and then the command. - final Command? command; - - /// A data entry field that is preserved on a code action between a - /// `textDocument/codeAction` and a `codeAction/resolve` request. - /// - /// @since 3.16.0 - final LSPAny data; - - /// The diagnostics that this code action resolves. - final List? diagnostics; - - /// Marks that the code action cannot currently be applied. - /// - /// Clients should follow the following guidelines regarding disabled code - /// actions: - /// - /// - Disabled code actions are not shown in automatic - /// [lightbulbs](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) - /// code action menus. - /// - /// - Disabled actions are shown as faded out in the code action menu when - /// the user requests a more specific type - /// of code action, such as refactorings. - /// - /// - If the user has a - /// [keybinding](https://code.visualstudio.com/docs/editor/refactoring#_keybindings-for-code-actions) - /// that auto applies a code action and only disabled code actions are - /// returned, the client should show the user an - /// error message with `reason` in the editor. - /// - /// @since 3.16.0 - final CodeActionDisabled? disabled; - - /// The workspace edit this code action performs. - final WorkspaceEdit? edit; - - /// Marks this as a preferred action. Preferred actions are used by the `auto - /// fix` command and can be targeted by keybindings. - /// - /// A quick fix should be marked preferred if it properly addresses the - /// underlying error. A refactoring should be marked preferred if it is the - /// most reasonable choice of actions to take. - /// - /// @since 3.15.0 - final bool? isPreferred; - - /// The kind of the code action. - /// - /// Used to filter code actions. - final CodeActionKind? kind; - - /// A short, human-readable, title for this code action. - final String title; - CodeAction({ - this.command, - this.data, - this.diagnostics, - this.disabled, - this.edit, - this.isPreferred, - this.kind, - required this.title, - }); - @override - int get hashCode => Object.hash( - command, - data, - lspHashCode(diagnostics), - disabled, - edit, - isPreferred, - kind, - title, - ); - - @override - bool operator ==(Object other) { - return other is CodeAction && - other.runtimeType == CodeAction && - command == other.command && - data == other.data && - const DeepCollectionEquality().equals(diagnostics, other.diagnostics) && - disabled == other.disabled && - edit == other.edit && - isPreferred == other.isPreferred && - kind == other.kind && - title == other.title; - } - - @override - Map toJson() { - var result = {}; - if (command != null) { - result['command'] = command?.toJson(); - } - if (data != null) { - result['data'] = data; - } - if (diagnostics != null) { - result['diagnostics'] = - diagnostics?.map((item) => item.toJson()).toList(); - } - if (disabled != null) { - result['disabled'] = disabled?.toJson(); - } - if (edit != null) { - result['edit'] = edit?.toJson(); - } - if (isPreferred != null) { - result['isPreferred'] = isPreferred; - } - if (kind != null) { - result['kind'] = kind?.toJson(); - } - result['title'] = title; - return result; - } - - @override - String toString() => jsonEncoder.convert(toJson()); - - static bool canParse(Object? obj, LspJsonReporter reporter) { - if (obj is Map) { - if (!_canParseCommand(obj, reporter, 'command', - allowsUndefined: true, allowsNull: false)) { - return false; - } - if (!_canParseListDiagnostic(obj, reporter, 'diagnostics', - allowsUndefined: true, allowsNull: false)) { - return false; - } - if (!_canParseCodeActionDisabled(obj, reporter, 'disabled', - allowsUndefined: true, allowsNull: false)) { - return false; - } - if (!_canParseWorkspaceEdit(obj, reporter, 'edit', - allowsUndefined: true, allowsNull: false)) { - return false; - } - if (!_canParseBool(obj, reporter, 'isPreferred', - allowsUndefined: true, allowsNull: false)) { - return false; - } - if (!_canParseCodeActionKind(obj, reporter, 'kind', - allowsUndefined: true, allowsNull: false)) { - return false; - } - return _canParseString(obj, reporter, 'title', - allowsUndefined: false, allowsNull: false); - } else { - reporter.reportError('must be of type CodeAction'); - return false; - } - } - - static CodeAction fromJson(Map json) { - final commandJson = json['command']; - final command = commandJson != null - ? Command.fromJson(commandJson as Map) - : null; - final dataJson = json['data']; - final data = dataJson; - final diagnosticsJson = json['diagnostics']; - final diagnostics = (diagnosticsJson as List?) - ?.map((item) => Diagnostic.fromJson(item as Map)) - .toList(); - final disabledJson = json['disabled']; - final disabled = disabledJson != null - ? CodeActionDisabled.fromJson(disabledJson as Map) - : null; - final editJson = json['edit']; - final edit = editJson != null - ? WorkspaceEdit.fromJson(editJson as Map) - : null; - final isPreferredJson = json['isPreferred']; - final isPreferred = isPreferredJson as bool?; - final kindJson = json['kind']; - final kind = - kindJson != null ? CodeActionKind.fromJson(kindJson as String) : null; - final titleJson = json['title']; - final title = titleJson as String; - return CodeAction( - command: command, - data: data, - diagnostics: diagnostics, - disabled: disabled, - edit: edit, - isPreferred: isPreferred, - kind: kind, - title: title, - ); - } -} - /// The Client Capabilities of a [CodeActionRequest]. class CodeActionClientCapabilities implements ToJsonable { static const jsonHandler = LspJsonHandler( @@ -10163,6 +9957,213 @@ class CodeActionKind implements ToJsonable { static bool canParse(Object? obj, LspJsonReporter reporter) => obj is String; } +/// A code action represents a change that can be performed in code, e.g. to fix +/// a problem or to refactor code. +/// +/// A CodeAction must set either `edit` and/or a `command`. If both are +/// supplied, the `edit` is applied first, then the `command` is executed. +class CodeActionLiteral implements ToJsonable { + static const jsonHandler = LspJsonHandler( + CodeActionLiteral.canParse, + CodeActionLiteral.fromJson, + ); + + /// A command this code action executes. If a code action provides an edit and + /// a command, first the edit is executed and then the command. + final Command? command; + + /// A data entry field that is preserved on a code action between a + /// `textDocument/codeAction` and a `codeAction/resolve` request. + /// + /// @since 3.16.0 + final LSPAny data; + + /// The diagnostics that this code action resolves. + final List? diagnostics; + + /// Marks that the code action cannot currently be applied. + /// + /// Clients should follow the following guidelines regarding disabled code + /// actions: + /// + /// - Disabled code actions are not shown in automatic + /// [lightbulbs](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) + /// code action menus. + /// + /// - Disabled actions are shown as faded out in the code action menu when + /// the user requests a more specific type + /// of code action, such as refactorings. + /// + /// - If the user has a + /// [keybinding](https://code.visualstudio.com/docs/editor/refactoring#_keybindings-for-code-actions) + /// that auto applies a code action and only disabled code actions are + /// returned, the client should show the user an + /// error message with `reason` in the editor. + /// + /// @since 3.16.0 + final CodeActionDisabled? disabled; + + /// The workspace edit this code action performs. + final WorkspaceEdit? edit; + + /// Marks this as a preferred action. Preferred actions are used by the `auto + /// fix` command and can be targeted by keybindings. + /// + /// A quick fix should be marked preferred if it properly addresses the + /// underlying error. A refactoring should be marked preferred if it is the + /// most reasonable choice of actions to take. + /// + /// @since 3.15.0 + final bool? isPreferred; + + /// The kind of the code action. + /// + /// Used to filter code actions. + final CodeActionKind? kind; + + /// A short, human-readable, title for this code action. + final String title; + CodeActionLiteral({ + this.command, + this.data, + this.diagnostics, + this.disabled, + this.edit, + this.isPreferred, + this.kind, + required this.title, + }); + @override + int get hashCode => Object.hash( + command, + data, + lspHashCode(diagnostics), + disabled, + edit, + isPreferred, + kind, + title, + ); + + @override + bool operator ==(Object other) { + return other is CodeActionLiteral && + other.runtimeType == CodeActionLiteral && + command == other.command && + data == other.data && + const DeepCollectionEquality().equals(diagnostics, other.diagnostics) && + disabled == other.disabled && + edit == other.edit && + isPreferred == other.isPreferred && + kind == other.kind && + title == other.title; + } + + @override + Map toJson() { + var result = {}; + if (command != null) { + result['command'] = command?.toJson(); + } + if (data != null) { + result['data'] = data; + } + if (diagnostics != null) { + result['diagnostics'] = + diagnostics?.map((item) => item.toJson()).toList(); + } + if (disabled != null) { + result['disabled'] = disabled?.toJson(); + } + if (edit != null) { + result['edit'] = edit?.toJson(); + } + if (isPreferred != null) { + result['isPreferred'] = isPreferred; + } + if (kind != null) { + result['kind'] = kind?.toJson(); + } + result['title'] = title; + return result; + } + + @override + String toString() => jsonEncoder.convert(toJson()); + + static bool canParse(Object? obj, LspJsonReporter reporter) { + if (obj is Map) { + if (!_canParseCommand(obj, reporter, 'command', + allowsUndefined: true, allowsNull: false)) { + return false; + } + if (!_canParseListDiagnostic(obj, reporter, 'diagnostics', + allowsUndefined: true, allowsNull: false)) { + return false; + } + if (!_canParseCodeActionDisabled(obj, reporter, 'disabled', + allowsUndefined: true, allowsNull: false)) { + return false; + } + if (!_canParseWorkspaceEdit(obj, reporter, 'edit', + allowsUndefined: true, allowsNull: false)) { + return false; + } + if (!_canParseBool(obj, reporter, 'isPreferred', + allowsUndefined: true, allowsNull: false)) { + return false; + } + if (!_canParseCodeActionKind(obj, reporter, 'kind', + allowsUndefined: true, allowsNull: false)) { + return false; + } + return _canParseString(obj, reporter, 'title', + allowsUndefined: false, allowsNull: false); + } else { + reporter.reportError('must be of type CodeActionLiteral'); + return false; + } + } + + static CodeActionLiteral fromJson(Map json) { + final commandJson = json['command']; + final command = commandJson != null + ? Command.fromJson(commandJson as Map) + : null; + final dataJson = json['data']; + final data = dataJson; + final diagnosticsJson = json['diagnostics']; + final diagnostics = (diagnosticsJson as List?) + ?.map((item) => Diagnostic.fromJson(item as Map)) + .toList(); + final disabledJson = json['disabled']; + final disabled = disabledJson != null + ? CodeActionDisabled.fromJson(disabledJson as Map) + : null; + final editJson = json['edit']; + final edit = editJson != null + ? WorkspaceEdit.fromJson(editJson as Map) + : null; + final isPreferredJson = json['isPreferred']; + final isPreferred = isPreferredJson as bool?; + final kindJson = json['kind']; + final kind = + kindJson != null ? CodeActionKind.fromJson(kindJson as String) : null; + final titleJson = json['title']; + final title = titleJson as String; + return CodeActionLiteral( + command: command, + data: data, + diagnostics: diagnostics, + disabled: disabled, + edit: edit, + isPreferred: isPreferred, + kind: kind, + title: title, + ); + } +} + /// Provider options for a [CodeActionRequest]. class CodeActionOptions implements WorkDoneProgressOptions, ToJsonable { static const jsonHandler = LspJsonHandler(