blob: a1e8226b3ca502e56174594919e368f0081c37c4 [file] [log] [blame]
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +00001//===--- Protocol.cpp - Language Server Protocol Implementation -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains the serialization code for the LSP structs.
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000011//
12//===----------------------------------------------------------------------===//
13
14#include "Protocol.h"
Eric Liu78ed91a72018-01-29 15:37:46 +000015#include "Logger.h"
Ilya Biryukov7d60d202018-02-16 12:20:47 +000016#include "URI.h"
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000017#include "clang/Basic/LLVM.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/Support/Format.h"
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000020#include "llvm/Support/FormatVariadic.h"
Krasimir Georgiev50117372017-04-07 11:03:26 +000021#include "llvm/Support/Path.h"
Ilya Biryukov574b7532017-08-02 09:08:39 +000022#include "llvm/Support/raw_ostream.h"
Ilya Biryukove5128f72017-09-20 07:24:15 +000023
Sam McCallff8b8742017-11-30 21:32:29 +000024namespace clang {
25namespace clangd {
Sam McCalld20d7982018-07-09 14:25:59 +000026using namespace llvm;
Sam McCall38a04912017-11-29 11:36:46 +000027
Sam McCalldc8f3cf2018-10-17 07:32:05 +000028char LSPError::ID;
29
Ilya Biryukov7d60d202018-02-16 12:20:47 +000030URIForFile::URIForFile(std::string AbsPath) {
31 assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative");
32 File = std::move(AbsPath);
33}
34
Sam McCalld20d7982018-07-09 14:25:59 +000035bool fromJSON(const json::Value &E, URIForFile &R) {
36 if (auto S = E.getAsString()) {
Eric Liu78ed91a72018-01-29 15:37:46 +000037 auto U = URI::parse(*S);
38 if (!U) {
Sam McCallbed58852018-07-11 10:35:11 +000039 elog("Failed to parse URI {0}: {1}", *S, U.takeError());
Eric Liu78ed91a72018-01-29 15:37:46 +000040 return false;
41 }
Eric Liu5740ff52018-01-31 16:26:27 +000042 if (U->scheme() != "file" && U->scheme() != "test") {
Sam McCallbed58852018-07-11 10:35:11 +000043 elog("Clangd only supports 'file' URI scheme for workspace files: {0}",
44 *S);
Eric Liu78ed91a72018-01-29 15:37:46 +000045 return false;
46 }
Sam McCall41d21522018-01-30 11:23:11 +000047 auto Path = URI::resolve(*U);
48 if (!Path) {
Sam McCallbed58852018-07-11 10:35:11 +000049 log("{0}", Path.takeError());
Sam McCall41d21522018-01-30 11:23:11 +000050 return false;
51 }
Ilya Biryukov7d60d202018-02-16 12:20:47 +000052 R = URIForFile(*Path);
Sam McCallff8b8742017-11-30 21:32:29 +000053 return true;
54 }
55 return false;
Sam McCall38a04912017-11-29 11:36:46 +000056}
57
Sam McCalld20d7982018-07-09 14:25:59 +000058json::Value toJSON(const URIForFile &U) { return U.uri(); }
Krasimir Georgiev50117372017-04-07 11:03:26 +000059
Eric Liu78ed91a72018-01-29 15:37:46 +000060llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) {
61 return OS << U.uri();
Sam McCallfffa8222017-12-20 10:26:53 +000062}
63
Sam McCalld20d7982018-07-09 14:25:59 +000064json::Value toJSON(const TextDocumentIdentifier &R) {
65 return json::Object{{"uri", R.uri}};
Eric Liuc5105f92018-02-16 14:15:55 +000066}
67
Sam McCalld20d7982018-07-09 14:25:59 +000068bool fromJSON(const json::Value &Params, TextDocumentIdentifier &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000069 json::ObjectMapper O(Params);
70 return O && O.map("uri", R.uri);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000071}
72
Sam McCalld20d7982018-07-09 14:25:59 +000073bool fromJSON(const json::Value &Params, Position &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000074 json::ObjectMapper O(Params);
75 return O && O.map("line", R.line) && O.map("character", R.character);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000076}
77
Sam McCalld20d7982018-07-09 14:25:59 +000078json::Value toJSON(const Position &P) {
79 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +000080 {"line", P.line},
81 {"character", P.character},
82 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000083}
84
Sam McCallfffa8222017-12-20 10:26:53 +000085llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) {
86 return OS << P.line << ':' << P.character;
87}
88
Sam McCalld20d7982018-07-09 14:25:59 +000089bool fromJSON(const json::Value &Params, Range &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000090 json::ObjectMapper O(Params);
91 return O && O.map("start", R.start) && O.map("end", R.end);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000092}
93
Sam McCalld20d7982018-07-09 14:25:59 +000094json::Value toJSON(const Range &P) {
95 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +000096 {"start", P.start},
97 {"end", P.end},
98 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000099}
100
Sam McCallfffa8222017-12-20 10:26:53 +0000101llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) {
102 return OS << R.start << '-' << R.end;
103}
104
Sam McCalld20d7982018-07-09 14:25:59 +0000105json::Value toJSON(const Location &P) {
106 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000107 {"uri", P.uri},
108 {"range", P.range},
109 };
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000110}
111
Sam McCallfffa8222017-12-20 10:26:53 +0000112llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) {
113 return OS << L.range << '@' << L.uri;
114}
115
Sam McCalld20d7982018-07-09 14:25:59 +0000116bool fromJSON(const json::Value &Params, TextDocumentItem &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000117 json::ObjectMapper O(Params);
118 return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&
119 O.map("version", R.version) && O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000120}
121
Sam McCalld20d7982018-07-09 14:25:59 +0000122bool fromJSON(const json::Value &Params, Metadata &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000123 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000124 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000125 return false;
126 O.map("extraFlags", R.extraFlags);
127 return true;
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000128}
129
Sam McCalld20d7982018-07-09 14:25:59 +0000130bool fromJSON(const json::Value &Params, TextEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000131 json::ObjectMapper O(Params);
132 return O && O.map("range", R.range) && O.map("newText", R.newText);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000133}
134
Sam McCalld20d7982018-07-09 14:25:59 +0000135json::Value toJSON(const TextEdit &P) {
136 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000137 {"range", P.range},
138 {"newText", P.newText},
139 };
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000140}
141
Sam McCall034e11a2018-01-25 17:29:17 +0000142llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {
143 OS << TE.range << " => \"";
Jonas Devlieghere1ab6a7a2018-05-31 17:36:31 +0000144 printEscapedString(TE.newText, OS);
Sam McCall034e11a2018-01-25 17:29:17 +0000145 return OS << '"';
146}
147
Sam McCalld20d7982018-07-09 14:25:59 +0000148bool fromJSON(const json::Value &E, TraceLevel &Out) {
149 if (auto S = E.getAsString()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000150 if (*S == "off") {
151 Out = TraceLevel::Off;
152 return true;
153 } else if (*S == "messages") {
154 Out = TraceLevel::Messages;
155 return true;
156 } else if (*S == "verbose") {
157 Out = TraceLevel::Verbose;
158 return true;
159 }
160 }
161 return false;
162}
163
Sam McCalld20d7982018-07-09 14:25:59 +0000164bool fromJSON(const json::Value &Params, CompletionItemClientCapabilities &R) {
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000165 json::ObjectMapper O(Params);
166 if (!O)
167 return false;
168 O.map("snippetSupport", R.snippetSupport);
169 O.map("commitCharacterSupport", R.commitCharacterSupport);
170 return true;
171}
172
Sam McCalld20d7982018-07-09 14:25:59 +0000173bool fromJSON(const json::Value &Params, CompletionClientCapabilities &R) {
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000174 json::ObjectMapper O(Params);
175 if (!O)
176 return false;
177 O.map("dynamicRegistration", R.dynamicRegistration);
178 O.map("completionItem", R.completionItem);
179 O.map("contextSupport", R.contextSupport);
180 return true;
181}
182
Alex Lorenz8626d362018-08-10 17:25:07 +0000183bool fromJSON(const llvm::json::Value &Params,
184 PublishDiagnosticsClientCapabilities &R) {
185 json::ObjectMapper O(Params);
186 if (!O)
187 return false;
188 O.map("clangdFixSupport", R.clangdFixSupport);
Alex Lorenz0ce8a7a2018-08-22 20:30:06 +0000189 O.map("categorySupport", R.categorySupport);
Alex Lorenz8626d362018-08-10 17:25:07 +0000190 return true;
191}
192
Sam McCalld20d7982018-07-09 14:25:59 +0000193bool fromJSON(const json::Value &E, SymbolKind &Out) {
194 if (auto T = E.getAsInteger()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000195 if (*T < static_cast<int>(SymbolKind::File) ||
196 *T > static_cast<int>(SymbolKind::TypeParameter))
197 return false;
198 Out = static_cast<SymbolKind>(*T);
199 return true;
200 }
201 return false;
202}
203
Sam McCalld20d7982018-07-09 14:25:59 +0000204bool fromJSON(const json::Value &E, std::vector<SymbolKind> &Out) {
205 if (auto *A = E.getAsArray()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000206 Out.clear();
207 for (size_t I = 0; I < A->size(); ++I) {
208 SymbolKind KindOut;
209 if (fromJSON((*A)[I], KindOut))
210 Out.push_back(KindOut);
211 }
212 return true;
213 }
214 return false;
215}
216
Sam McCalld20d7982018-07-09 14:25:59 +0000217bool fromJSON(const json::Value &Params, SymbolKindCapabilities &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000218 json::ObjectMapper O(Params);
219 return O && O.map("valueSet", R.valueSet);
220}
221
222SymbolKind adjustKindToCapability(SymbolKind Kind,
Ilya Biryukov74f26552018-07-26 12:05:31 +0000223 SymbolKindBitset &SupportedSymbolKinds) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000224 auto KindVal = static_cast<size_t>(Kind);
Ilya Biryukov74f26552018-07-26 12:05:31 +0000225 if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() &&
226 SupportedSymbolKinds[KindVal])
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000227 return Kind;
228
229 switch (Kind) {
230 // Provide some fall backs for common kinds that are close enough.
231 case SymbolKind::Struct:
232 return SymbolKind::Class;
233 case SymbolKind::EnumMember:
234 return SymbolKind::Enum;
235 default:
236 return SymbolKind::String;
237 }
238}
239
Sam McCalld20d7982018-07-09 14:25:59 +0000240bool fromJSON(const json::Value &Params, WorkspaceSymbolCapabilities &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000241 json::ObjectMapper O(Params);
242 return O && O.map("symbolKind", R.symbolKind);
243}
244
Sam McCalld20d7982018-07-09 14:25:59 +0000245bool fromJSON(const json::Value &Params, WorkspaceClientCapabilities &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000246 json::ObjectMapper O(Params);
247 return O && O.map("symbol", R.symbol);
248}
249
Sam McCalld20d7982018-07-09 14:25:59 +0000250bool fromJSON(const json::Value &Params, TextDocumentClientCapabilities &R) {
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000251 json::ObjectMapper O(Params);
252 if (!O)
253 return false;
254 O.map("completion", R.completion);
Alex Lorenz8626d362018-08-10 17:25:07 +0000255 O.map("publishDiagnostics", R.publishDiagnostics);
Sam McCall20841d42018-10-16 16:29:41 +0000256 if (auto *CodeAction = Params.getAsObject()->getObject("codeAction"))
257 if (CodeAction->getObject("codeActionLiteralSupport"))
258 R.codeActionLiteralSupport = true;
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000259 return true;
260}
261
Sam McCalld20d7982018-07-09 14:25:59 +0000262bool fromJSON(const json::Value &Params, ClientCapabilities &R) {
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000263 json::ObjectMapper O(Params);
264 if (!O)
265 return false;
266 O.map("textDocument", R.textDocument);
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000267 O.map("workspace", R.workspace);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000268 return true;
269}
270
Sam McCalld20d7982018-07-09 14:25:59 +0000271bool fromJSON(const json::Value &Params, InitializeParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000272 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000273 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000274 return false;
Sam McCall38a04912017-11-29 11:36:46 +0000275 // We deliberately don't fail if we can't parse individual fields.
276 // Failing to handle a slightly malformed initialize would be a disaster.
Sam McCallff8b8742017-11-30 21:32:29 +0000277 O.map("processId", R.processId);
278 O.map("rootUri", R.rootUri);
279 O.map("rootPath", R.rootPath);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000280 O.map("capabilities", R.capabilities);
Sam McCallff8b8742017-11-30 21:32:29 +0000281 O.map("trace", R.trace);
Simon Marchi88016782018-08-01 11:28:49 +0000282 O.map("initializationOptions", R.initializationOptions);
Sam McCallff8b8742017-11-30 21:32:29 +0000283 return true;
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000284}
285
Sam McCalld20d7982018-07-09 14:25:59 +0000286bool fromJSON(const json::Value &Params, DidOpenTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000287 json::ObjectMapper O(Params);
288 return O && O.map("textDocument", R.textDocument) &&
289 O.map("metadata", R.metadata);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000290}
291
Sam McCalld20d7982018-07-09 14:25:59 +0000292bool fromJSON(const json::Value &Params, DidCloseTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000293 json::ObjectMapper O(Params);
294 return O && O.map("textDocument", R.textDocument);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000295}
296
Sam McCalld20d7982018-07-09 14:25:59 +0000297bool fromJSON(const json::Value &Params, DidChangeTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000298 json::ObjectMapper O(Params);
299 return O && O.map("textDocument", R.textDocument) &&
Eric Liu51fed182018-02-22 18:40:39 +0000300 O.map("contentChanges", R.contentChanges) &&
301 O.map("wantDiagnostics", R.wantDiagnostics);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000302}
303
Sam McCalld20d7982018-07-09 14:25:59 +0000304bool fromJSON(const json::Value &E, FileChangeType &Out) {
305 if (auto T = E.getAsInteger()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000306 if (*T < static_cast<int>(FileChangeType::Created) ||
307 *T > static_cast<int>(FileChangeType::Deleted))
308 return false;
309 Out = static_cast<FileChangeType>(*T);
310 return true;
311 }
312 return false;
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000313}
314
Sam McCalld20d7982018-07-09 14:25:59 +0000315bool fromJSON(const json::Value &Params, FileEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000316 json::ObjectMapper O(Params);
317 return O && O.map("uri", R.uri) && O.map("type", R.type);
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000318}
319
Sam McCalld20d7982018-07-09 14:25:59 +0000320bool fromJSON(const json::Value &Params, DidChangeWatchedFilesParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000321 json::ObjectMapper O(Params);
322 return O && O.map("changes", R.changes);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000323}
324
Sam McCalld20d7982018-07-09 14:25:59 +0000325bool fromJSON(const json::Value &Params, TextDocumentContentChangeEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000326 json::ObjectMapper O(Params);
Simon Marchi98082622018-03-26 14:41:40 +0000327 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
328 O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000329}
330
Sam McCalld20d7982018-07-09 14:25:59 +0000331bool fromJSON(const json::Value &Params, FormattingOptions &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000332 json::ObjectMapper O(Params);
333 return O && O.map("tabSize", R.tabSize) &&
334 O.map("insertSpaces", R.insertSpaces);
335}
336
Sam McCalld20d7982018-07-09 14:25:59 +0000337json::Value toJSON(const FormattingOptions &P) {
338 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000339 {"tabSize", P.tabSize},
340 {"insertSpaces", P.insertSpaces},
341 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000342}
343
Sam McCalld20d7982018-07-09 14:25:59 +0000344bool fromJSON(const json::Value &Params, DocumentRangeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000345 json::ObjectMapper O(Params);
346 return O && O.map("textDocument", R.textDocument) &&
347 O.map("range", R.range) && O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000348}
349
Sam McCalld20d7982018-07-09 14:25:59 +0000350bool fromJSON(const json::Value &Params, DocumentOnTypeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000351 json::ObjectMapper O(Params);
352 return O && O.map("textDocument", R.textDocument) &&
353 O.map("position", R.position) && O.map("ch", R.ch) &&
354 O.map("options", R.options);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000355}
356
Sam McCalld20d7982018-07-09 14:25:59 +0000357bool fromJSON(const json::Value &Params, DocumentFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000358 json::ObjectMapper O(Params);
359 return O && O.map("textDocument", R.textDocument) &&
360 O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000361}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000362
Sam McCalld20d7982018-07-09 14:25:59 +0000363bool fromJSON(const json::Value &Params, DocumentSymbolParams &R) {
Marc-Andre Laperle1be69702018-07-05 19:35:01 +0000364 json::ObjectMapper O(Params);
365 return O && O.map("textDocument", R.textDocument);
366}
367
Sam McCall20841d42018-10-16 16:29:41 +0000368llvm::json::Value toJSON(const Diagnostic &D) {
369 json::Object Diag{
370 {"range", D.range},
371 {"severity", D.severity},
372 {"message", D.message},
373 };
374 // FIXME: this should be used for publishDiagnostics.
375 // FIXME: send category and fixes when appropriate.
376 return std::move(Diag);
377}
378
Sam McCalld20d7982018-07-09 14:25:59 +0000379bool fromJSON(const json::Value &Params, Diagnostic &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000380 json::ObjectMapper O(Params);
381 if (!O || !O.map("range", R.range) || !O.map("message", R.message))
382 return false;
383 O.map("severity", R.severity);
384 return true;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000385}
386
Sam McCalld20d7982018-07-09 14:25:59 +0000387bool fromJSON(const json::Value &Params, CodeActionContext &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000388 json::ObjectMapper O(Params);
389 return O && O.map("diagnostics", R.diagnostics);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000390}
391
Sam McCall034e11a2018-01-25 17:29:17 +0000392llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
393 OS << D.range << " [";
394 switch (D.severity) {
395 case 1:
396 OS << "error";
397 break;
398 case 2:
399 OS << "warning";
400 break;
401 case 3:
402 OS << "note";
403 break;
404 case 4:
405 OS << "remark";
406 break;
407 default:
408 OS << "diagnostic";
409 break;
410 }
411 return OS << '(' << D.severity << "): " << D.message << "]";
412}
413
Sam McCalld20d7982018-07-09 14:25:59 +0000414bool fromJSON(const json::Value &Params, CodeActionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000415 json::ObjectMapper O(Params);
416 return O && O.map("textDocument", R.textDocument) &&
417 O.map("range", R.range) && O.map("context", R.context);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000418}
419
Sam McCalld20d7982018-07-09 14:25:59 +0000420bool fromJSON(const json::Value &Params, WorkspaceEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000421 json::ObjectMapper O(Params);
422 return O && O.map("changes", R.changes);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000423}
424
Benjamin Kramerb4c5c2d2017-12-28 15:03:02 +0000425const llvm::StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000426 "clangd.applyFix";
Sam McCalld20d7982018-07-09 14:25:59 +0000427bool fromJSON(const json::Value &Params, ExecuteCommandParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000428 json::ObjectMapper O(Params);
429 if (!O || !O.map("command", R.command))
430 return false;
Sam McCallec109022017-11-28 09:37:43 +0000431
Sam McCalld20d7982018-07-09 14:25:59 +0000432 auto Args = Params.getAsObject()->getArray("arguments");
Sam McCallff8b8742017-11-30 21:32:29 +0000433 if (R.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
434 return Args && Args->size() == 1 &&
435 fromJSON(Args->front(), R.workspaceEdit);
436 }
437 return false; // Unrecognized command.
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000438}
439
Sam McCalld20d7982018-07-09 14:25:59 +0000440json::Value toJSON(const SymbolInformation &P) {
441 return json::Object{
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000442 {"name", P.name},
443 {"kind", static_cast<int>(P.kind)},
444 {"location", P.location},
445 {"containerName", P.containerName},
446 };
447}
448
449llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
450 const SymbolInformation &SI) {
451 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
452 return O;
453}
454
Sam McCalld20d7982018-07-09 14:25:59 +0000455bool fromJSON(const json::Value &Params, WorkspaceSymbolParams &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000456 json::ObjectMapper O(Params);
457 return O && O.map("query", R.query);
458}
459
Sam McCalld20d7982018-07-09 14:25:59 +0000460json::Value toJSON(const Command &C) {
461 auto Cmd = json::Object{{"title", C.title}, {"command", C.command}};
Eric Liuc5105f92018-02-16 14:15:55 +0000462 if (C.workspaceEdit)
463 Cmd["arguments"] = {*C.workspaceEdit};
Eric Liuc5105f92018-02-16 14:15:55 +0000464 return std::move(Cmd);
465}
466
Sam McCall20841d42018-10-16 16:29:41 +0000467const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";
468
469llvm::json::Value toJSON(const CodeAction &CA) {
470 auto CodeAction = json::Object{{"title", CA.title}};
471 if (CA.kind)
472 CodeAction["kind"] = *CA.kind;
473 if (CA.diagnostics)
474 CodeAction["diagnostics"] = json::Array(*CA.diagnostics);
475 if (CA.edit)
476 CodeAction["edit"] = *CA.edit;
477 if (CA.command)
478 CodeAction["command"] = *CA.command;
479 return std::move(CodeAction);
480}
481
Sam McCalld20d7982018-07-09 14:25:59 +0000482json::Value toJSON(const WorkspaceEdit &WE) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000483 if (!WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000484 return json::Object{};
485 json::Object FileChanges;
Sam McCalldd0566b2017-11-06 15:40:30 +0000486 for (auto &Change : *WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000487 FileChanges[Change.first] = json::Array(Change.second);
488 return json::Object{{"changes", std::move(FileChanges)}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000489}
490
Sam McCalld20d7982018-07-09 14:25:59 +0000491json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
492 return json::Object{{"edit", Params.edit}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000493}
494
Sam McCalld20d7982018-07-09 14:25:59 +0000495bool fromJSON(const json::Value &Params, TextDocumentPositionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000496 json::ObjectMapper O(Params);
497 return O && O.map("textDocument", R.textDocument) &&
498 O.map("position", R.position);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000499}
500
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000501static StringRef toTextKind(MarkupKind Kind) {
502 switch (Kind) {
503 case MarkupKind::PlainText:
504 return "plaintext";
505 case MarkupKind::Markdown:
506 return "markdown";
507 }
508 llvm_unreachable("Invalid MarkupKind");
509}
510
Sam McCalld20d7982018-07-09 14:25:59 +0000511json::Value toJSON(const MarkupContent &MC) {
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000512 if (MC.value.empty())
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000513 return nullptr;
514
Sam McCalld20d7982018-07-09 14:25:59 +0000515 return json::Object{
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000516 {"kind", toTextKind(MC.kind)},
517 {"value", MC.value},
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000518 };
519}
520
Sam McCalld20d7982018-07-09 14:25:59 +0000521json::Value toJSON(const Hover &H) {
522 json::Object Result{{"contents", toJSON(H.contents)}};
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000523
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000524 if (H.range.hasValue())
525 Result["range"] = toJSON(*H.range);
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000526
527 return std::move(Result);
528}
529
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000530bool fromJSON(const json::Value &E, CompletionItemKind &Out) {
531 if (auto T = E.getAsInteger()) {
532 if (*T < static_cast<int>(CompletionItemKind::Text) ||
533 *T > static_cast<int>(CompletionItemKind::TypeParameter))
534 return false;
535 Out = static_cast<CompletionItemKind>(*T);
536 return true;
537 }
538 return false;
539}
540
541CompletionItemKind
542adjustKindToCapability(CompletionItemKind Kind,
543 CompletionItemKindBitset &supportedCompletionItemKinds) {
544 auto KindVal = static_cast<size_t>(Kind);
545 if (KindVal >= CompletionItemKindMin &&
546 KindVal <= supportedCompletionItemKinds.size() &&
547 supportedCompletionItemKinds[KindVal])
548 return Kind;
549
550 switch (Kind) {
551 // Provide some fall backs for common kinds that are close enough.
552 case CompletionItemKind::Folder:
553 return CompletionItemKind::File;
554 case CompletionItemKind::EnumMember:
555 return CompletionItemKind::Enum;
556 case CompletionItemKind::Struct:
557 return CompletionItemKind::Class;
558 default:
559 return CompletionItemKind::Text;
560 }
561}
562
563bool fromJSON(const json::Value &E, std::vector<CompletionItemKind> &Out) {
564 if (auto *A = E.getAsArray()) {
565 Out.clear();
566 for (size_t I = 0; I < A->size(); ++I) {
567 CompletionItemKind KindOut;
568 if (fromJSON((*A)[I], KindOut))
569 Out.push_back(KindOut);
570 }
571 return true;
572 }
573 return false;
574}
575
576bool fromJSON(const json::Value &Params, CompletionItemKindCapabilities &R) {
577 json::ObjectMapper O(Params);
578 return O && O.map("valueSet", R.valueSet);
579}
580
Sam McCalld20d7982018-07-09 14:25:59 +0000581json::Value toJSON(const CompletionItem &CI) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000582 assert(!CI.label.empty() && "completion item label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000583 json::Object Result{{"label", CI.label}};
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000584 if (CI.kind != CompletionItemKind::Missing)
Sam McCalldd0566b2017-11-06 15:40:30 +0000585 Result["kind"] = static_cast<int>(CI.kind);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000586 if (!CI.detail.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000587 Result["detail"] = CI.detail;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000588 if (!CI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000589 Result["documentation"] = CI.documentation;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000590 if (!CI.sortText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000591 Result["sortText"] = CI.sortText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000592 if (!CI.filterText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000593 Result["filterText"] = CI.filterText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000594 if (!CI.insertText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000595 Result["insertText"] = CI.insertText;
596 if (CI.insertTextFormat != InsertTextFormat::Missing)
597 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000598 if (CI.textEdit)
Sam McCalldd0566b2017-11-06 15:40:30 +0000599 Result["textEdit"] = *CI.textEdit;
600 if (!CI.additionalTextEdits.empty())
Sam McCalld20d7982018-07-09 14:25:59 +0000601 Result["additionalTextEdits"] = json::Array(CI.additionalTextEdits);
Eric Liu6df66002018-09-06 18:52:26 +0000602 if (CI.deprecated)
603 Result["deprecated"] = CI.deprecated;
Sam McCalldd0566b2017-11-06 15:40:30 +0000604 return std::move(Result);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000605}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000606
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000607llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) {
608 O << I.label << " - " << toJSON(I);
609 return O;
610}
611
Sam McCallff8b8742017-11-30 21:32:29 +0000612bool operator<(const CompletionItem &L, const CompletionItem &R) {
Sam McCallc78ccbd2017-11-08 07:44:12 +0000613 return (L.sortText.empty() ? L.label : L.sortText) <
614 (R.sortText.empty() ? R.label : R.sortText);
615}
616
Sam McCalld20d7982018-07-09 14:25:59 +0000617json::Value toJSON(const CompletionList &L) {
618 return json::Object{
Sam McCalla40371b2017-11-15 09:16:29 +0000619 {"isIncomplete", L.isIncomplete},
Sam McCalld20d7982018-07-09 14:25:59 +0000620 {"items", json::Array(L.items)},
Sam McCalla40371b2017-11-15 09:16:29 +0000621 };
622}
623
Sam McCalld20d7982018-07-09 14:25:59 +0000624json::Value toJSON(const ParameterInformation &PI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000625 assert(!PI.label.empty() && "parameter information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000626 json::Object Result{{"label", PI.label}};
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000627 if (!PI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000628 Result["documentation"] = PI.documentation;
629 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000630}
631
Sam McCalld20d7982018-07-09 14:25:59 +0000632json::Value toJSON(const SignatureInformation &SI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000633 assert(!SI.label.empty() && "signature information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000634 json::Object Result{
Sam McCalldd0566b2017-11-06 15:40:30 +0000635 {"label", SI.label},
Sam McCalld20d7982018-07-09 14:25:59 +0000636 {"parameters", json::Array(SI.parameters)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000637 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000638 if (!SI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000639 Result["documentation"] = SI.documentation;
640 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000641}
642
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000643llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
644 const SignatureInformation &I) {
645 O << I.label << " - " << toJSON(I);
646 return O;
647}
648
Sam McCalld20d7982018-07-09 14:25:59 +0000649json::Value toJSON(const SignatureHelp &SH) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000650 assert(SH.activeSignature >= 0 &&
651 "Unexpected negative value for number of active signatures.");
652 assert(SH.activeParameter >= 0 &&
653 "Unexpected negative value for active parameter index");
Sam McCalld20d7982018-07-09 14:25:59 +0000654 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000655 {"activeSignature", SH.activeSignature},
656 {"activeParameter", SH.activeParameter},
Sam McCalld20d7982018-07-09 14:25:59 +0000657 {"signatures", json::Array(SH.signatures)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000658 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000659}
Haojian Wu345099c2017-11-09 11:30:04 +0000660
Sam McCalld20d7982018-07-09 14:25:59 +0000661bool fromJSON(const json::Value &Params, RenameParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000662 json::ObjectMapper O(Params);
663 return O && O.map("textDocument", R.textDocument) &&
664 O.map("position", R.position) && O.map("newName", R.newName);
Haojian Wu345099c2017-11-09 11:30:04 +0000665}
Sam McCallff8b8742017-11-30 21:32:29 +0000666
Sam McCalld20d7982018-07-09 14:25:59 +0000667json::Value toJSON(const DocumentHighlight &DH) {
668 return json::Object{
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000669 {"range", toJSON(DH.range)},
670 {"kind", static_cast<int>(DH.kind)},
671 };
672}
673
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000674llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
675 const DocumentHighlight &V) {
676 O << V.range;
677 if (V.kind == DocumentHighlightKind::Read)
678 O << "(r)";
679 if (V.kind == DocumentHighlightKind::Write)
680 O << "(w)";
681 return O;
682}
683
Sam McCalld20d7982018-07-09 14:25:59 +0000684bool fromJSON(const json::Value &Params, DidChangeConfigurationParams &CCP) {
Simon Marchi5178f922018-02-22 14:00:39 +0000685 json::ObjectMapper O(Params);
686 return O && O.map("settings", CCP.settings);
687}
688
Alex Lorenzf8087862018-08-01 17:39:29 +0000689bool fromJSON(const llvm::json::Value &Params,
690 ClangdCompileCommand &CDbUpdate) {
691 json::ObjectMapper O(Params);
692 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&
693 O.map("compilationCommand", CDbUpdate.compilationCommand);
694}
695
Sam McCalld20d7982018-07-09 14:25:59 +0000696bool fromJSON(const json::Value &Params,
697 ClangdConfigurationParamsChange &CCPC) {
Simon Marchi5178f922018-02-22 14:00:39 +0000698 json::ObjectMapper O(Params);
Simon Marchiabeed662018-10-16 15:55:03 +0000699 return O &&
Alex Lorenzf8087862018-08-01 17:39:29 +0000700 O.map("compilationDatabaseChanges", CCPC.compilationDatabaseChanges);
Simon Marchi5178f922018-02-22 14:00:39 +0000701}
702
Simon Marchiabeed662018-10-16 15:55:03 +0000703bool fromJSON(const json::Value &Params, ClangdInitializationOptions &Opts) {
704 if (!fromJSON(Params, Opts.ParamsChange)) {
705 return false;
706 }
707
708 json::ObjectMapper O(Params);
709 return O && O.map("compilationDatabasePath", Opts.compilationDatabasePath);
710}
711
Sam McCall1ad142f2018-09-05 11:53:07 +0000712bool fromJSON(const json::Value &Params, ReferenceParams &R) {
713 TextDocumentPositionParams &Base = R;
714 return fromJSON(Params, Base);
715}
716
Sam McCallff8b8742017-11-30 21:32:29 +0000717} // namespace clangd
718} // namespace clang