[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
This commit is contained in:
Marc-Andre Laperle 2017-09-18 15:02:59 +00:00
parent 3fa0ccffc6
commit 85dcce4d15
4 changed files with 138 additions and 87 deletions

View File

@ -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>
TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params) {
TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
TextDocumentIdentifier Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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> Position::parse(llvm::yaml::MappingNode *Params) {
llvm::Optional<Position> Position::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
Position Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@ -106,7 +117,7 @@ llvm::Optional<Position> 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> Range::parse(llvm::yaml::MappingNode *Params) {
llvm::Optional<Range> Range::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
Range Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@ -135,17 +147,17 @@ llvm::Optional<Range> 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>
TextDocumentItem::parse(llvm::yaml::MappingNode *Params) {
TextDocumentItem::parse(llvm::yaml::MappingNode *Params, JSONOutput &Output) {
TextDocumentItem Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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> Metadata::parse(llvm::yaml::MappingNode *Params) {
llvm::Optional<Metadata> Metadata::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
Metadata Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@ -223,12 +236,15 @@ llvm::Optional<Metadata> 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> TextEdit::parse(llvm::yaml::MappingNode *Params) {
llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
TextEdit Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@ -244,7 +260,7 @@ llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params) {
auto *Map = dyn_cast<llvm::yaml::MappingNode>(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> 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>
DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
DidOpenTextDocumentParams Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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>
DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
DidCloseTextDocumentParams Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@ -317,19 +335,20 @@ DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
auto *Map = dyn_cast<llvm::yaml::MappingNode>(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>
DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
DidChangeTextDocumentParams Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@ -345,7 +364,7 @@ DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
auto *Map = dyn_cast<llvm::yaml::MappingNode>(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<llvm::yaml::MappingNode>(&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>
TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params) {
TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
TextDocumentContentChangeEvent Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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>
FormattingOptions::parse(llvm::yaml::MappingNode *Params) {
FormattingOptions::parse(llvm::yaml::MappingNode *Params, JSONOutput &Output) {
FormattingOptions Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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>
DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params) {
DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
DocumentRangeFormattingParams Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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>
DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params) {
DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
DocumentOnTypeFormattingParams Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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>
DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params) {
DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
DocumentFormattingParams Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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> Diagnostic::parse(llvm::yaml::MappingNode *Params) {
llvm::Optional<Diagnostic> Diagnostic::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
Diagnostic Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@ -575,7 +599,7 @@ llvm::Optional<Diagnostic> Diagnostic::parse(llvm::yaml::MappingNode *Params) {
dyn_cast_or_null<llvm::yaml::MappingNode>(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> 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<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
@ -595,14 +623,14 @@ llvm::Optional<Diagnostic> 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>
CodeActionContext::parse(llvm::yaml::MappingNode *Params) {
CodeActionContext::parse(llvm::yaml::MappingNode *Params, JSONOutput &Output) {
CodeActionContext Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
@ -622,20 +650,20 @@ CodeActionContext::parse(llvm::yaml::MappingNode *Params) {
auto *I = dyn_cast<llvm::yaml::MappingNode>(&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>
CodeActionParams::parse(llvm::yaml::MappingNode *Params) {
CodeActionParams::parse(llvm::yaml::MappingNode *Params, JSONOutput &Output) {
CodeActionParams Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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>
TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params) {
TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output) {
TextDocumentPositionParams Result;
for (auto &NextKeyValue : *Params) {
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(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;

View File

@ -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<TextDocumentIdentifier>
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<Position> parse(llvm::yaml::MappingNode *Params);
static llvm::Optional<Position> 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<Range> parse(llvm::yaml::MappingNode *Params);
static llvm::Optional<Range> parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output);
static std::string unparse(const Range &P);
};
@ -121,7 +125,8 @@ struct Location {
struct Metadata {
std::vector<std::string> extraFlags;
static llvm::Optional<Metadata> parse(llvm::yaml::MappingNode *Params);
static llvm::Optional<Metadata> parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output);
};
struct TextEdit {
@ -133,7 +138,8 @@ struct TextEdit {
/// empty string.
std::string newText;
static llvm::Optional<TextEdit> parse(llvm::yaml::MappingNode *Params);
static llvm::Optional<TextEdit> 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<TextDocumentItem>
parse(llvm::yaml::MappingNode *Params);
static llvm::Optional<TextDocumentItem> parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output);
};
struct DidOpenTextDocumentParams {
@ -162,7 +168,7 @@ struct DidOpenTextDocumentParams {
llvm::Optional<Metadata> metadata;
static llvm::Optional<DidOpenTextDocumentParams>
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<DidCloseTextDocumentParams>
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<TextDocumentContentChangeEvent>
parse(llvm::yaml::MappingNode *Params);
parse(llvm::yaml::MappingNode *Params, JSONOutput &Output);
};
struct DidChangeTextDocumentParams {
@ -191,7 +197,7 @@ struct DidChangeTextDocumentParams {
std::vector<TextDocumentContentChangeEvent> contentChanges;
static llvm::Optional<DidChangeTextDocumentParams>
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<FormattingOptions>
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<DocumentRangeFormattingParams>
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<DocumentOnTypeFormattingParams>
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<DocumentFormattingParams>
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<Diagnostic> parse(llvm::yaml::MappingNode *Params);
static llvm::Optional<Diagnostic> parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output);
};
struct CodeActionContext {
@ -276,7 +292,7 @@ struct CodeActionContext {
std::vector<Diagnostic> diagnostics;
static llvm::Optional<CodeActionContext>
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<CodeActionParams>
parse(llvm::yaml::MappingNode *Params);
static llvm::Optional<CodeActionParams> parse(llvm::yaml::MappingNode *Params,
JSONOutput &Output);
};
struct TextDocumentPositionParams {
@ -301,7 +317,7 @@ struct TextDocumentPositionParams {
Position position;
static llvm::Optional<TextDocumentPositionParams>
parse(llvm::yaml::MappingNode *Params);
parse(llvm::yaml::MappingNode *Params, JSONOutput &Output);
};
/// The kind of a completion entry.

View File

@ -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;

View File

@ -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"}