blob: 64f6bd60c0237fbb7dc04be28ced0ab0a3f1b04e [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 McCall38a04912017-11-29 11:36:46 +000026
Ilya Biryukov7d60d202018-02-16 12:20:47 +000027URIForFile::URIForFile(std::string AbsPath) {
28 assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative");
29 File = std::move(AbsPath);
30}
31
Eric Liu78ed91a72018-01-29 15:37:46 +000032bool fromJSON(const json::Expr &E, URIForFile &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000033 if (auto S = E.asString()) {
Eric Liu78ed91a72018-01-29 15:37:46 +000034 auto U = URI::parse(*S);
35 if (!U) {
Sam McCalld1a7a372018-01-31 13:40:48 +000036 log("Failed to parse URI " + *S + ": " + llvm::toString(U.takeError()));
Eric Liu78ed91a72018-01-29 15:37:46 +000037 return false;
38 }
Eric Liu5740ff52018-01-31 16:26:27 +000039 if (U->scheme() != "file" && U->scheme() != "test") {
Sam McCalld1a7a372018-01-31 13:40:48 +000040 log("Clangd only supports 'file' URI scheme for workspace files: " + *S);
Eric Liu78ed91a72018-01-29 15:37:46 +000041 return false;
42 }
Sam McCall41d21522018-01-30 11:23:11 +000043 auto Path = URI::resolve(*U);
44 if (!Path) {
Sam McCalld1a7a372018-01-31 13:40:48 +000045 log(llvm::toString(Path.takeError()));
Sam McCall41d21522018-01-30 11:23:11 +000046 return false;
47 }
Ilya Biryukov7d60d202018-02-16 12:20:47 +000048 R = URIForFile(*Path);
Sam McCallff8b8742017-11-30 21:32:29 +000049 return true;
50 }
51 return false;
Sam McCall38a04912017-11-29 11:36:46 +000052}
53
Ilya Biryukov7d60d202018-02-16 12:20:47 +000054json::Expr toJSON(const URIForFile &U) { return U.uri(); }
Krasimir Georgiev50117372017-04-07 11:03:26 +000055
Eric Liu78ed91a72018-01-29 15:37:46 +000056llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) {
57 return OS << U.uri();
Sam McCallfffa8222017-12-20 10:26:53 +000058}
59
Eric Liuc5105f92018-02-16 14:15:55 +000060json::Expr toJSON(const TextDocumentIdentifier &R) {
61 return json::obj{{"uri", R.uri}};
62}
63
Sam McCallff8b8742017-11-30 21:32:29 +000064bool fromJSON(const json::Expr &Params, TextDocumentIdentifier &R) {
65 json::ObjectMapper O(Params);
66 return O && O.map("uri", R.uri);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000067}
68
Sam McCallff8b8742017-11-30 21:32:29 +000069bool fromJSON(const json::Expr &Params, Position &R) {
70 json::ObjectMapper O(Params);
71 return O && O.map("line", R.line) && O.map("character", R.character);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000072}
73
Sam McCallff8b8742017-11-30 21:32:29 +000074json::Expr toJSON(const Position &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +000075 return json::obj{
76 {"line", P.line},
77 {"character", P.character},
78 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000079}
80
Sam McCallfffa8222017-12-20 10:26:53 +000081llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) {
82 return OS << P.line << ':' << P.character;
83}
84
Sam McCallff8b8742017-11-30 21:32:29 +000085bool fromJSON(const json::Expr &Params, Range &R) {
86 json::ObjectMapper O(Params);
87 return O && O.map("start", R.start) && O.map("end", R.end);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000088}
89
Sam McCallff8b8742017-11-30 21:32:29 +000090json::Expr toJSON(const Range &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +000091 return json::obj{
92 {"start", P.start},
93 {"end", P.end},
94 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000095}
96
Sam McCallfffa8222017-12-20 10:26:53 +000097llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) {
98 return OS << R.start << '-' << R.end;
99}
100
Sam McCallff8b8742017-11-30 21:32:29 +0000101json::Expr toJSON(const Location &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000102 return json::obj{
103 {"uri", P.uri},
104 {"range", P.range},
105 };
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000106}
107
Sam McCallfffa8222017-12-20 10:26:53 +0000108llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) {
109 return OS << L.range << '@' << L.uri;
110}
111
Sam McCallff8b8742017-11-30 21:32:29 +0000112bool fromJSON(const json::Expr &Params, TextDocumentItem &R) {
113 json::ObjectMapper O(Params);
114 return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&
115 O.map("version", R.version) && O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000116}
117
Sam McCallff8b8742017-11-30 21:32:29 +0000118bool fromJSON(const json::Expr &Params, Metadata &R) {
119 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000120 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000121 return false;
122 O.map("extraFlags", R.extraFlags);
123 return true;
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000124}
125
Sam McCallff8b8742017-11-30 21:32:29 +0000126bool fromJSON(const json::Expr &Params, TextEdit &R) {
127 json::ObjectMapper O(Params);
128 return O && O.map("range", R.range) && O.map("newText", R.newText);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000129}
130
Sam McCallff8b8742017-11-30 21:32:29 +0000131json::Expr toJSON(const TextEdit &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000132 return json::obj{
133 {"range", P.range},
134 {"newText", P.newText},
135 };
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000136}
137
Sam McCall034e11a2018-01-25 17:29:17 +0000138llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {
139 OS << TE.range << " => \"";
Jonas Devlieghere1ab6a7a2018-05-31 17:36:31 +0000140 printEscapedString(TE.newText, OS);
Sam McCall034e11a2018-01-25 17:29:17 +0000141 return OS << '"';
142}
143
Sam McCallff8b8742017-11-30 21:32:29 +0000144bool fromJSON(const json::Expr &E, TraceLevel &Out) {
145 if (auto S = E.asString()) {
146 if (*S == "off") {
147 Out = TraceLevel::Off;
148 return true;
149 } else if (*S == "messages") {
150 Out = TraceLevel::Messages;
151 return true;
152 } else if (*S == "verbose") {
153 Out = TraceLevel::Verbose;
154 return true;
155 }
156 }
157 return false;
158}
159
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000160bool fromJSON(const json::Expr &Params, CompletionItemClientCapabilities &R) {
161 json::ObjectMapper O(Params);
162 if (!O)
163 return false;
164 O.map("snippetSupport", R.snippetSupport);
165 O.map("commitCharacterSupport", R.commitCharacterSupport);
166 return true;
167}
168
169bool fromJSON(const json::Expr &Params, CompletionClientCapabilities &R) {
170 json::ObjectMapper O(Params);
171 if (!O)
172 return false;
173 O.map("dynamicRegistration", R.dynamicRegistration);
174 O.map("completionItem", R.completionItem);
175 O.map("contextSupport", R.contextSupport);
176 return true;
177}
178
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000179bool fromJSON(const json::Expr &E, SymbolKind &Out) {
180 if (auto T = E.asInteger()) {
181 if (*T < static_cast<int>(SymbolKind::File) ||
182 *T > static_cast<int>(SymbolKind::TypeParameter))
183 return false;
184 Out = static_cast<SymbolKind>(*T);
185 return true;
186 }
187 return false;
188}
189
190bool fromJSON(const json::Expr &E, std::vector<SymbolKind> &Out) {
191 if (auto *A = E.asArray()) {
192 Out.clear();
193 for (size_t I = 0; I < A->size(); ++I) {
194 SymbolKind KindOut;
195 if (fromJSON((*A)[I], KindOut))
196 Out.push_back(KindOut);
197 }
198 return true;
199 }
200 return false;
201}
202
203bool fromJSON(const json::Expr &Params, SymbolKindCapabilities &R) {
204 json::ObjectMapper O(Params);
205 return O && O.map("valueSet", R.valueSet);
206}
207
208SymbolKind adjustKindToCapability(SymbolKind Kind,
209 SymbolKindBitset &supportedSymbolKinds) {
210 auto KindVal = static_cast<size_t>(Kind);
211 if (KindVal >= SymbolKindMin && KindVal <= supportedSymbolKinds.size() &&
212 supportedSymbolKinds[KindVal])
213 return Kind;
214
215 switch (Kind) {
216 // Provide some fall backs for common kinds that are close enough.
217 case SymbolKind::Struct:
218 return SymbolKind::Class;
219 case SymbolKind::EnumMember:
220 return SymbolKind::Enum;
221 default:
222 return SymbolKind::String;
223 }
224}
225
226bool fromJSON(const json::Expr &Params, WorkspaceSymbolCapabilities &R) {
227 json::ObjectMapper O(Params);
228 return O && O.map("symbolKind", R.symbolKind);
229}
230
231bool fromJSON(const json::Expr &Params, WorkspaceClientCapabilities &R) {
232 json::ObjectMapper O(Params);
233 return O && O.map("symbol", R.symbol);
234}
235
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000236bool fromJSON(const json::Expr &Params, TextDocumentClientCapabilities &R) {
237 json::ObjectMapper O(Params);
238 if (!O)
239 return false;
240 O.map("completion", R.completion);
241 return true;
242}
243
244bool fromJSON(const json::Expr &Params, ClientCapabilities &R) {
245 json::ObjectMapper O(Params);
246 if (!O)
247 return false;
248 O.map("textDocument", R.textDocument);
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000249 O.map("workspace", R.workspace);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000250 return true;
251}
252
Sam McCallff8b8742017-11-30 21:32:29 +0000253bool fromJSON(const json::Expr &Params, InitializeParams &R) {
254 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000255 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000256 return false;
Sam McCall38a04912017-11-29 11:36:46 +0000257 // We deliberately don't fail if we can't parse individual fields.
258 // Failing to handle a slightly malformed initialize would be a disaster.
Sam McCallff8b8742017-11-30 21:32:29 +0000259 O.map("processId", R.processId);
260 O.map("rootUri", R.rootUri);
261 O.map("rootPath", R.rootPath);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000262 O.map("capabilities", R.capabilities);
Sam McCallff8b8742017-11-30 21:32:29 +0000263 O.map("trace", R.trace);
Sam McCallec109022017-11-28 09:37:43 +0000264 // initializationOptions, capabilities unused
Sam McCallff8b8742017-11-30 21:32:29 +0000265 return true;
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000266}
267
Sam McCallff8b8742017-11-30 21:32:29 +0000268bool fromJSON(const json::Expr &Params, DidOpenTextDocumentParams &R) {
269 json::ObjectMapper O(Params);
270 return O && O.map("textDocument", R.textDocument) &&
271 O.map("metadata", R.metadata);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000272}
273
Sam McCallff8b8742017-11-30 21:32:29 +0000274bool fromJSON(const json::Expr &Params, DidCloseTextDocumentParams &R) {
275 json::ObjectMapper O(Params);
276 return O && O.map("textDocument", R.textDocument);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000277}
278
Sam McCallff8b8742017-11-30 21:32:29 +0000279bool fromJSON(const json::Expr &Params, DidChangeTextDocumentParams &R) {
280 json::ObjectMapper O(Params);
281 return O && O.map("textDocument", R.textDocument) &&
Eric Liu51fed182018-02-22 18:40:39 +0000282 O.map("contentChanges", R.contentChanges) &&
283 O.map("wantDiagnostics", R.wantDiagnostics);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000284}
285
Sam McCallff8b8742017-11-30 21:32:29 +0000286bool fromJSON(const json::Expr &E, FileChangeType &Out) {
287 if (auto T = E.asInteger()) {
288 if (*T < static_cast<int>(FileChangeType::Created) ||
289 *T > static_cast<int>(FileChangeType::Deleted))
290 return false;
291 Out = static_cast<FileChangeType>(*T);
292 return true;
293 }
294 return false;
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000295}
296
Sam McCallff8b8742017-11-30 21:32:29 +0000297bool fromJSON(const json::Expr &Params, FileEvent &R) {
298 json::ObjectMapper O(Params);
299 return O && O.map("uri", R.uri) && O.map("type", R.type);
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000300}
301
Sam McCallff8b8742017-11-30 21:32:29 +0000302bool fromJSON(const json::Expr &Params, DidChangeWatchedFilesParams &R) {
303 json::ObjectMapper O(Params);
304 return O && O.map("changes", R.changes);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000305}
306
Sam McCallff8b8742017-11-30 21:32:29 +0000307bool fromJSON(const json::Expr &Params, TextDocumentContentChangeEvent &R) {
308 json::ObjectMapper O(Params);
Simon Marchi98082622018-03-26 14:41:40 +0000309 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
310 O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000311}
312
Sam McCallff8b8742017-11-30 21:32:29 +0000313bool fromJSON(const json::Expr &Params, FormattingOptions &R) {
314 json::ObjectMapper O(Params);
315 return O && O.map("tabSize", R.tabSize) &&
316 O.map("insertSpaces", R.insertSpaces);
317}
318
319json::Expr toJSON(const FormattingOptions &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000320 return json::obj{
321 {"tabSize", P.tabSize},
322 {"insertSpaces", P.insertSpaces},
323 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000324}
325
Sam McCallff8b8742017-11-30 21:32:29 +0000326bool fromJSON(const json::Expr &Params, DocumentRangeFormattingParams &R) {
327 json::ObjectMapper O(Params);
328 return O && O.map("textDocument", R.textDocument) &&
329 O.map("range", R.range) && O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000330}
331
Sam McCallff8b8742017-11-30 21:32:29 +0000332bool fromJSON(const json::Expr &Params, DocumentOnTypeFormattingParams &R) {
333 json::ObjectMapper O(Params);
334 return O && O.map("textDocument", R.textDocument) &&
335 O.map("position", R.position) && O.map("ch", R.ch) &&
336 O.map("options", R.options);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000337}
338
Sam McCallff8b8742017-11-30 21:32:29 +0000339bool fromJSON(const json::Expr &Params, DocumentFormattingParams &R) {
340 json::ObjectMapper O(Params);
341 return O && O.map("textDocument", R.textDocument) &&
342 O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000343}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000344
Marc-Andre Laperle1be69702018-07-05 19:35:01 +0000345bool fromJSON(const json::Expr &Params, DocumentSymbolParams &R) {
346 json::ObjectMapper O(Params);
347 return O && O.map("textDocument", R.textDocument);
348}
349
Sam McCallff8b8742017-11-30 21:32:29 +0000350bool fromJSON(const json::Expr &Params, Diagnostic &R) {
351 json::ObjectMapper O(Params);
352 if (!O || !O.map("range", R.range) || !O.map("message", R.message))
353 return false;
354 O.map("severity", R.severity);
355 return true;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000356}
357
Sam McCallff8b8742017-11-30 21:32:29 +0000358bool fromJSON(const json::Expr &Params, CodeActionContext &R) {
359 json::ObjectMapper O(Params);
360 return O && O.map("diagnostics", R.diagnostics);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000361}
362
Sam McCall034e11a2018-01-25 17:29:17 +0000363llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
364 OS << D.range << " [";
365 switch (D.severity) {
366 case 1:
367 OS << "error";
368 break;
369 case 2:
370 OS << "warning";
371 break;
372 case 3:
373 OS << "note";
374 break;
375 case 4:
376 OS << "remark";
377 break;
378 default:
379 OS << "diagnostic";
380 break;
381 }
382 return OS << '(' << D.severity << "): " << D.message << "]";
383}
384
Sam McCallff8b8742017-11-30 21:32:29 +0000385bool fromJSON(const json::Expr &Params, CodeActionParams &R) {
386 json::ObjectMapper O(Params);
387 return O && O.map("textDocument", R.textDocument) &&
388 O.map("range", R.range) && O.map("context", R.context);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000389}
390
Sam McCallff8b8742017-11-30 21:32:29 +0000391bool fromJSON(const json::Expr &Params, WorkspaceEdit &R) {
392 json::ObjectMapper O(Params);
393 return O && O.map("changes", R.changes);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000394}
395
Benjamin Kramerb4c5c2d2017-12-28 15:03:02 +0000396const llvm::StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000397 "clangd.applyFix";
Sam McCallff8b8742017-11-30 21:32:29 +0000398bool fromJSON(const json::Expr &Params, ExecuteCommandParams &R) {
399 json::ObjectMapper O(Params);
400 if (!O || !O.map("command", R.command))
401 return false;
Sam McCallec109022017-11-28 09:37:43 +0000402
Sam McCallff8b8742017-11-30 21:32:29 +0000403 auto Args = Params.asObject()->getArray("arguments");
404 if (R.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
405 return Args && Args->size() == 1 &&
406 fromJSON(Args->front(), R.workspaceEdit);
407 }
408 return false; // Unrecognized command.
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000409}
410
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000411json::Expr toJSON(const SymbolInformation &P) {
412 return json::obj{
413 {"name", P.name},
414 {"kind", static_cast<int>(P.kind)},
415 {"location", P.location},
416 {"containerName", P.containerName},
417 };
418}
419
420llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
421 const SymbolInformation &SI) {
422 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
423 return O;
424}
425
426bool fromJSON(const json::Expr &Params, WorkspaceSymbolParams &R) {
427 json::ObjectMapper O(Params);
428 return O && O.map("query", R.query);
429}
430
Eric Liuc5105f92018-02-16 14:15:55 +0000431json::Expr toJSON(const Command &C) {
432 auto Cmd = json::obj{{"title", C.title}, {"command", C.command}};
433 if (C.workspaceEdit)
434 Cmd["arguments"] = {*C.workspaceEdit};
Eric Liuc5105f92018-02-16 14:15:55 +0000435 return std::move(Cmd);
436}
437
Sam McCallff8b8742017-11-30 21:32:29 +0000438json::Expr toJSON(const WorkspaceEdit &WE) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000439 if (!WE.changes)
440 return json::obj{};
441 json::obj FileChanges;
442 for (auto &Change : *WE.changes)
443 FileChanges[Change.first] = json::ary(Change.second);
444 return json::obj{{"changes", std::move(FileChanges)}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000445}
446
Sam McCallff8b8742017-11-30 21:32:29 +0000447json::Expr toJSON(const ApplyWorkspaceEditParams &Params) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000448 return json::obj{{"edit", Params.edit}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000449}
450
Sam McCallff8b8742017-11-30 21:32:29 +0000451bool fromJSON(const json::Expr &Params, TextDocumentPositionParams &R) {
452 json::ObjectMapper O(Params);
453 return O && O.map("textDocument", R.textDocument) &&
454 O.map("position", R.position);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000455}
456
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000457static StringRef toTextKind(MarkupKind Kind) {
458 switch (Kind) {
459 case MarkupKind::PlainText:
460 return "plaintext";
461 case MarkupKind::Markdown:
462 return "markdown";
463 }
464 llvm_unreachable("Invalid MarkupKind");
465}
466
467json::Expr toJSON(const MarkupContent &MC) {
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000468 if (MC.value.empty())
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000469 return nullptr;
470
471 return json::obj{
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000472 {"kind", toTextKind(MC.kind)},
473 {"value", MC.value},
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000474 };
475}
476
477json::Expr toJSON(const Hover &H) {
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000478 json::obj Result{{"contents", toJSON(H.contents)}};
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000479
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000480 if (H.range.hasValue())
481 Result["range"] = toJSON(*H.range);
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000482
483 return std::move(Result);
484}
485
Sam McCallff8b8742017-11-30 21:32:29 +0000486json::Expr toJSON(const CompletionItem &CI) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000487 assert(!CI.label.empty() && "completion item label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +0000488 json::obj Result{{"label", CI.label}};
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000489 if (CI.kind != CompletionItemKind::Missing)
Sam McCalldd0566b2017-11-06 15:40:30 +0000490 Result["kind"] = static_cast<int>(CI.kind);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000491 if (!CI.detail.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000492 Result["detail"] = CI.detail;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000493 if (!CI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000494 Result["documentation"] = CI.documentation;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000495 if (!CI.sortText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000496 Result["sortText"] = CI.sortText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000497 if (!CI.filterText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000498 Result["filterText"] = CI.filterText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000499 if (!CI.insertText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000500 Result["insertText"] = CI.insertText;
501 if (CI.insertTextFormat != InsertTextFormat::Missing)
502 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000503 if (CI.textEdit)
Sam McCalldd0566b2017-11-06 15:40:30 +0000504 Result["textEdit"] = *CI.textEdit;
505 if (!CI.additionalTextEdits.empty())
506 Result["additionalTextEdits"] = json::ary(CI.additionalTextEdits);
507 return std::move(Result);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000508}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000509
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000510llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) {
511 O << I.label << " - " << toJSON(I);
512 return O;
513}
514
Sam McCallff8b8742017-11-30 21:32:29 +0000515bool operator<(const CompletionItem &L, const CompletionItem &R) {
Sam McCallc78ccbd2017-11-08 07:44:12 +0000516 return (L.sortText.empty() ? L.label : L.sortText) <
517 (R.sortText.empty() ? R.label : R.sortText);
518}
519
Sam McCallff8b8742017-11-30 21:32:29 +0000520json::Expr toJSON(const CompletionList &L) {
Sam McCalla40371b2017-11-15 09:16:29 +0000521 return json::obj{
522 {"isIncomplete", L.isIncomplete},
523 {"items", json::ary(L.items)},
524 };
525}
526
Sam McCallff8b8742017-11-30 21:32:29 +0000527json::Expr toJSON(const ParameterInformation &PI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000528 assert(!PI.label.empty() && "parameter information label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +0000529 json::obj Result{{"label", PI.label}};
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000530 if (!PI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000531 Result["documentation"] = PI.documentation;
532 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000533}
534
Sam McCallff8b8742017-11-30 21:32:29 +0000535json::Expr toJSON(const SignatureInformation &SI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000536 assert(!SI.label.empty() && "signature information label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +0000537 json::obj Result{
538 {"label", SI.label},
539 {"parameters", json::ary(SI.parameters)},
540 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000541 if (!SI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000542 Result["documentation"] = SI.documentation;
543 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000544}
545
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000546llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
547 const SignatureInformation &I) {
548 O << I.label << " - " << toJSON(I);
549 return O;
550}
551
Sam McCallff8b8742017-11-30 21:32:29 +0000552json::Expr toJSON(const SignatureHelp &SH) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000553 assert(SH.activeSignature >= 0 &&
554 "Unexpected negative value for number of active signatures.");
555 assert(SH.activeParameter >= 0 &&
556 "Unexpected negative value for active parameter index");
Sam McCalldd0566b2017-11-06 15:40:30 +0000557 return json::obj{
558 {"activeSignature", SH.activeSignature},
559 {"activeParameter", SH.activeParameter},
560 {"signatures", json::ary(SH.signatures)},
561 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000562}
Haojian Wu345099c2017-11-09 11:30:04 +0000563
Sam McCallff8b8742017-11-30 21:32:29 +0000564bool fromJSON(const json::Expr &Params, RenameParams &R) {
565 json::ObjectMapper O(Params);
566 return O && O.map("textDocument", R.textDocument) &&
567 O.map("position", R.position) && O.map("newName", R.newName);
Haojian Wu345099c2017-11-09 11:30:04 +0000568}
Sam McCallff8b8742017-11-30 21:32:29 +0000569
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000570json::Expr toJSON(const DocumentHighlight &DH) {
571 return json::obj{
572 {"range", toJSON(DH.range)},
573 {"kind", static_cast<int>(DH.kind)},
574 };
575}
576
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000577llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
578 const DocumentHighlight &V) {
579 O << V.range;
580 if (V.kind == DocumentHighlightKind::Read)
581 O << "(r)";
582 if (V.kind == DocumentHighlightKind::Write)
583 O << "(w)";
584 return O;
585}
586
Simon Marchi5178f922018-02-22 14:00:39 +0000587bool fromJSON(const json::Expr &Params, DidChangeConfigurationParams &CCP) {
588 json::ObjectMapper O(Params);
589 return O && O.map("settings", CCP.settings);
590}
591
592bool fromJSON(const json::Expr &Params, ClangdConfigurationParamsChange &CCPC) {
593 json::ObjectMapper O(Params);
594 return O && O.map("compilationDatabasePath", CCPC.compilationDatabasePath);
595}
596
Sam McCallff8b8742017-11-30 21:32:29 +0000597} // namespace clangd
598} // namespace clang