blob: d8369f3dcc13e288a01244b9d191f599d36e05d1 [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 McCallc008af62018-10-20 15:30:37 +000024using namespace llvm;
Sam McCallff8b8742017-11-30 21:32:29 +000025namespace clang {
26namespace clangd {
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) {
Sam McCallc008af62018-10-20 15:30:37 +000031 assert(sys::path::is_absolute(AbsPath) && "the path is relative");
Ilya Biryukov7d60d202018-02-16 12:20:47 +000032 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
Sam McCallc008af62018-10-20 15:30:37 +000060raw_ostream &operator<<(raw_ostream &OS, const URIForFile &U) {
Eric Liu78ed91a72018-01-29 15:37:46 +000061 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 McCallc008af62018-10-20 15:30:37 +000085raw_ostream &operator<<(raw_ostream &OS, const Position &P) {
Sam McCallfffa8222017-12-20 10:26:53 +000086 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 McCallc008af62018-10-20 15:30:37 +0000101raw_ostream &operator<<(raw_ostream &OS, const Range &R) {
Sam McCallfffa8222017-12-20 10:26:53 +0000102 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 McCallc008af62018-10-20 15:30:37 +0000112raw_ostream &operator<<(raw_ostream &OS, const Location &L) {
Sam McCallfffa8222017-12-20 10:26:53 +0000113 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, TextEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000123 json::ObjectMapper O(Params);
124 return O && O.map("range", R.range) && O.map("newText", R.newText);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000125}
126
Sam McCalld20d7982018-07-09 14:25:59 +0000127json::Value toJSON(const TextEdit &P) {
128 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000129 {"range", P.range},
130 {"newText", P.newText},
131 };
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000132}
133
Sam McCallc008af62018-10-20 15:30:37 +0000134raw_ostream &operator<<(raw_ostream &OS, const TextEdit &TE) {
Sam McCall034e11a2018-01-25 17:29:17 +0000135 OS << TE.range << " => \"";
Jonas Devlieghere1ab6a7a2018-05-31 17:36:31 +0000136 printEscapedString(TE.newText, OS);
Sam McCall034e11a2018-01-25 17:29:17 +0000137 return OS << '"';
138}
139
Sam McCalld20d7982018-07-09 14:25:59 +0000140bool fromJSON(const json::Value &E, TraceLevel &Out) {
141 if (auto S = E.getAsString()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000142 if (*S == "off") {
143 Out = TraceLevel::Off;
144 return true;
145 } else if (*S == "messages") {
146 Out = TraceLevel::Messages;
147 return true;
148 } else if (*S == "verbose") {
149 Out = TraceLevel::Verbose;
150 return true;
151 }
152 }
153 return false;
154}
155
Sam McCalld20d7982018-07-09 14:25:59 +0000156bool fromJSON(const json::Value &E, SymbolKind &Out) {
157 if (auto T = E.getAsInteger()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000158 if (*T < static_cast<int>(SymbolKind::File) ||
159 *T > static_cast<int>(SymbolKind::TypeParameter))
160 return false;
161 Out = static_cast<SymbolKind>(*T);
162 return true;
163 }
164 return false;
165}
166
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000167bool fromJSON(const json::Value &E, SymbolKindBitset &Out) {
Sam McCalld20d7982018-07-09 14:25:59 +0000168 if (auto *A = E.getAsArray()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000169 for (size_t I = 0; I < A->size(); ++I) {
170 SymbolKind KindOut;
171 if (fromJSON((*A)[I], KindOut))
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000172 Out.set(size_t(KindOut));
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000173 }
174 return true;
175 }
176 return false;
177}
178
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000179SymbolKind adjustKindToCapability(SymbolKind Kind,
Ilya Biryukov74f26552018-07-26 12:05:31 +0000180 SymbolKindBitset &SupportedSymbolKinds) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000181 auto KindVal = static_cast<size_t>(Kind);
Ilya Biryukov74f26552018-07-26 12:05:31 +0000182 if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() &&
183 SupportedSymbolKinds[KindVal])
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000184 return Kind;
185
186 switch (Kind) {
187 // Provide some fall backs for common kinds that are close enough.
188 case SymbolKind::Struct:
189 return SymbolKind::Class;
190 case SymbolKind::EnumMember:
191 return SymbolKind::Enum;
192 default:
193 return SymbolKind::String;
194 }
195}
196
Sam McCalld20d7982018-07-09 14:25:59 +0000197bool fromJSON(const json::Value &Params, ClientCapabilities &R) {
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000198 const json::Object *O = Params.getAsObject();
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000199 if (!O)
200 return false;
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000201 if (auto *TextDocument = O->getObject("textDocument")) {
202 if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {
203 if (auto CategorySupport = Diagnostics->getBoolean("categorySupport"))
204 R.DiagnosticCategory = *CategorySupport;
Sam McCall16e70702018-10-24 07:59:38 +0000205 if (auto CodeActions = Diagnostics->getBoolean("codeActionsInline"))
206 R.DiagnosticFixes = *CodeActions;
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000207 }
208 if (auto *Completion = TextDocument->getObject("completion")) {
209 if (auto *Item = Completion->getObject("completionItem")) {
210 if (auto SnippetSupport = Item->getBoolean("snippetSupport"))
211 R.CompletionSnippets = *SnippetSupport;
212 }
213 if (auto *ItemKind = Completion->getObject("completionItemKind")) {
214 if (auto *ValueSet = ItemKind->get("valueSet")) {
215 R.CompletionItemKinds.emplace();
216 if (!fromJSON(*ValueSet, *R.CompletionItemKinds))
217 return false;
218 }
219 }
220 }
221 if (auto *CodeAction = TextDocument->getObject("codeAction")) {
222 if (CodeAction->getObject("codeActionLiteralSupport"))
223 R.CodeActionStructure = true;
224 }
225 }
226 if (auto *Workspace = O->getObject("workspace")) {
227 if (auto *Symbol = Workspace->getObject("symbol")) {
228 if (auto *SymbolKind = Symbol->getObject("symbolKind")) {
229 if (auto *ValueSet = SymbolKind->get("valueSet")) {
230 R.WorkspaceSymbolKinds.emplace();
231 if (!fromJSON(*ValueSet, *R.WorkspaceSymbolKinds))
232 return false;
233 }
234 }
235 }
236 }
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000237 return true;
238}
239
Sam McCalld20d7982018-07-09 14:25:59 +0000240bool fromJSON(const json::Value &Params, InitializeParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000241 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000242 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000243 return false;
Sam McCall38a04912017-11-29 11:36:46 +0000244 // We deliberately don't fail if we can't parse individual fields.
245 // Failing to handle a slightly malformed initialize would be a disaster.
Sam McCallff8b8742017-11-30 21:32:29 +0000246 O.map("processId", R.processId);
247 O.map("rootUri", R.rootUri);
248 O.map("rootPath", R.rootPath);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000249 O.map("capabilities", R.capabilities);
Sam McCallff8b8742017-11-30 21:32:29 +0000250 O.map("trace", R.trace);
Simon Marchi88016782018-08-01 11:28:49 +0000251 O.map("initializationOptions", R.initializationOptions);
Sam McCallff8b8742017-11-30 21:32:29 +0000252 return true;
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000253}
254
Sam McCalld20d7982018-07-09 14:25:59 +0000255bool fromJSON(const json::Value &Params, DidOpenTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000256 json::ObjectMapper O(Params);
Sam McCall2eb6b402018-11-02 13:06:55 +0000257 return O && O.map("textDocument", R.textDocument);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000258}
259
Sam McCalld20d7982018-07-09 14:25:59 +0000260bool fromJSON(const json::Value &Params, DidCloseTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000261 json::ObjectMapper O(Params);
262 return O && O.map("textDocument", R.textDocument);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000263}
264
Sam McCalld20d7982018-07-09 14:25:59 +0000265bool fromJSON(const json::Value &Params, DidChangeTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000266 json::ObjectMapper O(Params);
267 return O && O.map("textDocument", R.textDocument) &&
Eric Liu51fed182018-02-22 18:40:39 +0000268 O.map("contentChanges", R.contentChanges) &&
269 O.map("wantDiagnostics", R.wantDiagnostics);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000270}
271
Sam McCalld20d7982018-07-09 14:25:59 +0000272bool fromJSON(const json::Value &E, FileChangeType &Out) {
273 if (auto T = E.getAsInteger()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000274 if (*T < static_cast<int>(FileChangeType::Created) ||
275 *T > static_cast<int>(FileChangeType::Deleted))
276 return false;
277 Out = static_cast<FileChangeType>(*T);
278 return true;
279 }
280 return false;
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000281}
282
Sam McCalld20d7982018-07-09 14:25:59 +0000283bool fromJSON(const json::Value &Params, FileEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000284 json::ObjectMapper O(Params);
285 return O && O.map("uri", R.uri) && O.map("type", R.type);
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000286}
287
Sam McCalld20d7982018-07-09 14:25:59 +0000288bool fromJSON(const json::Value &Params, DidChangeWatchedFilesParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000289 json::ObjectMapper O(Params);
290 return O && O.map("changes", R.changes);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000291}
292
Sam McCalld20d7982018-07-09 14:25:59 +0000293bool fromJSON(const json::Value &Params, TextDocumentContentChangeEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000294 json::ObjectMapper O(Params);
Simon Marchi98082622018-03-26 14:41:40 +0000295 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
296 O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000297}
298
Sam McCalld20d7982018-07-09 14:25:59 +0000299bool fromJSON(const json::Value &Params, FormattingOptions &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000300 json::ObjectMapper O(Params);
301 return O && O.map("tabSize", R.tabSize) &&
302 O.map("insertSpaces", R.insertSpaces);
303}
304
Sam McCalld20d7982018-07-09 14:25:59 +0000305json::Value toJSON(const FormattingOptions &P) {
306 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000307 {"tabSize", P.tabSize},
308 {"insertSpaces", P.insertSpaces},
309 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000310}
311
Sam McCalld20d7982018-07-09 14:25:59 +0000312bool fromJSON(const json::Value &Params, DocumentRangeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000313 json::ObjectMapper O(Params);
314 return O && O.map("textDocument", R.textDocument) &&
315 O.map("range", R.range) && O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000316}
317
Sam McCalld20d7982018-07-09 14:25:59 +0000318bool fromJSON(const json::Value &Params, DocumentOnTypeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000319 json::ObjectMapper O(Params);
320 return O && O.map("textDocument", R.textDocument) &&
321 O.map("position", R.position) && O.map("ch", R.ch) &&
322 O.map("options", R.options);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000323}
324
Sam McCalld20d7982018-07-09 14:25:59 +0000325bool fromJSON(const json::Value &Params, DocumentFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000326 json::ObjectMapper O(Params);
327 return O && O.map("textDocument", R.textDocument) &&
328 O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000329}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000330
Sam McCalld20d7982018-07-09 14:25:59 +0000331bool fromJSON(const json::Value &Params, DocumentSymbolParams &R) {
Marc-Andre Laperle1be69702018-07-05 19:35:01 +0000332 json::ObjectMapper O(Params);
333 return O && O.map("textDocument", R.textDocument);
334}
335
Sam McCallc008af62018-10-20 15:30:37 +0000336json::Value toJSON(const Diagnostic &D) {
Sam McCall20841d42018-10-16 16:29:41 +0000337 json::Object Diag{
338 {"range", D.range},
339 {"severity", D.severity},
340 {"message", D.message},
341 };
Sam McCall16e70702018-10-24 07:59:38 +0000342 if (D.category)
343 Diag["category"] = *D.category;
344 if (D.codeActions)
345 Diag["codeActions"] = D.codeActions;
Sam McCall20841d42018-10-16 16:29:41 +0000346 return std::move(Diag);
347}
348
Sam McCalld20d7982018-07-09 14:25:59 +0000349bool fromJSON(const json::Value &Params, Diagnostic &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000350 json::ObjectMapper O(Params);
351 if (!O || !O.map("range", R.range) || !O.map("message", R.message))
352 return false;
353 O.map("severity", R.severity);
Sam McCall16e70702018-10-24 07:59:38 +0000354 O.map("category", R.category);
Sam McCallff8b8742017-11-30 21:32:29 +0000355 return true;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000356}
357
Sam McCalld20d7982018-07-09 14:25:59 +0000358bool fromJSON(const json::Value &Params, CodeActionContext &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000359 json::ObjectMapper O(Params);
360 return O && O.map("diagnostics", R.diagnostics);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000361}
362
Sam McCallc008af62018-10-20 15:30:37 +0000363raw_ostream &operator<<(raw_ostream &OS, const Diagnostic &D) {
Sam McCall034e11a2018-01-25 17:29:17 +0000364 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 McCalld20d7982018-07-09 14:25:59 +0000385bool fromJSON(const json::Value &Params, CodeActionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000386 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 McCalld20d7982018-07-09 14:25:59 +0000391bool fromJSON(const json::Value &Params, WorkspaceEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000392 json::ObjectMapper O(Params);
393 return O && O.map("changes", R.changes);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000394}
395
Sam McCallc008af62018-10-20 15:30:37 +0000396const StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000397 "clangd.applyFix";
Sam McCalld20d7982018-07-09 14:25:59 +0000398bool fromJSON(const json::Value &Params, ExecuteCommandParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000399 json::ObjectMapper O(Params);
400 if (!O || !O.map("command", R.command))
401 return false;
Sam McCallec109022017-11-28 09:37:43 +0000402
Sam McCalld20d7982018-07-09 14:25:59 +0000403 auto Args = Params.getAsObject()->getArray("arguments");
Sam McCallff8b8742017-11-30 21:32:29 +0000404 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
Sam McCalld20d7982018-07-09 14:25:59 +0000411json::Value toJSON(const SymbolInformation &P) {
412 return json::Object{
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000413 {"name", P.name},
414 {"kind", static_cast<int>(P.kind)},
415 {"location", P.location},
416 {"containerName", P.containerName},
417 };
418}
419
Sam McCallc008af62018-10-20 15:30:37 +0000420raw_ostream &operator<<(raw_ostream &O, const SymbolInformation &SI) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000421 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
422 return O;
423}
424
Sam McCalld20d7982018-07-09 14:25:59 +0000425bool fromJSON(const json::Value &Params, WorkspaceSymbolParams &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000426 json::ObjectMapper O(Params);
427 return O && O.map("query", R.query);
428}
429
Sam McCalld20d7982018-07-09 14:25:59 +0000430json::Value toJSON(const Command &C) {
431 auto Cmd = json::Object{{"title", C.title}, {"command", C.command}};
Eric Liuc5105f92018-02-16 14:15:55 +0000432 if (C.workspaceEdit)
433 Cmd["arguments"] = {*C.workspaceEdit};
Eric Liuc5105f92018-02-16 14:15:55 +0000434 return std::move(Cmd);
435}
436
Sam McCallc008af62018-10-20 15:30:37 +0000437const StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";
Sam McCall20841d42018-10-16 16:29:41 +0000438
Sam McCallc008af62018-10-20 15:30:37 +0000439json::Value toJSON(const CodeAction &CA) {
Sam McCall20841d42018-10-16 16:29:41 +0000440 auto CodeAction = json::Object{{"title", CA.title}};
441 if (CA.kind)
442 CodeAction["kind"] = *CA.kind;
443 if (CA.diagnostics)
444 CodeAction["diagnostics"] = json::Array(*CA.diagnostics);
445 if (CA.edit)
446 CodeAction["edit"] = *CA.edit;
447 if (CA.command)
448 CodeAction["command"] = *CA.command;
449 return std::move(CodeAction);
450}
451
Sam McCalld20d7982018-07-09 14:25:59 +0000452json::Value toJSON(const WorkspaceEdit &WE) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000453 if (!WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000454 return json::Object{};
455 json::Object FileChanges;
Sam McCalldd0566b2017-11-06 15:40:30 +0000456 for (auto &Change : *WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000457 FileChanges[Change.first] = json::Array(Change.second);
458 return json::Object{{"changes", std::move(FileChanges)}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000459}
460
Sam McCalld20d7982018-07-09 14:25:59 +0000461json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
462 return json::Object{{"edit", Params.edit}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000463}
464
Sam McCalld20d7982018-07-09 14:25:59 +0000465bool fromJSON(const json::Value &Params, TextDocumentPositionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000466 json::ObjectMapper O(Params);
467 return O && O.map("textDocument", R.textDocument) &&
468 O.map("position", R.position);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000469}
470
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000471static StringRef toTextKind(MarkupKind Kind) {
472 switch (Kind) {
473 case MarkupKind::PlainText:
474 return "plaintext";
475 case MarkupKind::Markdown:
476 return "markdown";
477 }
478 llvm_unreachable("Invalid MarkupKind");
479}
480
Sam McCalld20d7982018-07-09 14:25:59 +0000481json::Value toJSON(const MarkupContent &MC) {
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000482 if (MC.value.empty())
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000483 return nullptr;
484
Sam McCalld20d7982018-07-09 14:25:59 +0000485 return json::Object{
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000486 {"kind", toTextKind(MC.kind)},
487 {"value", MC.value},
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000488 };
489}
490
Sam McCalld20d7982018-07-09 14:25:59 +0000491json::Value toJSON(const Hover &H) {
492 json::Object Result{{"contents", toJSON(H.contents)}};
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000493
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000494 if (H.range.hasValue())
495 Result["range"] = toJSON(*H.range);
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000496
497 return std::move(Result);
498}
499
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000500bool fromJSON(const json::Value &E, CompletionItemKind &Out) {
501 if (auto T = E.getAsInteger()) {
502 if (*T < static_cast<int>(CompletionItemKind::Text) ||
503 *T > static_cast<int>(CompletionItemKind::TypeParameter))
504 return false;
505 Out = static_cast<CompletionItemKind>(*T);
506 return true;
507 }
508 return false;
509}
510
511CompletionItemKind
512adjustKindToCapability(CompletionItemKind Kind,
513 CompletionItemKindBitset &supportedCompletionItemKinds) {
514 auto KindVal = static_cast<size_t>(Kind);
515 if (KindVal >= CompletionItemKindMin &&
516 KindVal <= supportedCompletionItemKinds.size() &&
517 supportedCompletionItemKinds[KindVal])
518 return Kind;
519
520 switch (Kind) {
521 // Provide some fall backs for common kinds that are close enough.
522 case CompletionItemKind::Folder:
523 return CompletionItemKind::File;
524 case CompletionItemKind::EnumMember:
525 return CompletionItemKind::Enum;
526 case CompletionItemKind::Struct:
527 return CompletionItemKind::Class;
528 default:
529 return CompletionItemKind::Text;
530 }
531}
532
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000533bool fromJSON(const json::Value &E, CompletionItemKindBitset &Out) {
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000534 if (auto *A = E.getAsArray()) {
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000535 for (size_t I = 0; I < A->size(); ++I) {
536 CompletionItemKind KindOut;
537 if (fromJSON((*A)[I], KindOut))
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000538 Out.set(size_t(KindOut));
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000539 }
540 return true;
541 }
542 return false;
543}
544
Sam McCalld20d7982018-07-09 14:25:59 +0000545json::Value toJSON(const CompletionItem &CI) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000546 assert(!CI.label.empty() && "completion item label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000547 json::Object Result{{"label", CI.label}};
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000548 if (CI.kind != CompletionItemKind::Missing)
Sam McCalldd0566b2017-11-06 15:40:30 +0000549 Result["kind"] = static_cast<int>(CI.kind);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000550 if (!CI.detail.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000551 Result["detail"] = CI.detail;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000552 if (!CI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000553 Result["documentation"] = CI.documentation;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000554 if (!CI.sortText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000555 Result["sortText"] = CI.sortText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000556 if (!CI.filterText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000557 Result["filterText"] = CI.filterText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000558 if (!CI.insertText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000559 Result["insertText"] = CI.insertText;
560 if (CI.insertTextFormat != InsertTextFormat::Missing)
561 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000562 if (CI.textEdit)
Sam McCalldd0566b2017-11-06 15:40:30 +0000563 Result["textEdit"] = *CI.textEdit;
564 if (!CI.additionalTextEdits.empty())
Sam McCalld20d7982018-07-09 14:25:59 +0000565 Result["additionalTextEdits"] = json::Array(CI.additionalTextEdits);
Eric Liu6df66002018-09-06 18:52:26 +0000566 if (CI.deprecated)
567 Result["deprecated"] = CI.deprecated;
Sam McCalldd0566b2017-11-06 15:40:30 +0000568 return std::move(Result);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000569}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000570
Sam McCallc008af62018-10-20 15:30:37 +0000571raw_ostream &operator<<(raw_ostream &O, const CompletionItem &I) {
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000572 O << I.label << " - " << toJSON(I);
573 return O;
574}
575
Sam McCallff8b8742017-11-30 21:32:29 +0000576bool operator<(const CompletionItem &L, const CompletionItem &R) {
Sam McCallc78ccbd2017-11-08 07:44:12 +0000577 return (L.sortText.empty() ? L.label : L.sortText) <
578 (R.sortText.empty() ? R.label : R.sortText);
579}
580
Sam McCalld20d7982018-07-09 14:25:59 +0000581json::Value toJSON(const CompletionList &L) {
582 return json::Object{
Sam McCalla40371b2017-11-15 09:16:29 +0000583 {"isIncomplete", L.isIncomplete},
Sam McCalld20d7982018-07-09 14:25:59 +0000584 {"items", json::Array(L.items)},
Sam McCalla40371b2017-11-15 09:16:29 +0000585 };
586}
587
Sam McCalld20d7982018-07-09 14:25:59 +0000588json::Value toJSON(const ParameterInformation &PI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000589 assert(!PI.label.empty() && "parameter information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000590 json::Object Result{{"label", PI.label}};
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000591 if (!PI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000592 Result["documentation"] = PI.documentation;
593 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000594}
595
Sam McCalld20d7982018-07-09 14:25:59 +0000596json::Value toJSON(const SignatureInformation &SI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000597 assert(!SI.label.empty() && "signature information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000598 json::Object Result{
Sam McCalldd0566b2017-11-06 15:40:30 +0000599 {"label", SI.label},
Sam McCalld20d7982018-07-09 14:25:59 +0000600 {"parameters", json::Array(SI.parameters)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000601 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000602 if (!SI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000603 Result["documentation"] = SI.documentation;
604 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000605}
606
Sam McCallc008af62018-10-20 15:30:37 +0000607raw_ostream &operator<<(raw_ostream &O, const SignatureInformation &I) {
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000608 O << I.label << " - " << toJSON(I);
609 return O;
610}
611
Sam McCalld20d7982018-07-09 14:25:59 +0000612json::Value toJSON(const SignatureHelp &SH) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000613 assert(SH.activeSignature >= 0 &&
614 "Unexpected negative value for number of active signatures.");
615 assert(SH.activeParameter >= 0 &&
616 "Unexpected negative value for active parameter index");
Sam McCalld20d7982018-07-09 14:25:59 +0000617 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000618 {"activeSignature", SH.activeSignature},
619 {"activeParameter", SH.activeParameter},
Sam McCalld20d7982018-07-09 14:25:59 +0000620 {"signatures", json::Array(SH.signatures)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000621 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000622}
Haojian Wu345099c2017-11-09 11:30:04 +0000623
Sam McCalld20d7982018-07-09 14:25:59 +0000624bool fromJSON(const json::Value &Params, RenameParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000625 json::ObjectMapper O(Params);
626 return O && O.map("textDocument", R.textDocument) &&
627 O.map("position", R.position) && O.map("newName", R.newName);
Haojian Wu345099c2017-11-09 11:30:04 +0000628}
Sam McCallff8b8742017-11-30 21:32:29 +0000629
Sam McCalld20d7982018-07-09 14:25:59 +0000630json::Value toJSON(const DocumentHighlight &DH) {
631 return json::Object{
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000632 {"range", toJSON(DH.range)},
633 {"kind", static_cast<int>(DH.kind)},
634 };
635}
636
Sam McCallc008af62018-10-20 15:30:37 +0000637raw_ostream &operator<<(raw_ostream &O, const DocumentHighlight &V) {
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000638 O << V.range;
639 if (V.kind == DocumentHighlightKind::Read)
640 O << "(r)";
641 if (V.kind == DocumentHighlightKind::Write)
642 O << "(w)";
643 return O;
644}
645
Sam McCalld20d7982018-07-09 14:25:59 +0000646bool fromJSON(const json::Value &Params, DidChangeConfigurationParams &CCP) {
Simon Marchi5178f922018-02-22 14:00:39 +0000647 json::ObjectMapper O(Params);
648 return O && O.map("settings", CCP.settings);
649}
650
Sam McCallc008af62018-10-20 15:30:37 +0000651bool fromJSON(const json::Value &Params, ClangdCompileCommand &CDbUpdate) {
Alex Lorenzf8087862018-08-01 17:39:29 +0000652 json::ObjectMapper O(Params);
653 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&
654 O.map("compilationCommand", CDbUpdate.compilationCommand);
655}
656
Sam McCallbc904612018-10-25 04:22:52 +0000657bool fromJSON(const json::Value &Params, ConfigurationSettings &S) {
Simon Marchi5178f922018-02-22 14:00:39 +0000658 json::ObjectMapper O(Params);
Sam McCallbc904612018-10-25 04:22:52 +0000659 if (!O)
660 return true; // 'any' type in LSP.
661 O.map("compilationDatabaseChanges", S.compilationDatabaseChanges);
662 return true;
Simon Marchi5178f922018-02-22 14:00:39 +0000663}
664
Sam McCallbc904612018-10-25 04:22:52 +0000665bool fromJSON(const json::Value &Params, InitializationOptions &Opts) {
Simon Marchiabeed662018-10-16 15:55:03 +0000666 json::ObjectMapper O(Params);
Sam McCallbc904612018-10-25 04:22:52 +0000667 if (!O)
668 return true; // 'any' type in LSP.
669
670 fromJSON(Params, Opts.ConfigSettings);
671 O.map("compilationDatabasePath", Opts.compilationDatabasePath);
Sam McCall6980edb2018-11-02 14:07:51 +0000672 O.map("fallbackFlags", Opts.fallbackFlags);
Sam McCallbc904612018-10-25 04:22:52 +0000673 return true;
Simon Marchiabeed662018-10-16 15:55:03 +0000674}
675
Sam McCall1ad142f2018-09-05 11:53:07 +0000676bool fromJSON(const json::Value &Params, ReferenceParams &R) {
677 TextDocumentPositionParams &Base = R;
678 return fromJSON(Params, Base);
679}
680
Sam McCallff8b8742017-11-30 21:32:29 +0000681} // namespace clangd
682} // namespace clang