blob: 42093797bd8bda7f9b818a4cadbac47c838ebe8d [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
Ilya Biryukov7d60d202018-02-16 12:20:47 +000028URIForFile::URIForFile(std::string AbsPath) {
29 assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative");
30 File = std::move(AbsPath);
31}
32
Sam McCalld20d7982018-07-09 14:25:59 +000033bool fromJSON(const json::Value &E, URIForFile &R) {
34 if (auto S = E.getAsString()) {
Eric Liu78ed91a72018-01-29 15:37:46 +000035 auto U = URI::parse(*S);
36 if (!U) {
Sam McCallbed58852018-07-11 10:35:11 +000037 elog("Failed to parse URI {0}: {1}", *S, U.takeError());
Eric Liu78ed91a72018-01-29 15:37:46 +000038 return false;
39 }
Eric Liu5740ff52018-01-31 16:26:27 +000040 if (U->scheme() != "file" && U->scheme() != "test") {
Sam McCallbed58852018-07-11 10:35:11 +000041 elog("Clangd only supports 'file' URI scheme for workspace files: {0}",
42 *S);
Eric Liu78ed91a72018-01-29 15:37:46 +000043 return false;
44 }
Sam McCall41d21522018-01-30 11:23:11 +000045 auto Path = URI::resolve(*U);
46 if (!Path) {
Sam McCallbed58852018-07-11 10:35:11 +000047 log("{0}", Path.takeError());
Sam McCall41d21522018-01-30 11:23:11 +000048 return false;
49 }
Ilya Biryukov7d60d202018-02-16 12:20:47 +000050 R = URIForFile(*Path);
Sam McCallff8b8742017-11-30 21:32:29 +000051 return true;
52 }
53 return false;
Sam McCall38a04912017-11-29 11:36:46 +000054}
55
Sam McCalld20d7982018-07-09 14:25:59 +000056json::Value toJSON(const URIForFile &U) { return U.uri(); }
Krasimir Georgiev50117372017-04-07 11:03:26 +000057
Eric Liu78ed91a72018-01-29 15:37:46 +000058llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) {
59 return OS << U.uri();
Sam McCallfffa8222017-12-20 10:26:53 +000060}
61
Sam McCalld20d7982018-07-09 14:25:59 +000062json::Value toJSON(const TextDocumentIdentifier &R) {
63 return json::Object{{"uri", R.uri}};
Eric Liuc5105f92018-02-16 14:15:55 +000064}
65
Sam McCalld20d7982018-07-09 14:25:59 +000066bool fromJSON(const json::Value &Params, TextDocumentIdentifier &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000067 json::ObjectMapper O(Params);
68 return O && O.map("uri", R.uri);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000069}
70
Sam McCalld20d7982018-07-09 14:25:59 +000071bool fromJSON(const json::Value &Params, Position &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000072 json::ObjectMapper O(Params);
73 return O && O.map("line", R.line) && O.map("character", R.character);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000074}
75
Sam McCalld20d7982018-07-09 14:25:59 +000076json::Value toJSON(const Position &P) {
77 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +000078 {"line", P.line},
79 {"character", P.character},
80 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000081}
82
Sam McCallfffa8222017-12-20 10:26:53 +000083llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) {
84 return OS << P.line << ':' << P.character;
85}
86
Sam McCalld20d7982018-07-09 14:25:59 +000087bool fromJSON(const json::Value &Params, Range &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000088 json::ObjectMapper O(Params);
89 return O && O.map("start", R.start) && O.map("end", R.end);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000090}
91
Sam McCalld20d7982018-07-09 14:25:59 +000092json::Value toJSON(const Range &P) {
93 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +000094 {"start", P.start},
95 {"end", P.end},
96 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000097}
98
Sam McCallfffa8222017-12-20 10:26:53 +000099llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) {
100 return OS << R.start << '-' << R.end;
101}
102
Sam McCalld20d7982018-07-09 14:25:59 +0000103json::Value toJSON(const Location &P) {
104 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000105 {"uri", P.uri},
106 {"range", P.range},
107 };
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000108}
109
Sam McCallfffa8222017-12-20 10:26:53 +0000110llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) {
111 return OS << L.range << '@' << L.uri;
112}
113
Sam McCalld20d7982018-07-09 14:25:59 +0000114bool fromJSON(const json::Value &Params, TextDocumentItem &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000115 json::ObjectMapper O(Params);
116 return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&
117 O.map("version", R.version) && O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000118}
119
Sam McCalld20d7982018-07-09 14:25:59 +0000120bool fromJSON(const json::Value &Params, Metadata &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000121 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000122 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000123 return false;
124 O.map("extraFlags", R.extraFlags);
125 return true;
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000126}
127
Sam McCalld20d7982018-07-09 14:25:59 +0000128bool fromJSON(const json::Value &Params, TextEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000129 json::ObjectMapper O(Params);
130 return O && O.map("range", R.range) && O.map("newText", R.newText);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000131}
132
Sam McCalld20d7982018-07-09 14:25:59 +0000133json::Value toJSON(const TextEdit &P) {
134 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000135 {"range", P.range},
136 {"newText", P.newText},
137 };
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000138}
139
Sam McCall034e11a2018-01-25 17:29:17 +0000140llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {
141 OS << TE.range << " => \"";
Jonas Devlieghere1ab6a7a2018-05-31 17:36:31 +0000142 printEscapedString(TE.newText, OS);
Sam McCall034e11a2018-01-25 17:29:17 +0000143 return OS << '"';
144}
145
Sam McCalld20d7982018-07-09 14:25:59 +0000146bool fromJSON(const json::Value &E, TraceLevel &Out) {
147 if (auto S = E.getAsString()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000148 if (*S == "off") {
149 Out = TraceLevel::Off;
150 return true;
151 } else if (*S == "messages") {
152 Out = TraceLevel::Messages;
153 return true;
154 } else if (*S == "verbose") {
155 Out = TraceLevel::Verbose;
156 return true;
157 }
158 }
159 return false;
160}
161
Sam McCalld20d7982018-07-09 14:25:59 +0000162bool fromJSON(const json::Value &Params, CompletionItemClientCapabilities &R) {
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000163 json::ObjectMapper O(Params);
164 if (!O)
165 return false;
166 O.map("snippetSupport", R.snippetSupport);
167 O.map("commitCharacterSupport", R.commitCharacterSupport);
168 return true;
169}
170
Sam McCalld20d7982018-07-09 14:25:59 +0000171bool fromJSON(const json::Value &Params, CompletionClientCapabilities &R) {
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000172 json::ObjectMapper O(Params);
173 if (!O)
174 return false;
175 O.map("dynamicRegistration", R.dynamicRegistration);
176 O.map("completionItem", R.completionItem);
177 O.map("contextSupport", R.contextSupport);
178 return true;
179}
180
Alex Lorenz8626d362018-08-10 17:25:07 +0000181bool fromJSON(const llvm::json::Value &Params,
182 PublishDiagnosticsClientCapabilities &R) {
183 json::ObjectMapper O(Params);
184 if (!O)
185 return false;
186 O.map("clangdFixSupport", R.clangdFixSupport);
Alex Lorenz0ce8a7a2018-08-22 20:30:06 +0000187 O.map("categorySupport", R.categorySupport);
Alex Lorenz8626d362018-08-10 17:25:07 +0000188 return true;
189}
190
Sam McCalld20d7982018-07-09 14:25:59 +0000191bool fromJSON(const json::Value &E, SymbolKind &Out) {
192 if (auto T = E.getAsInteger()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000193 if (*T < static_cast<int>(SymbolKind::File) ||
194 *T > static_cast<int>(SymbolKind::TypeParameter))
195 return false;
196 Out = static_cast<SymbolKind>(*T);
197 return true;
198 }
199 return false;
200}
201
Sam McCalld20d7982018-07-09 14:25:59 +0000202bool fromJSON(const json::Value &E, std::vector<SymbolKind> &Out) {
203 if (auto *A = E.getAsArray()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000204 Out.clear();
205 for (size_t I = 0; I < A->size(); ++I) {
206 SymbolKind KindOut;
207 if (fromJSON((*A)[I], KindOut))
208 Out.push_back(KindOut);
209 }
210 return true;
211 }
212 return false;
213}
214
Sam McCalld20d7982018-07-09 14:25:59 +0000215bool fromJSON(const json::Value &Params, SymbolKindCapabilities &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000216 json::ObjectMapper O(Params);
217 return O && O.map("valueSet", R.valueSet);
218}
219
220SymbolKind adjustKindToCapability(SymbolKind Kind,
Ilya Biryukov74f26552018-07-26 12:05:31 +0000221 SymbolKindBitset &SupportedSymbolKinds) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000222 auto KindVal = static_cast<size_t>(Kind);
Ilya Biryukov74f26552018-07-26 12:05:31 +0000223 if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() &&
224 SupportedSymbolKinds[KindVal])
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000225 return Kind;
226
227 switch (Kind) {
228 // Provide some fall backs for common kinds that are close enough.
229 case SymbolKind::Struct:
230 return SymbolKind::Class;
231 case SymbolKind::EnumMember:
232 return SymbolKind::Enum;
233 default:
234 return SymbolKind::String;
235 }
236}
237
Sam McCalld20d7982018-07-09 14:25:59 +0000238bool fromJSON(const json::Value &Params, WorkspaceSymbolCapabilities &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000239 json::ObjectMapper O(Params);
240 return O && O.map("symbolKind", R.symbolKind);
241}
242
Sam McCalld20d7982018-07-09 14:25:59 +0000243bool fromJSON(const json::Value &Params, WorkspaceClientCapabilities &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000244 json::ObjectMapper O(Params);
245 return O && O.map("symbol", R.symbol);
246}
247
Sam McCalld20d7982018-07-09 14:25:59 +0000248bool fromJSON(const json::Value &Params, TextDocumentClientCapabilities &R) {
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000249 json::ObjectMapper O(Params);
250 if (!O)
251 return false;
252 O.map("completion", R.completion);
Alex Lorenz8626d362018-08-10 17:25:07 +0000253 O.map("publishDiagnostics", R.publishDiagnostics);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000254 return true;
255}
256
Sam McCalld20d7982018-07-09 14:25:59 +0000257bool fromJSON(const json::Value &Params, ClientCapabilities &R) {
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000258 json::ObjectMapper O(Params);
259 if (!O)
260 return false;
261 O.map("textDocument", R.textDocument);
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000262 O.map("workspace", R.workspace);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000263 return true;
264}
265
Sam McCalld20d7982018-07-09 14:25:59 +0000266bool fromJSON(const json::Value &Params, InitializeParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000267 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000268 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000269 return false;
Sam McCall38a04912017-11-29 11:36:46 +0000270 // We deliberately don't fail if we can't parse individual fields.
271 // Failing to handle a slightly malformed initialize would be a disaster.
Sam McCallff8b8742017-11-30 21:32:29 +0000272 O.map("processId", R.processId);
273 O.map("rootUri", R.rootUri);
274 O.map("rootPath", R.rootPath);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000275 O.map("capabilities", R.capabilities);
Sam McCallff8b8742017-11-30 21:32:29 +0000276 O.map("trace", R.trace);
Simon Marchi88016782018-08-01 11:28:49 +0000277 O.map("initializationOptions", R.initializationOptions);
Sam McCallff8b8742017-11-30 21:32:29 +0000278 return true;
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000279}
280
Sam McCalld20d7982018-07-09 14:25:59 +0000281bool fromJSON(const json::Value &Params, DidOpenTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000282 json::ObjectMapper O(Params);
283 return O && O.map("textDocument", R.textDocument) &&
284 O.map("metadata", R.metadata);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000285}
286
Sam McCalld20d7982018-07-09 14:25:59 +0000287bool fromJSON(const json::Value &Params, DidCloseTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000288 json::ObjectMapper O(Params);
289 return O && O.map("textDocument", R.textDocument);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000290}
291
Sam McCalld20d7982018-07-09 14:25:59 +0000292bool fromJSON(const json::Value &Params, DidChangeTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000293 json::ObjectMapper O(Params);
294 return O && O.map("textDocument", R.textDocument) &&
Eric Liu51fed182018-02-22 18:40:39 +0000295 O.map("contentChanges", R.contentChanges) &&
296 O.map("wantDiagnostics", R.wantDiagnostics);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000297}
298
Sam McCalld20d7982018-07-09 14:25:59 +0000299bool fromJSON(const json::Value &E, FileChangeType &Out) {
300 if (auto T = E.getAsInteger()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000301 if (*T < static_cast<int>(FileChangeType::Created) ||
302 *T > static_cast<int>(FileChangeType::Deleted))
303 return false;
304 Out = static_cast<FileChangeType>(*T);
305 return true;
306 }
307 return false;
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000308}
309
Sam McCalld20d7982018-07-09 14:25:59 +0000310bool fromJSON(const json::Value &Params, FileEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000311 json::ObjectMapper O(Params);
312 return O && O.map("uri", R.uri) && O.map("type", R.type);
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000313}
314
Sam McCalld20d7982018-07-09 14:25:59 +0000315bool fromJSON(const json::Value &Params, DidChangeWatchedFilesParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000316 json::ObjectMapper O(Params);
317 return O && O.map("changes", R.changes);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000318}
319
Sam McCalld20d7982018-07-09 14:25:59 +0000320bool fromJSON(const json::Value &Params, TextDocumentContentChangeEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000321 json::ObjectMapper O(Params);
Simon Marchi98082622018-03-26 14:41:40 +0000322 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
323 O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000324}
325
Sam McCalld20d7982018-07-09 14:25:59 +0000326bool fromJSON(const json::Value &Params, FormattingOptions &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000327 json::ObjectMapper O(Params);
328 return O && O.map("tabSize", R.tabSize) &&
329 O.map("insertSpaces", R.insertSpaces);
330}
331
Sam McCalld20d7982018-07-09 14:25:59 +0000332json::Value toJSON(const FormattingOptions &P) {
333 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000334 {"tabSize", P.tabSize},
335 {"insertSpaces", P.insertSpaces},
336 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000337}
338
Sam McCalld20d7982018-07-09 14:25:59 +0000339bool fromJSON(const json::Value &Params, DocumentRangeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000340 json::ObjectMapper O(Params);
341 return O && O.map("textDocument", R.textDocument) &&
342 O.map("range", R.range) && O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000343}
344
Sam McCalld20d7982018-07-09 14:25:59 +0000345bool fromJSON(const json::Value &Params, DocumentOnTypeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000346 json::ObjectMapper O(Params);
347 return O && O.map("textDocument", R.textDocument) &&
348 O.map("position", R.position) && O.map("ch", R.ch) &&
349 O.map("options", R.options);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000350}
351
Sam McCalld20d7982018-07-09 14:25:59 +0000352bool fromJSON(const json::Value &Params, DocumentFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000353 json::ObjectMapper O(Params);
354 return O && O.map("textDocument", R.textDocument) &&
355 O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000356}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000357
Sam McCalld20d7982018-07-09 14:25:59 +0000358bool fromJSON(const json::Value &Params, DocumentSymbolParams &R) {
Marc-Andre Laperle1be69702018-07-05 19:35:01 +0000359 json::ObjectMapper O(Params);
360 return O && O.map("textDocument", R.textDocument);
361}
362
Sam McCalld20d7982018-07-09 14:25:59 +0000363bool fromJSON(const json::Value &Params, Diagnostic &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000364 json::ObjectMapper O(Params);
365 if (!O || !O.map("range", R.range) || !O.map("message", R.message))
366 return false;
367 O.map("severity", R.severity);
368 return true;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000369}
370
Sam McCalld20d7982018-07-09 14:25:59 +0000371bool fromJSON(const json::Value &Params, CodeActionContext &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000372 json::ObjectMapper O(Params);
373 return O && O.map("diagnostics", R.diagnostics);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000374}
375
Sam McCall034e11a2018-01-25 17:29:17 +0000376llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
377 OS << D.range << " [";
378 switch (D.severity) {
379 case 1:
380 OS << "error";
381 break;
382 case 2:
383 OS << "warning";
384 break;
385 case 3:
386 OS << "note";
387 break;
388 case 4:
389 OS << "remark";
390 break;
391 default:
392 OS << "diagnostic";
393 break;
394 }
395 return OS << '(' << D.severity << "): " << D.message << "]";
396}
397
Sam McCalld20d7982018-07-09 14:25:59 +0000398bool fromJSON(const json::Value &Params, CodeActionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000399 json::ObjectMapper O(Params);
400 return O && O.map("textDocument", R.textDocument) &&
401 O.map("range", R.range) && O.map("context", R.context);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000402}
403
Sam McCalld20d7982018-07-09 14:25:59 +0000404bool fromJSON(const json::Value &Params, WorkspaceEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000405 json::ObjectMapper O(Params);
406 return O && O.map("changes", R.changes);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000407}
408
Benjamin Kramerb4c5c2d2017-12-28 15:03:02 +0000409const llvm::StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000410 "clangd.applyFix";
Sam McCalld20d7982018-07-09 14:25:59 +0000411bool fromJSON(const json::Value &Params, ExecuteCommandParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000412 json::ObjectMapper O(Params);
413 if (!O || !O.map("command", R.command))
414 return false;
Sam McCallec109022017-11-28 09:37:43 +0000415
Sam McCalld20d7982018-07-09 14:25:59 +0000416 auto Args = Params.getAsObject()->getArray("arguments");
Sam McCallff8b8742017-11-30 21:32:29 +0000417 if (R.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
418 return Args && Args->size() == 1 &&
419 fromJSON(Args->front(), R.workspaceEdit);
420 }
421 return false; // Unrecognized command.
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000422}
423
Sam McCalld20d7982018-07-09 14:25:59 +0000424json::Value toJSON(const SymbolInformation &P) {
425 return json::Object{
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000426 {"name", P.name},
427 {"kind", static_cast<int>(P.kind)},
428 {"location", P.location},
429 {"containerName", P.containerName},
430 };
431}
432
433llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
434 const SymbolInformation &SI) {
435 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
436 return O;
437}
438
Sam McCalld20d7982018-07-09 14:25:59 +0000439bool fromJSON(const json::Value &Params, WorkspaceSymbolParams &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000440 json::ObjectMapper O(Params);
441 return O && O.map("query", R.query);
442}
443
Sam McCalld20d7982018-07-09 14:25:59 +0000444json::Value toJSON(const Command &C) {
445 auto Cmd = json::Object{{"title", C.title}, {"command", C.command}};
Eric Liuc5105f92018-02-16 14:15:55 +0000446 if (C.workspaceEdit)
447 Cmd["arguments"] = {*C.workspaceEdit};
Eric Liuc5105f92018-02-16 14:15:55 +0000448 return std::move(Cmd);
449}
450
Sam McCalld20d7982018-07-09 14:25:59 +0000451json::Value toJSON(const WorkspaceEdit &WE) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000452 if (!WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000453 return json::Object{};
454 json::Object FileChanges;
Sam McCalldd0566b2017-11-06 15:40:30 +0000455 for (auto &Change : *WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000456 FileChanges[Change.first] = json::Array(Change.second);
457 return json::Object{{"changes", std::move(FileChanges)}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000458}
459
Sam McCalld20d7982018-07-09 14:25:59 +0000460json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
461 return json::Object{{"edit", Params.edit}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000462}
463
Sam McCalld20d7982018-07-09 14:25:59 +0000464bool fromJSON(const json::Value &Params, TextDocumentPositionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000465 json::ObjectMapper O(Params);
466 return O && O.map("textDocument", R.textDocument) &&
467 O.map("position", R.position);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000468}
469
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000470static StringRef toTextKind(MarkupKind Kind) {
471 switch (Kind) {
472 case MarkupKind::PlainText:
473 return "plaintext";
474 case MarkupKind::Markdown:
475 return "markdown";
476 }
477 llvm_unreachable("Invalid MarkupKind");
478}
479
Sam McCalld20d7982018-07-09 14:25:59 +0000480json::Value toJSON(const MarkupContent &MC) {
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000481 if (MC.value.empty())
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000482 return nullptr;
483
Sam McCalld20d7982018-07-09 14:25:59 +0000484 return json::Object{
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000485 {"kind", toTextKind(MC.kind)},
486 {"value", MC.value},
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000487 };
488}
489
Sam McCalld20d7982018-07-09 14:25:59 +0000490json::Value toJSON(const Hover &H) {
491 json::Object Result{{"contents", toJSON(H.contents)}};
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000492
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000493 if (H.range.hasValue())
494 Result["range"] = toJSON(*H.range);
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000495
496 return std::move(Result);
497}
498
Sam McCalld20d7982018-07-09 14:25:59 +0000499json::Value toJSON(const CompletionItem &CI) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000500 assert(!CI.label.empty() && "completion item label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000501 json::Object Result{{"label", CI.label}};
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000502 if (CI.kind != CompletionItemKind::Missing)
Sam McCalldd0566b2017-11-06 15:40:30 +0000503 Result["kind"] = static_cast<int>(CI.kind);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000504 if (!CI.detail.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000505 Result["detail"] = CI.detail;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000506 if (!CI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000507 Result["documentation"] = CI.documentation;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000508 if (!CI.sortText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000509 Result["sortText"] = CI.sortText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000510 if (!CI.filterText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000511 Result["filterText"] = CI.filterText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000512 if (!CI.insertText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000513 Result["insertText"] = CI.insertText;
514 if (CI.insertTextFormat != InsertTextFormat::Missing)
515 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000516 if (CI.textEdit)
Sam McCalldd0566b2017-11-06 15:40:30 +0000517 Result["textEdit"] = *CI.textEdit;
518 if (!CI.additionalTextEdits.empty())
Sam McCalld20d7982018-07-09 14:25:59 +0000519 Result["additionalTextEdits"] = json::Array(CI.additionalTextEdits);
Sam McCalldd0566b2017-11-06 15:40:30 +0000520 return std::move(Result);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000521}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000522
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000523llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) {
524 O << I.label << " - " << toJSON(I);
525 return O;
526}
527
Sam McCallff8b8742017-11-30 21:32:29 +0000528bool operator<(const CompletionItem &L, const CompletionItem &R) {
Sam McCallc78ccbd2017-11-08 07:44:12 +0000529 return (L.sortText.empty() ? L.label : L.sortText) <
530 (R.sortText.empty() ? R.label : R.sortText);
531}
532
Sam McCalld20d7982018-07-09 14:25:59 +0000533json::Value toJSON(const CompletionList &L) {
534 return json::Object{
Sam McCalla40371b2017-11-15 09:16:29 +0000535 {"isIncomplete", L.isIncomplete},
Sam McCalld20d7982018-07-09 14:25:59 +0000536 {"items", json::Array(L.items)},
Sam McCalla40371b2017-11-15 09:16:29 +0000537 };
538}
539
Sam McCalld20d7982018-07-09 14:25:59 +0000540json::Value toJSON(const ParameterInformation &PI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000541 assert(!PI.label.empty() && "parameter information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000542 json::Object Result{{"label", PI.label}};
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000543 if (!PI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000544 Result["documentation"] = PI.documentation;
545 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000546}
547
Sam McCalld20d7982018-07-09 14:25:59 +0000548json::Value toJSON(const SignatureInformation &SI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000549 assert(!SI.label.empty() && "signature information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000550 json::Object Result{
Sam McCalldd0566b2017-11-06 15:40:30 +0000551 {"label", SI.label},
Sam McCalld20d7982018-07-09 14:25:59 +0000552 {"parameters", json::Array(SI.parameters)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000553 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000554 if (!SI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000555 Result["documentation"] = SI.documentation;
556 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000557}
558
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000559llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
560 const SignatureInformation &I) {
561 O << I.label << " - " << toJSON(I);
562 return O;
563}
564
Sam McCalld20d7982018-07-09 14:25:59 +0000565json::Value toJSON(const SignatureHelp &SH) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000566 assert(SH.activeSignature >= 0 &&
567 "Unexpected negative value for number of active signatures.");
568 assert(SH.activeParameter >= 0 &&
569 "Unexpected negative value for active parameter index");
Sam McCalld20d7982018-07-09 14:25:59 +0000570 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000571 {"activeSignature", SH.activeSignature},
572 {"activeParameter", SH.activeParameter},
Sam McCalld20d7982018-07-09 14:25:59 +0000573 {"signatures", json::Array(SH.signatures)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000574 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000575}
Haojian Wu345099c2017-11-09 11:30:04 +0000576
Sam McCalld20d7982018-07-09 14:25:59 +0000577bool fromJSON(const json::Value &Params, RenameParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000578 json::ObjectMapper O(Params);
579 return O && O.map("textDocument", R.textDocument) &&
580 O.map("position", R.position) && O.map("newName", R.newName);
Haojian Wu345099c2017-11-09 11:30:04 +0000581}
Sam McCallff8b8742017-11-30 21:32:29 +0000582
Sam McCalld20d7982018-07-09 14:25:59 +0000583json::Value toJSON(const DocumentHighlight &DH) {
584 return json::Object{
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000585 {"range", toJSON(DH.range)},
586 {"kind", static_cast<int>(DH.kind)},
587 };
588}
589
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000590llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
591 const DocumentHighlight &V) {
592 O << V.range;
593 if (V.kind == DocumentHighlightKind::Read)
594 O << "(r)";
595 if (V.kind == DocumentHighlightKind::Write)
596 O << "(w)";
597 return O;
598}
599
Sam McCalld20d7982018-07-09 14:25:59 +0000600bool fromJSON(const json::Value &Params, DidChangeConfigurationParams &CCP) {
Simon Marchi5178f922018-02-22 14:00:39 +0000601 json::ObjectMapper O(Params);
602 return O && O.map("settings", CCP.settings);
603}
604
Alex Lorenzf8087862018-08-01 17:39:29 +0000605bool fromJSON(const llvm::json::Value &Params,
606 ClangdCompileCommand &CDbUpdate) {
607 json::ObjectMapper O(Params);
608 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&
609 O.map("compilationCommand", CDbUpdate.compilationCommand);
610}
611
Sam McCalld20d7982018-07-09 14:25:59 +0000612bool fromJSON(const json::Value &Params,
613 ClangdConfigurationParamsChange &CCPC) {
Simon Marchi5178f922018-02-22 14:00:39 +0000614 json::ObjectMapper O(Params);
Alex Lorenzf8087862018-08-01 17:39:29 +0000615 return O && O.map("compilationDatabasePath", CCPC.compilationDatabasePath) &&
616 O.map("compilationDatabaseChanges", CCPC.compilationDatabaseChanges);
Simon Marchi5178f922018-02-22 14:00:39 +0000617}
618
Sam McCall1ad142f2018-09-05 11:53:07 +0000619bool fromJSON(const json::Value &Params, ReferenceParams &R) {
620 TextDocumentPositionParams &Base = R;
621 return fromJSON(Params, Base);
622}
623
Kadir Cetinkaya689bf932018-08-24 13:09:41 +0000624json::Value toJSON(const CancelParams &CP) {
625 return json::Object{{"id", CP.ID}};
626}
627
628llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CancelParams &CP) {
629 O << toJSON(CP);
630 return O;
631}
632
633llvm::Optional<std::string> parseNumberOrString(const json::Value *Params) {
634 if (!Params)
635 return llvm::None;
636 // ID is either a number or a string, check for both.
637 if(const auto AsString = Params->getAsString())
638 return AsString->str();
639
640 if(const auto AsNumber = Params->getAsInteger())
641 return itostr(AsNumber.getValue());
642
643 return llvm::None;
644}
645
646bool fromJSON(const json::Value &Params, CancelParams &CP) {
647 const auto ParamsAsObject = Params.getAsObject();
648 if (!ParamsAsObject)
649 return false;
650 if (auto Parsed = parseNumberOrString(ParamsAsObject->get("id"))) {
651 CP.ID = std::move(*Parsed);
652 return true;
653 }
654 return false;
655}
656
Sam McCallff8b8742017-11-30 21:32:29 +0000657} // namespace clangd
658} // namespace clang