Index: clangd/Protocol.h =================================================================== --- clangd/Protocol.h +++ clangd/Protocol.h @@ -29,6 +29,8 @@ namespace clang { namespace clangd { +class JSONOutput; + struct URI { std::string uri; std::string file; @@ -56,8 +58,8 @@ /// The text document's URI. URI uri; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct Position { @@ -76,7 +78,8 @@ std::tie(RHS.line, RHS.character); } - static llvm::Optional parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output); static std::string unparse(const Position &P); }; @@ -94,7 +97,8 @@ return std::tie(LHS.start, LHS.end) < std::tie(RHS.start, RHS.end); } - static llvm::Optional parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output); static std::string unparse(const Range &P); }; @@ -121,7 +125,8 @@ struct Metadata { std::vector extraFlags; - static llvm::Optional parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output); }; struct TextEdit { @@ -133,7 +138,8 @@ /// empty string. std::string newText; - static llvm::Optional parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output); static std::string unparse(const TextEdit &P); }; @@ -150,8 +156,8 @@ /// The content of the opened text document. std::string text; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output); }; struct DidOpenTextDocumentParams { @@ -161,24 +167,24 @@ /// Extension storing per-file metadata, such as compilation flags. llvm::Optional metadata; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct DidCloseTextDocumentParams { /// The document that was closed. TextDocumentIdentifier textDocument; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct TextDocumentContentChangeEvent { /// The new text of the document. std::string text; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct DidChangeTextDocumentParams { @@ -190,8 +196,8 @@ /// The actual content changes. std::vector contentChanges; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct FormattingOptions { @@ -201,8 +207,8 @@ /// Prefer spaces over tabs. bool insertSpaces; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); static std::string unparse(const FormattingOptions &P); }; @@ -216,8 +222,8 @@ /// The format options FormattingOptions options; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct DocumentOnTypeFormattingParams { @@ -233,8 +239,8 @@ /// The format options. FormattingOptions options; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct DocumentFormattingParams { @@ -244,8 +250,8 @@ /// The format options FormattingOptions options; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct Diagnostic { @@ -256,6 +262,15 @@ /// client to interpret diagnostics as error, warning, info or hint. int severity; + /// The diagnostic's code. Can be omitted. + /// Note: Not currently used by clangd + //std::string code; + + /// A human-readable string describing the source of this + /// diagnostic, e.g. 'typescript' or 'super lint'. + /// Note: Not currently used by clangd + //std::string source; + /// The diagnostic's message. std::string message; @@ -268,15 +283,16 @@ std::tie(RHS.range, RHS.severity, RHS.message); } - static llvm::Optional parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output); }; struct CodeActionContext { /// An array of diagnostics. std::vector diagnostics; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct CodeActionParams { @@ -289,8 +305,8 @@ /// Context carrying additional information. CodeActionContext context; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output); }; struct TextDocumentPositionParams { @@ -300,8 +316,8 @@ /// The position inside the text document. Position position; - static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + static llvm::Optional parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output); }; /// The kind of a completion entry. Index: clangd/Protocol.cpp =================================================================== --- clangd/Protocol.cpp +++ clangd/Protocol.cpp @@ -13,13 +13,23 @@ //===----------------------------------------------------------------------===// #include "Protocol.h" +#include "JSONRPCDispatcher.h" + #include "clang/Basic/LLVM.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" using namespace clang::clangd; +namespace { +void logIgnoredField(const clang::StringRef& KeyValue, JSONOutput &Output) { + Output.log( + llvm::formatv("Ignored unknown field \"{0}\"\n", KeyValue.str().c_str())); +} +} + URI URI::fromUri(llvm::StringRef uri) { URI Result; Result.uri = uri; @@ -55,7 +65,8 @@ std::string URI::unparse(const URI &U) { return "\"" + U.uri + "\""; } llvm::Optional -TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params) { +TextDocumentIdentifier::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { TextDocumentIdentifier Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -74,13 +85,14 @@ } else if (KeyValue == "version") { // FIXME: parse version, but only for VersionedTextDocumentIdentifiers. } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } -llvm::Optional Position::parse(llvm::yaml::MappingNode *Params) { +llvm::Optional Position::parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output) { Position Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -106,7 +118,7 @@ return llvm::None; Result.character = Val; } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; @@ -119,7 +131,8 @@ return Result; } -llvm::Optional Range::parse(llvm::yaml::MappingNode *Params) { +llvm::Optional Range::parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output) { Range Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -135,17 +148,17 @@ llvm::SmallString<10> Storage; if (KeyValue == "start") { - auto Parsed = Position::parse(Value); + auto Parsed = Position::parse(Value, Output); if (!Parsed) return llvm::None; Result.start = std::move(*Parsed); } else if (KeyValue == "end") { - auto Parsed = Position::parse(Value); + auto Parsed = Position::parse(Value, Output); if (!Parsed) return llvm::None; Result.end = std::move(*Parsed); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; @@ -168,7 +181,8 @@ } llvm::Optional -TextDocumentItem::parse(llvm::yaml::MappingNode *Params) { +TextDocumentItem::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { TextDocumentItem Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -195,13 +209,14 @@ } else if (KeyValue == "text") { Result.text = Value->getValue(Storage); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } -llvm::Optional Metadata::parse(llvm::yaml::MappingNode *Params) { +llvm::Optional Metadata::parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output) { Metadata Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -223,12 +238,15 @@ return llvm::None; Result.extraFlags.push_back(Node->getValue(Storage)); } + } else { + logIgnoredField(KeyValue, Output); } } return Result; } -llvm::Optional TextEdit::parse(llvm::yaml::MappingNode *Params) { +llvm::Optional TextEdit::parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output) { TextEdit Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -244,7 +262,7 @@ auto *Map = dyn_cast(Value); if (!Map) return llvm::None; - auto Parsed = Range::parse(Map); + auto Parsed = Range::parse(Map, Output); if (!Parsed) return llvm::None; Result.range = std::move(*Parsed); @@ -254,7 +272,7 @@ return llvm::None; Result.newText = Node->getValue(Storage); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; @@ -269,7 +287,8 @@ } llvm::Optional -DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params) { +DidOpenTextDocumentParams::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { DidOpenTextDocumentParams Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -285,24 +304,25 @@ llvm::SmallString<10> Storage; if (KeyValue == "textDocument") { - auto Parsed = TextDocumentItem::parse(Value); + auto Parsed = TextDocumentItem::parse(Value, Output); if (!Parsed) return llvm::None; Result.textDocument = std::move(*Parsed); } else if (KeyValue == "metadata") { - auto Parsed = Metadata::parse(Value); + auto Parsed = Metadata::parse(Value, Output); if (!Parsed) return llvm::None; Result.metadata = std::move(*Parsed); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } llvm::Optional -DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params) { +DidCloseTextDocumentParams::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { DidCloseTextDocumentParams Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -317,19 +337,20 @@ auto *Map = dyn_cast(Value); if (!Map) return llvm::None; - auto Parsed = TextDocumentIdentifier::parse(Map); + auto Parsed = TextDocumentIdentifier::parse(Map, Output); if (!Parsed) return llvm::None; Result.textDocument = std::move(*Parsed); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } llvm::Optional -DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params) { +DidChangeTextDocumentParams::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { DidChangeTextDocumentParams Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -345,7 +366,7 @@ auto *Map = dyn_cast(Value); if (!Map) return llvm::None; - auto Parsed = TextDocumentIdentifier::parse(Map); + auto Parsed = TextDocumentIdentifier::parse(Map, Output); if (!Parsed) return llvm::None; Result.textDocument = std::move(*Parsed); @@ -357,20 +378,21 @@ auto *I = dyn_cast(&Item); if (!I) return llvm::None; - auto Parsed = TextDocumentContentChangeEvent::parse(I); + auto Parsed = TextDocumentContentChangeEvent::parse(I, Output); if (!Parsed) return llvm::None; Result.contentChanges.push_back(std::move(*Parsed)); } } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } llvm::Optional -TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params) { +TextDocumentContentChangeEvent::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { TextDocumentContentChangeEvent Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -388,14 +410,15 @@ if (KeyValue == "text") { Result.text = Value->getValue(Storage); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } llvm::Optional -FormattingOptions::parse(llvm::yaml::MappingNode *Params) { +FormattingOptions::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { FormattingOptions Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -428,7 +451,7 @@ } Result.insertSpaces = Val; } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; @@ -442,7 +465,8 @@ } llvm::Optional -DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params) { +DocumentRangeFormattingParams::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { DocumentRangeFormattingParams Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -458,29 +482,30 @@ llvm::SmallString<10> Storage; if (KeyValue == "textDocument") { - auto Parsed = TextDocumentIdentifier::parse(Value); + auto Parsed = TextDocumentIdentifier::parse(Value, Output); if (!Parsed) return llvm::None; Result.textDocument = std::move(*Parsed); } else if (KeyValue == "range") { - auto Parsed = Range::parse(Value); + auto Parsed = Range::parse(Value, Output); if (!Parsed) return llvm::None; Result.range = std::move(*Parsed); } else if (KeyValue == "options") { - auto Parsed = FormattingOptions::parse(Value); + auto Parsed = FormattingOptions::parse(Value, Output); if (!Parsed) return llvm::None; Result.options = std::move(*Parsed); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } llvm::Optional -DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params) { +DocumentOnTypeFormattingParams::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { DocumentOnTypeFormattingParams Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -505,29 +530,30 @@ if (!Value) return llvm::None; if (KeyValue == "textDocument") { - auto Parsed = TextDocumentIdentifier::parse(Value); + auto Parsed = TextDocumentIdentifier::parse(Value, Output); if (!Parsed) return llvm::None; Result.textDocument = std::move(*Parsed); } else if (KeyValue == "position") { - auto Parsed = Position::parse(Value); + auto Parsed = Position::parse(Value, Output); if (!Parsed) return llvm::None; Result.position = std::move(*Parsed); } else if (KeyValue == "options") { - auto Parsed = FormattingOptions::parse(Value); + auto Parsed = FormattingOptions::parse(Value, Output); if (!Parsed) return llvm::None; Result.options = std::move(*Parsed); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } llvm::Optional -DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params) { +DocumentFormattingParams::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { DocumentFormattingParams Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -543,23 +569,24 @@ llvm::SmallString<10> Storage; if (KeyValue == "textDocument") { - auto Parsed = TextDocumentIdentifier::parse(Value); + auto Parsed = TextDocumentIdentifier::parse(Value, Output); if (!Parsed) return llvm::None; Result.textDocument = std::move(*Parsed); } else if (KeyValue == "options") { - auto Parsed = FormattingOptions::parse(Value); + auto Parsed = FormattingOptions::parse(Value, Output); if (!Parsed) return llvm::None; Result.options = std::move(*Parsed); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } -llvm::Optional Diagnostic::parse(llvm::yaml::MappingNode *Params) { +llvm::Optional Diagnostic::parse(llvm::yaml::MappingNode *Params, + JSONOutput &Output) { Diagnostic Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -575,7 +602,7 @@ dyn_cast_or_null(NextKeyValue.getValue()); if (!Value) return llvm::None; - auto Parsed = Range::parse(Value); + auto Parsed = Range::parse(Value, Output); if (!Parsed) return llvm::None; Result.range = std::move(*Parsed); @@ -588,6 +615,10 @@ if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val)) return llvm::None; Result.severity = Val; + } else if (KeyValue == "code") { + // Not currently used + } else if (KeyValue == "source") { + // Not currently used } else if (KeyValue == "message") { auto *Value = dyn_cast_or_null(NextKeyValue.getValue()); @@ -595,14 +626,15 @@ return llvm::None; Result.message = Value->getValue(Storage); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } llvm::Optional -CodeActionContext::parse(llvm::yaml::MappingNode *Params) { +CodeActionContext::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { CodeActionContext Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -622,20 +654,21 @@ auto *I = dyn_cast(&Item); if (!I) return llvm::None; - auto Parsed = Diagnostic::parse(I); + auto Parsed = Diagnostic::parse(I, Output); if (!Parsed) return llvm::None; Result.diagnostics.push_back(std::move(*Parsed)); } } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } llvm::Optional -CodeActionParams::parse(llvm::yaml::MappingNode *Params) { +CodeActionParams::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { CodeActionParams Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -651,29 +684,30 @@ llvm::SmallString<10> Storage; if (KeyValue == "textDocument") { - auto Parsed = TextDocumentIdentifier::parse(Value); + auto Parsed = TextDocumentIdentifier::parse(Value, Output); if (!Parsed) return llvm::None; Result.textDocument = std::move(*Parsed); } else if (KeyValue == "range") { - auto Parsed = Range::parse(Value); + auto Parsed = Range::parse(Value, Output); if (!Parsed) return llvm::None; Result.range = std::move(*Parsed); } else if (KeyValue == "context") { - auto Parsed = CodeActionContext::parse(Value); + auto Parsed = CodeActionContext::parse(Value, Output); if (!Parsed) return llvm::None; Result.context = std::move(*Parsed); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; } llvm::Optional -TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params) { +TextDocumentPositionParams::parse( + llvm::yaml::MappingNode *Params, JSONOutput &Output) { TextDocumentPositionParams Result; for (auto &NextKeyValue : *Params) { auto *KeyString = dyn_cast(NextKeyValue.getKey()); @@ -689,17 +723,17 @@ llvm::SmallString<10> Storage; if (KeyValue == "textDocument") { - auto Parsed = TextDocumentIdentifier::parse(Value); + auto Parsed = TextDocumentIdentifier::parse(Value, Output); if (!Parsed) return llvm::None; Result.textDocument = std::move(*Parsed); } else if (KeyValue == "position") { - auto Parsed = Position::parse(Value); + auto Parsed = Position::parse(Value, Output); if (!Parsed) return llvm::None; Result.position = std::move(*Parsed); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; Index: clangd/ProtocolHandlers.cpp =================================================================== --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -45,7 +45,7 @@ : Handler(Output), Callbacks(Callbacks) {} void handleNotification(llvm::yaml::MappingNode *Params) override { - auto DOTDP = DidOpenTextDocumentParams::parse(Params); + auto DOTDP = DidOpenTextDocumentParams::parse(Params, Output); if (!DOTDP) { Output.log("Failed to decode DidOpenTextDocumentParams!\n"); return; @@ -62,7 +62,7 @@ : Handler(Output), Callbacks(Callbacks) {} void handleNotification(llvm::yaml::MappingNode *Params) override { - auto DCTDP = DidChangeTextDocumentParams::parse(Params); + auto DCTDP = DidChangeTextDocumentParams::parse(Params, Output); if (!DCTDP || DCTDP->contentChanges.size() != 1) { Output.log("Failed to decode DidChangeTextDocumentParams!\n"); return; @@ -80,7 +80,7 @@ : Handler(Output), Callbacks(Callbacks) {} void handleNotification(llvm::yaml::MappingNode *Params) override { - auto DCTDP = DidCloseTextDocumentParams::parse(Params); + auto DCTDP = DidCloseTextDocumentParams::parse(Params, Output); if (!DCTDP) { Output.log("Failed to decode DidCloseTextDocumentParams!\n"); return; @@ -99,7 +99,7 @@ : Handler(Output), Callbacks(Callbacks) {} void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override { - auto DOTFP = DocumentOnTypeFormattingParams::parse(Params); + auto DOTFP = DocumentOnTypeFormattingParams::parse(Params, Output); if (!DOTFP) { Output.log("Failed to decode DocumentOnTypeFormattingParams!\n"); return; @@ -118,7 +118,7 @@ : Handler(Output), Callbacks(Callbacks) {} void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override { - auto DRFP = DocumentRangeFormattingParams::parse(Params); + auto DRFP = DocumentRangeFormattingParams::parse(Params, Output); if (!DRFP) { Output.log("Failed to decode DocumentRangeFormattingParams!\n"); return; @@ -137,7 +137,7 @@ : Handler(Output), Callbacks(Callbacks) {} void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override { - auto DFP = DocumentFormattingParams::parse(Params); + auto DFP = DocumentFormattingParams::parse(Params, Output); if (!DFP) { Output.log("Failed to decode DocumentFormattingParams!\n"); return; @@ -155,7 +155,7 @@ : Handler(Output), Callbacks(Callbacks) {} void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override { - auto CAP = CodeActionParams::parse(Params); + auto CAP = CodeActionParams::parse(Params, Output); if (!CAP) { Output.log("Failed to decode CodeActionParams!\n"); return; @@ -173,7 +173,7 @@ : Handler(Output), Callbacks(Callbacks) {} void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override { - auto TDPP = TextDocumentPositionParams::parse(Params); + auto TDPP = TextDocumentPositionParams::parse(Params, Output); if (!TDPP) { Output.log("Failed to decode TextDocumentPositionParams!\n"); return; @@ -191,7 +191,7 @@ : Handler(Output), Callbacks(Callbacks) {} void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override { - auto TDPP = TextDocumentPositionParams::parse(Params); + auto TDPP = TextDocumentPositionParams::parse(Params, Output); if (!TDPP) { Output.log("Failed to decode TextDocumentPositionParams!\n"); return; Index: test/clangd/fixits.test =================================================================== --- test/clangd/fixits.test +++ test/clangd/fixits.test @@ -17,6 +17,12 @@ # # CHECK: {"jsonrpc":"2.0","id":2, "result": [{"title":"Apply FixIt 'place parentheses around the assignment to silence this warning'", "command": "clangd.applyFix", "arguments": ["file:///foo.c", [{"range": {"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 32}}, "newText": "("},{"range": {"start": {"line": 0, "character": 37}, "end": {"line": 0, "character": 37}}, "newText": ")"}]]},{"title":"Apply FixIt 'use '==' to turn this assignment into an equality comparison'", "command": "clangd.applyFix", "arguments": ["file:///foo.c", [{"range": {"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}}, "newText": "=="}]]}] # +Content-Length: 771 + +{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"file:///foo.c"},"range":{"start":{"line":104,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":2,"code":"1","source":"foo","message":"using the result of an assignment as a condition without parentheses"},{"range":{"start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"place parentheses around the assignment to silence this warning"},{"range":{"start": {"line": 0, "character": 35}, "end": {"line": 0, "character": 35}},"severity":3,"message":"use '==' to turn this assignment into an equality comparison"}]}}} +# Make sure unused "code" and "source" fields ignored gracefully +# CHECK: {"jsonrpc":"2.0","id":2, "result": [{"title":"Apply FixIt 'place parentheses around the assignment to silence this warning'", "command": "clangd.applyFix", "arguments": ["file:///foo.c", [{"range": {"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 32}}, "newText": "("},{"range": {"start": {"line": 0, "character": 37}, "end": {"line": 0, "character": 37}}, "newText": ")"}]]},{"title":"Apply FixIt 'use '==' to turn this assignment into an equality comparison'", "command": "clangd.applyFix", "arguments": ["file:///foo.c", [{"range": {"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}}, "newText": "=="}]]}] +# Content-Length: 44 {"jsonrpc":"2.0","id":3,"method":"shutdown"}