From 85dcce4d15ff5cf3b5f5099ab39b24214431d935 Mon Sep 17 00:00:00 2001 From: Marc-Andre Laperle Date: Mon, 18 Sep 2017 15:02:59 +0000 Subject: [PATCH] [clangd] Fix codeAction not decoded properly when sent from some clients Summary: Fix for bug https://bugs.llvm.org/show_bug.cgi?id=34559 Also log unknown fields instead of aborting the JSON parsing because it's common that new optional fields are added either in new versions of the protocol or extensions. Reviewers: ilya-biryukov Reviewed By: ilya-biryukov Subscribers: ilya-biryukov Tags: #clang-tools-extra Differential Revision: https://reviews.llvm.org/D37754 llvm-svn: 313536 --- clang-tools-extra/clangd/Protocol.cpp | 145 +++++++++++------- clang-tools-extra/clangd/Protocol.h | 56 ++++--- clang-tools-extra/clangd/ProtocolHandlers.cpp | 18 +-- clang-tools-extra/test/clangd/fixits.test | 6 + 4 files changed, 138 insertions(+), 87 deletions(-) diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index 94b24010423b..57d3bee80bbc 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -13,13 +13,22 @@ //===----------------------------------------------------------------------===// #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(llvm::StringRef KeyValue, JSONOutput &Output) { + Output.log(llvm::formatv("Ignored unknown field \"{0}\"\n", KeyValue)); +} +} // namespace + URI URI::fromUri(llvm::StringRef uri) { URI Result; Result.uri = uri; @@ -55,7 +64,8 @@ URI URI::parse(llvm::yaml::ScalarNode *Param) { 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 +84,14 @@ TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params) { } 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 +117,7 @@ llvm::Optional Position::parse(llvm::yaml::MappingNode *Params) { return llvm::None; Result.character = Val; } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; @@ -119,7 +130,8 @@ std::string Position::unparse(const Position &P) { 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 +147,17 @@ llvm::Optional Range::parse(llvm::yaml::MappingNode *Params) { 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 +180,7 @@ std::string Location::unparse(const Location &P) { } 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 +207,14 @@ TextDocumentItem::parse(llvm::yaml::MappingNode *Params) { } 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 +236,15 @@ llvm::Optional Metadata::parse(llvm::yaml::MappingNode *Params) { 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 +260,7 @@ llvm::Optional TextEdit::parse(llvm::yaml::MappingNode *Params) { 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 +270,7 @@ llvm::Optional TextEdit::parse(llvm::yaml::MappingNode *Params) { return llvm::None; Result.newText = Node->getValue(Storage); } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; @@ -269,7 +285,8 @@ std::string TextEdit::unparse(const TextEdit &P) { } 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 +302,25 @@ DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params) { 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 +335,20 @@ DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params) { 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 +364,7 @@ DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params) { 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 +376,21 @@ DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params) { 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 +408,14 @@ TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params) { 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 +448,7 @@ FormattingOptions::parse(llvm::yaml::MappingNode *Params) { } Result.insertSpaces = Val; } else { - return llvm::None; + logIgnoredField(KeyValue, Output); } } return Result; @@ -442,7 +462,8 @@ std::string FormattingOptions::unparse(const FormattingOptions &P) { } 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 +479,30 @@ DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params) { 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 +527,30 @@ DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params) { 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 +566,24 @@ DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params) { 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 +599,7 @@ llvm::Optional Diagnostic::parse(llvm::yaml::MappingNode *Params) { 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 +612,10 @@ llvm::Optional Diagnostic::parse(llvm::yaml::MappingNode *Params) { 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 +623,14 @@ llvm::Optional Diagnostic::parse(llvm::yaml::MappingNode *Params) { 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 +650,20 @@ CodeActionContext::parse(llvm::yaml::MappingNode *Params) { 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 +679,30 @@ CodeActionParams::parse(llvm::yaml::MappingNode *Params) { 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 +718,17 @@ TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params) { 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; diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index 8239d8b2774f..f3f2d00dab68 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -29,6 +29,8 @@ namespace clang { namespace clangd { +class JSONOutput; + struct URI { std::string uri; std::string file; @@ -57,7 +59,7 @@ struct TextDocumentIdentifier { URI uri; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct Position { @@ -76,7 +78,8 @@ struct Position { 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 @@ struct Range { 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 Location { 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 @@ struct TextEdit { /// 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 @@ struct TextDocumentItem { /// 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 { @@ -162,7 +168,7 @@ struct DidOpenTextDocumentParams { llvm::Optional metadata; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct DidCloseTextDocumentParams { @@ -170,7 +176,7 @@ struct DidCloseTextDocumentParams { TextDocumentIdentifier textDocument; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct TextDocumentContentChangeEvent { @@ -178,7 +184,7 @@ struct TextDocumentContentChangeEvent { std::string text; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct DidChangeTextDocumentParams { @@ -191,7 +197,7 @@ struct DidChangeTextDocumentParams { std::vector contentChanges; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct FormattingOptions { @@ -202,7 +208,7 @@ struct FormattingOptions { bool insertSpaces; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); static std::string unparse(const FormattingOptions &P); }; @@ -217,7 +223,7 @@ struct DocumentRangeFormattingParams { FormattingOptions options; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct DocumentOnTypeFormattingParams { @@ -234,7 +240,7 @@ struct DocumentOnTypeFormattingParams { FormattingOptions options; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct DocumentFormattingParams { @@ -245,7 +251,7 @@ struct DocumentFormattingParams { FormattingOptions options; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct Diagnostic { @@ -256,6 +262,15 @@ struct Diagnostic { /// 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,7 +283,8 @@ struct Diagnostic { 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 { @@ -276,7 +292,7 @@ struct CodeActionContext { std::vector diagnostics; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; struct CodeActionParams { @@ -289,8 +305,8 @@ struct CodeActionParams { /// 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 { @@ -301,7 +317,7 @@ struct TextDocumentPositionParams { Position position; static llvm::Optional - parse(llvm::yaml::MappingNode *Params); + parse(llvm::yaml::MappingNode *Params, JSONOutput &Output); }; /// The kind of a completion entry. diff --git a/clang-tools-extra/clangd/ProtocolHandlers.cpp b/clang-tools-extra/clangd/ProtocolHandlers.cpp index 3f1f72f078e2..6d527ef090b4 100644 --- a/clang-tools-extra/clangd/ProtocolHandlers.cpp +++ b/clang-tools-extra/clangd/ProtocolHandlers.cpp @@ -45,7 +45,7 @@ struct TextDocumentDidOpenHandler : Handler { : 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 @@ struct TextDocumentDidChangeHandler : Handler { : 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 @@ struct TextDocumentDidCloseHandler : Handler { : 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 @@ struct TextDocumentOnTypeFormattingHandler : Handler { : 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 @@ struct TextDocumentRangeFormattingHandler : Handler { : 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 @@ struct TextDocumentFormattingHandler : Handler { : 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 @@ struct CodeActionHandler : Handler { : 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 @@ struct CompletionHandler : Handler { : 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 @@ struct GotoDefinitionHandler : Handler { : 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; diff --git a/clang-tools-extra/test/clangd/fixits.test b/clang-tools-extra/test/clangd/fixits.test index 7272c3b174e6..3f7ddb4185f4 100644 --- a/clang-tools-extra/test/clangd/fixits.test +++ b/clang-tools-extra/test/clangd/fixits.test @@ -17,6 +17,12 @@ Content-Length: 746 # # 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"}