if (!Code)
return Reply(llvm::make_error<LSPError>(
"onCodeAction called for non-added file", ErrorCode::InvalidParams));
+
+ // Checks whether a particular CodeActionKind is included in the response.
+ auto KindAllowed = [Only(Params.context.only)](llvm::StringRef Kind) {
+ if (Only.empty())
+ return true;
+ return llvm::any_of(Only, [&](llvm::StringRef Base) {
+ return Kind.consume_front(Base) && (Kind.empty() || Kind.startswith("."));
+ });
+ };
+
// We provide a code action for Fixes on the specified diagnostics.
std::vector<CodeAction> FixIts;
- for (const Diagnostic &D : Params.context.diagnostics) {
- for (auto &F : getFixes(File.file(), D)) {
- FixIts.push_back(toCodeAction(F, Params.textDocument.uri));
- FixIts.back().diagnostics = {D};
+ if (KindAllowed(CodeAction::QUICKFIX_KIND)) {
+ for (const Diagnostic &D : Params.context.diagnostics) {
+ for (auto &F : getFixes(File.file(), D)) {
+ FixIts.push_back(toCodeAction(F, Params.textDocument.uri));
+ FixIts.back().diagnostics = {D};
+ }
}
}
}
return Reply(llvm::json::Array(Commands));
};
-
Server->enumerateTweaks(
File.file(), Params.range,
- [&](const Tweak &T) {
- if (!Opts.TweakFilter(T))
- return false;
- // FIXME: also consider CodeActionContext.only
- return true;
+ [this, KindAllowed(std::move(KindAllowed))](const Tweak &T) {
+ return Opts.TweakFilter(T) && KindAllowed(T.kind());
},
std::move(ConsumeActions));
}
bool fromJSON(const llvm::json::Value &Params, CodeActionContext &R,
llvm::json::Path P) {
llvm::json::ObjectMapper O(Params, P);
- return O && O.map("diagnostics", R.diagnostics);
+ if (!O || !O.map("diagnostics", R.diagnostics))
+ return false;
+ O.map("only", R.only);
+ return true;
}
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
llvm::json::Value toJSON(const PublishDiagnosticsParams &);
struct CodeActionContext {
- /// An array of diagnostics.
+ /// An array of diagnostics known on the client side overlapping the range
+ /// provided to the `textDocument/codeAction` request. They are provided so
+ /// that the server knows which errors are currently presented to the user for
+ /// the given range. There is no guarantee that these accurately reflect the
+ /// error state of the resource. The primary parameter to compute code actions
+ /// is the provided range.
std::vector<Diagnostic> diagnostics;
+
+ /// Requested kind of actions to return.
+ ///
+ /// Actions not of this kind are filtered out by the client before being
+ /// shown. So servers can omit computing them.
+ std::vector<std::string> only;
};
bool fromJSON(const llvm::json::Value &, CodeActionContext &, llvm::json::Path);
# CHECK-NEXT: }
# CHECK-NEXT: ]
---
+{
+ "jsonrpc": "2.0",
+ "id": 2,
+ "method": "textDocument/codeAction",
+ "params": {
+ "textDocument": { "uri": "test:///main.cpp" },
+ "range": {
+ "start": {"line": 0, "character": 0},
+ "end": {"line": 0, "character": 4}
+ },
+ "context": {
+ "diagnostics": [],
+ "only": ["quickfix"]
+ }
+ }
+}
+# CHECK: "id": 2,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": []
+---
+{
+ "jsonrpc": "2.0",
+ "id": 3,
+ "method": "textDocument/codeAction",
+ "params": {
+ "textDocument": { "uri": "test:///main.cpp" },
+ "range": {
+ "start": {"line": 0, "character": 0},
+ "end": {"line": 0, "character": 4}
+ },
+ "context": {
+ "diagnostics": [],
+ "only": ["refactor"]
+ }
+ }
+}
+# CHECK: "id": 3,
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT: {
+---
{"jsonrpc":"2.0","id":4,"method":"workspace/executeCommand","params":{"command":"clangd.applyTweak","arguments":[{"file":"test:///main.cpp","selection":{"end":{"character":4,"line":0},"start":{"character":0,"line":0}},"tweakID":"ExpandAutoType"}]}}
# CHECK: "newText": "int",
# CHECK-NEXT: "range": {
# CHECK-NEXT: }
# CHECK-NEXT: }
---
-{"jsonrpc":"2.0","id":4,"method":"shutdown"}
+{"jsonrpc":"2.0","id":5,"method":"shutdown"}
---
{"jsonrpc":"2.0","method":"exit"}
---