Skip to content

Commit 34e8fd5

Browse files
kadircettstellar
authored andcommitted
[clangd] Treat "null" optional fields as missing
Clangd currently throws away any protocol messages whenever an optional field has an unexpected type. This patch changes the behaviour to treat `null` fields as missing. This enables clangd to be more tolerant against small violations to the LSP spec. Fixes clangd/vscode-clangd#134 Differential Revision: https://reviews.llvm.org/D95229 (cherry picked from commit af20232)
1 parent 2f74c22 commit 34e8fd5

File tree

1 file changed

+31
-15
lines changed

1 file changed

+31
-15
lines changed

clang-tools-extra/clangd/Protocol.cpp

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@
2727

2828
namespace clang {
2929
namespace clangd {
30+
namespace {
31+
32+
// Helper that doesn't treat `null` and absent fields as failures.
33+
template <typename T>
34+
bool mapOptOrNull(const llvm::json::Value &Params, llvm::StringLiteral Prop,
35+
T &Out, llvm::json::Path P) {
36+
auto *O = Params.getAsObject();
37+
assert(O);
38+
auto *V = O->get(Prop);
39+
// Field is missing or null.
40+
if (!V || V->getAsNull().hasValue())
41+
return true;
42+
return fromJSON(*V, Out, P.field(Prop));
43+
}
44+
} // namespace
3045

3146
char LSPError::ID;
3247

@@ -490,7 +505,7 @@ bool fromJSON(const llvm::json::Value &Params, DidChangeTextDocumentParams &R,
490505
return O && O.map("textDocument", R.textDocument) &&
491506
O.map("contentChanges", R.contentChanges) &&
492507
O.map("wantDiagnostics", R.wantDiagnostics) &&
493-
O.mapOptional("forceRebuild", R.forceRebuild);
508+
mapOptOrNull(Params, "forceRebuild", R.forceRebuild, P);
494509
}
495510

496511
bool fromJSON(const llvm::json::Value &E, FileChangeType &Out,
@@ -580,10 +595,10 @@ bool fromJSON(const llvm::json::Value &Params, Diagnostic &R,
580595
llvm::json::Path P) {
581596
llvm::json::ObjectMapper O(Params, P);
582597
return O && O.map("range", R.range) && O.map("message", R.message) &&
583-
O.mapOptional("severity", R.severity) &&
584-
O.mapOptional("category", R.category) &&
585-
O.mapOptional("code", R.code) && O.mapOptional("source", R.source);
586-
return true;
598+
mapOptOrNull(Params, "severity", R.severity, P) &&
599+
mapOptOrNull(Params, "category", R.category, P) &&
600+
mapOptOrNull(Params, "code", R.code, P) &&
601+
mapOptOrNull(Params, "source", R.source, P);
587602
}
588603

589604
llvm::json::Value toJSON(const PublishDiagnosticsParams &PDP) {
@@ -818,7 +833,7 @@ bool fromJSON(const llvm::json::Value &Params, CompletionContext &R,
818833
llvm::json::ObjectMapper O(Params, P);
819834
int TriggerKind;
820835
if (!O || !O.map("triggerKind", TriggerKind) ||
821-
!O.mapOptional("triggerCharacter", R.triggerCharacter))
836+
!mapOptOrNull(Params, "triggerCharacter", R.triggerCharacter, P))
822837
return false;
823838
R.triggerKind = static_cast<CompletionTriggerKind>(TriggerKind);
824839
return true;
@@ -1121,8 +1136,8 @@ bool fromJSON(const llvm::json::Value &Params, ConfigurationSettings &S,
11211136
llvm::json::ObjectMapper O(Params, P);
11221137
if (!O)
11231138
return true; // 'any' type in LSP.
1124-
return O.mapOptional("compilationDatabaseChanges",
1125-
S.compilationDatabaseChanges);
1139+
return mapOptOrNull(Params, "compilationDatabaseChanges",
1140+
S.compilationDatabaseChanges, P);
11261141
}
11271142

11281143
bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts,
@@ -1133,8 +1148,8 @@ bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts,
11331148

11341149
return fromJSON(Params, Opts.ConfigSettings, P) &&
11351150
O.map("compilationDatabasePath", Opts.compilationDatabasePath) &&
1136-
O.mapOptional("fallbackFlags", Opts.fallbackFlags) &&
1137-
O.mapOptional("clangdFileStatus", Opts.FileStatus);
1151+
mapOptOrNull(Params, "fallbackFlags", Opts.fallbackFlags, P) &&
1152+
mapOptOrNull(Params, "clangdFileStatus", Opts.FileStatus, P);
11381153
}
11391154

11401155
bool fromJSON(const llvm::json::Value &E, TypeHierarchyDirection &Out,
@@ -1190,10 +1205,11 @@ bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I,
11901205
return O && O.map("name", I.name) && O.map("kind", I.kind) &&
11911206
O.map("uri", I.uri) && O.map("range", I.range) &&
11921207
O.map("selectionRange", I.selectionRange) &&
1193-
O.mapOptional("detail", I.detail) &&
1194-
O.mapOptional("deprecated", I.deprecated) &&
1195-
O.mapOptional("parents", I.parents) &&
1196-
O.mapOptional("children", I.children) && O.mapOptional("data", I.data);
1208+
mapOptOrNull(Params, "detail", I.detail, P) &&
1209+
mapOptOrNull(Params, "deprecated", I.deprecated, P) &&
1210+
mapOptOrNull(Params, "parents", I.parents, P) &&
1211+
mapOptOrNull(Params, "children", I.children, P) &&
1212+
mapOptOrNull(Params, "data", I.data, P);
11971213
}
11981214

11991215
bool fromJSON(const llvm::json::Value &Params,
@@ -1238,7 +1254,7 @@ bool fromJSON(const llvm::json::Value &Params, CallHierarchyItem &I,
12381254
return O && O.map("name", I.name) && O.map("kind", I.kind) &&
12391255
O.map("uri", I.uri) && O.map("range", I.range) &&
12401256
O.map("selectionRange", I.selectionRange) &&
1241-
O.mapOptional("data", I.data);
1257+
mapOptOrNull(Params, "data", I.data, P);
12421258
}
12431259

12441260
bool fromJSON(const llvm::json::Value &Params,

0 commit comments

Comments
 (0)