diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -1007,6 +1007,20 @@ for (const auto &T : *Tweaks) Actions.push_back(toCodeAction(T, File, Selection)); + // If there's exactly one quick-fix, call it "preferred". + // We never consider refactorings etc as preferred. + CodeAction *OnlyFix = nullptr; + for (auto &Action : Actions) { + if (Action.kind && *Action.kind == CodeAction::QUICKFIX_KIND) { + if (OnlyFix) { + OnlyFix->isPreferred = false; + break; + } + Action.isPreferred = true; + OnlyFix = &Action; + } + } + if (SupportsCodeAction) return Reply(llvm::json::Array(Actions)); std::vector Commands; diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -411,6 +411,8 @@ Main.codeActions.emplace(); for (const auto &Fix : D.Fixes) Main.codeActions->push_back(toCodeAction(Fix, File)); + if (Main.codeActions->size() == 1) + Main.codeActions->front().isPreferred = true; } if (Opts.SendDiagnosticCategory && !D.Category.empty()) Main.category = D.Category; diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -952,6 +952,13 @@ /// The diagnostics that this code action resolves. llvm::Optional> diagnostics; + /// 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. + bool isPreferred = false; + /// The workspace edit this code action performs. llvm::Optional edit; diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -740,6 +740,8 @@ CodeAction["kind"] = *CA.kind; if (CA.diagnostics) CodeAction["diagnostics"] = llvm::json::Array(*CA.diagnostics); + if (CA.isPreferred) + CodeAction["isPreferred"] = true; if (CA.edit) CodeAction["edit"] = *CA.edit; if (CA.command) diff --git a/clang-tools-extra/clangd/test/fixits-embed-in-diagnostic.test b/clang-tools-extra/clangd/test/fixits-embed-in-diagnostic.test --- a/clang-tools-extra/clangd/test/fixits-embed-in-diagnostic.test +++ b/clang-tools-extra/clangd/test/fixits-embed-in-diagnostic.test @@ -28,6 +28,7 @@ # CHECK-NEXT: ] # CHECK-NEXT: } # CHECK-NEXT: }, +# CHECK-NEXT: "isPreferred": true, # CHECK-NEXT: "kind": "quickfix", # CHECK-NEXT: "title": "change 'union' to 'struct'" # CHECK-NEXT: }