blob: 7687693f62cacbcda22e79113de5781c53ba58cf [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"
Jan Korousb4067012018-11-27 16:40:46 +000017#include "index/Index.h"
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000018#include "clang/Basic/LLVM.h"
Jan Korousb4067012018-11-27 16:40:46 +000019#include "llvm/ADT/Hashing.h"
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000020#include "llvm/ADT/SmallString.h"
21#include "llvm/Support/Format.h"
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000022#include "llvm/Support/FormatVariadic.h"
Ilya Biryukov19d75602018-11-23 15:21:19 +000023#include "llvm/Support/JSON.h"
Krasimir Georgiev50117372017-04-07 11:03:26 +000024#include "llvm/Support/Path.h"
Ilya Biryukov574b7532017-08-02 09:08:39 +000025#include "llvm/Support/raw_ostream.h"
Ilya Biryukove5128f72017-09-20 07:24:15 +000026
Sam McCallc008af62018-10-20 15:30:37 +000027using namespace llvm;
Sam McCallff8b8742017-11-30 21:32:29 +000028namespace clang {
29namespace clangd {
Sam McCall38a04912017-11-29 11:36:46 +000030
Sam McCalldc8f3cf2018-10-17 07:32:05 +000031char LSPError::ID;
32
Ilya Biryukov7d60d202018-02-16 12:20:47 +000033URIForFile::URIForFile(std::string AbsPath) {
Sam McCallc008af62018-10-20 15:30:37 +000034 assert(sys::path::is_absolute(AbsPath) && "the path is relative");
Ilya Biryukov7d60d202018-02-16 12:20:47 +000035 File = std::move(AbsPath);
36}
37
Sam McCalld20d7982018-07-09 14:25:59 +000038bool fromJSON(const json::Value &E, URIForFile &R) {
39 if (auto S = E.getAsString()) {
Eric Liu78ed91a72018-01-29 15:37:46 +000040 auto U = URI::parse(*S);
41 if (!U) {
Sam McCallbed58852018-07-11 10:35:11 +000042 elog("Failed to parse URI {0}: {1}", *S, U.takeError());
Eric Liu78ed91a72018-01-29 15:37:46 +000043 return false;
44 }
Eric Liu5740ff52018-01-31 16:26:27 +000045 if (U->scheme() != "file" && U->scheme() != "test") {
Sam McCallbed58852018-07-11 10:35:11 +000046 elog("Clangd only supports 'file' URI scheme for workspace files: {0}",
47 *S);
Eric Liu78ed91a72018-01-29 15:37:46 +000048 return false;
49 }
Sam McCall41d21522018-01-30 11:23:11 +000050 auto Path = URI::resolve(*U);
51 if (!Path) {
Sam McCallbed58852018-07-11 10:35:11 +000052 log("{0}", Path.takeError());
Sam McCall41d21522018-01-30 11:23:11 +000053 return false;
54 }
Ilya Biryukov7d60d202018-02-16 12:20:47 +000055 R = URIForFile(*Path);
Sam McCallff8b8742017-11-30 21:32:29 +000056 return true;
57 }
58 return false;
Sam McCall38a04912017-11-29 11:36:46 +000059}
60
Sam McCalld20d7982018-07-09 14:25:59 +000061json::Value toJSON(const URIForFile &U) { return U.uri(); }
Krasimir Georgiev50117372017-04-07 11:03:26 +000062
Sam McCallc008af62018-10-20 15:30:37 +000063raw_ostream &operator<<(raw_ostream &OS, const URIForFile &U) {
Eric Liu78ed91a72018-01-29 15:37:46 +000064 return OS << U.uri();
Sam McCallfffa8222017-12-20 10:26:53 +000065}
66
Sam McCalld20d7982018-07-09 14:25:59 +000067json::Value toJSON(const TextDocumentIdentifier &R) {
68 return json::Object{{"uri", R.uri}};
Eric Liuc5105f92018-02-16 14:15:55 +000069}
70
Sam McCalld20d7982018-07-09 14:25:59 +000071bool fromJSON(const json::Value &Params, TextDocumentIdentifier &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000072 json::ObjectMapper O(Params);
73 return O && O.map("uri", R.uri);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000074}
75
Sam McCalld20d7982018-07-09 14:25:59 +000076bool fromJSON(const json::Value &Params, Position &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000077 json::ObjectMapper O(Params);
78 return O && O.map("line", R.line) && O.map("character", R.character);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000079}
80
Sam McCalld20d7982018-07-09 14:25:59 +000081json::Value toJSON(const Position &P) {
82 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +000083 {"line", P.line},
84 {"character", P.character},
85 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000086}
87
Sam McCallc008af62018-10-20 15:30:37 +000088raw_ostream &operator<<(raw_ostream &OS, const Position &P) {
Sam McCallfffa8222017-12-20 10:26:53 +000089 return OS << P.line << ':' << P.character;
90}
91
Sam McCalld20d7982018-07-09 14:25:59 +000092bool fromJSON(const json::Value &Params, Range &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000093 json::ObjectMapper O(Params);
94 return O && O.map("start", R.start) && O.map("end", R.end);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000095}
96
Sam McCalld20d7982018-07-09 14:25:59 +000097json::Value toJSON(const Range &P) {
98 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +000099 {"start", P.start},
100 {"end", P.end},
101 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000102}
103
Sam McCallc008af62018-10-20 15:30:37 +0000104raw_ostream &operator<<(raw_ostream &OS, const Range &R) {
Sam McCallfffa8222017-12-20 10:26:53 +0000105 return OS << R.start << '-' << R.end;
106}
107
Sam McCalld20d7982018-07-09 14:25:59 +0000108json::Value toJSON(const Location &P) {
109 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000110 {"uri", P.uri},
111 {"range", P.range},
112 };
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000113}
114
Sam McCallc008af62018-10-20 15:30:37 +0000115raw_ostream &operator<<(raw_ostream &OS, const Location &L) {
Sam McCallfffa8222017-12-20 10:26:53 +0000116 return OS << L.range << '@' << L.uri;
117}
118
Sam McCalld20d7982018-07-09 14:25:59 +0000119bool fromJSON(const json::Value &Params, TextDocumentItem &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000120 json::ObjectMapper O(Params);
121 return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&
122 O.map("version", R.version) && O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000123}
124
Sam McCalld20d7982018-07-09 14:25:59 +0000125bool fromJSON(const json::Value &Params, TextEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000126 json::ObjectMapper O(Params);
127 return O && O.map("range", R.range) && O.map("newText", R.newText);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000128}
129
Sam McCalld20d7982018-07-09 14:25:59 +0000130json::Value toJSON(const TextEdit &P) {
131 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000132 {"range", P.range},
133 {"newText", P.newText},
134 };
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000135}
136
Sam McCallc008af62018-10-20 15:30:37 +0000137raw_ostream &operator<<(raw_ostream &OS, const TextEdit &TE) {
Sam McCall034e11a2018-01-25 17:29:17 +0000138 OS << TE.range << " => \"";
Jonas Devlieghere1ab6a7a2018-05-31 17:36:31 +0000139 printEscapedString(TE.newText, OS);
Sam McCall034e11a2018-01-25 17:29:17 +0000140 return OS << '"';
141}
142
Sam McCalld20d7982018-07-09 14:25:59 +0000143bool fromJSON(const json::Value &E, TraceLevel &Out) {
144 if (auto S = E.getAsString()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000145 if (*S == "off") {
146 Out = TraceLevel::Off;
147 return true;
148 } else if (*S == "messages") {
149 Out = TraceLevel::Messages;
150 return true;
151 } else if (*S == "verbose") {
152 Out = TraceLevel::Verbose;
153 return true;
154 }
155 }
156 return false;
157}
158
Sam McCalld20d7982018-07-09 14:25:59 +0000159bool fromJSON(const json::Value &E, SymbolKind &Out) {
160 if (auto T = E.getAsInteger()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000161 if (*T < static_cast<int>(SymbolKind::File) ||
162 *T > static_cast<int>(SymbolKind::TypeParameter))
163 return false;
164 Out = static_cast<SymbolKind>(*T);
165 return true;
166 }
167 return false;
168}
169
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000170bool fromJSON(const json::Value &E, SymbolKindBitset &Out) {
Sam McCalld20d7982018-07-09 14:25:59 +0000171 if (auto *A = E.getAsArray()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000172 for (size_t I = 0; I < A->size(); ++I) {
173 SymbolKind KindOut;
174 if (fromJSON((*A)[I], KindOut))
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000175 Out.set(size_t(KindOut));
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000176 }
177 return true;
178 }
179 return false;
180}
181
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000182SymbolKind adjustKindToCapability(SymbolKind Kind,
Ilya Biryukov74f26552018-07-26 12:05:31 +0000183 SymbolKindBitset &SupportedSymbolKinds) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000184 auto KindVal = static_cast<size_t>(Kind);
Ilya Biryukov74f26552018-07-26 12:05:31 +0000185 if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() &&
186 SupportedSymbolKinds[KindVal])
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000187 return Kind;
188
189 switch (Kind) {
190 // Provide some fall backs for common kinds that are close enough.
191 case SymbolKind::Struct:
192 return SymbolKind::Class;
193 case SymbolKind::EnumMember:
194 return SymbolKind::Enum;
195 default:
196 return SymbolKind::String;
197 }
198}
199
Sam McCalld20d7982018-07-09 14:25:59 +0000200bool fromJSON(const json::Value &Params, ClientCapabilities &R) {
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000201 const json::Object *O = Params.getAsObject();
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000202 if (!O)
203 return false;
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000204 if (auto *TextDocument = O->getObject("textDocument")) {
205 if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {
206 if (auto CategorySupport = Diagnostics->getBoolean("categorySupport"))
207 R.DiagnosticCategory = *CategorySupport;
Sam McCall16e70702018-10-24 07:59:38 +0000208 if (auto CodeActions = Diagnostics->getBoolean("codeActionsInline"))
209 R.DiagnosticFixes = *CodeActions;
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000210 }
211 if (auto *Completion = TextDocument->getObject("completion")) {
212 if (auto *Item = Completion->getObject("completionItem")) {
213 if (auto SnippetSupport = Item->getBoolean("snippetSupport"))
214 R.CompletionSnippets = *SnippetSupport;
215 }
216 if (auto *ItemKind = Completion->getObject("completionItemKind")) {
217 if (auto *ValueSet = ItemKind->get("valueSet")) {
218 R.CompletionItemKinds.emplace();
219 if (!fromJSON(*ValueSet, *R.CompletionItemKinds))
220 return false;
221 }
222 }
223 }
224 if (auto *CodeAction = TextDocument->getObject("codeAction")) {
225 if (CodeAction->getObject("codeActionLiteralSupport"))
226 R.CodeActionStructure = true;
227 }
Ilya Biryukov19d75602018-11-23 15:21:19 +0000228 if (auto *DocumentSymbol = TextDocument->getObject("documentSymbol")) {
229 if (auto HierarchicalSupport =
230 DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
231 R.HierarchicalDocumentSymbol = *HierarchicalSupport;
232 }
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000233 }
234 if (auto *Workspace = O->getObject("workspace")) {
235 if (auto *Symbol = Workspace->getObject("symbol")) {
236 if (auto *SymbolKind = Symbol->getObject("symbolKind")) {
237 if (auto *ValueSet = SymbolKind->get("valueSet")) {
238 R.WorkspaceSymbolKinds.emplace();
239 if (!fromJSON(*ValueSet, *R.WorkspaceSymbolKinds))
240 return false;
241 }
242 }
243 }
244 }
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000245 return true;
246}
247
Sam McCalld20d7982018-07-09 14:25:59 +0000248bool fromJSON(const json::Value &Params, InitializeParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000249 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000250 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000251 return false;
Sam McCall38a04912017-11-29 11:36:46 +0000252 // We deliberately don't fail if we can't parse individual fields.
253 // Failing to handle a slightly malformed initialize would be a disaster.
Sam McCallff8b8742017-11-30 21:32:29 +0000254 O.map("processId", R.processId);
255 O.map("rootUri", R.rootUri);
256 O.map("rootPath", R.rootPath);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000257 O.map("capabilities", R.capabilities);
Sam McCallff8b8742017-11-30 21:32:29 +0000258 O.map("trace", R.trace);
Simon Marchi88016782018-08-01 11:28:49 +0000259 O.map("initializationOptions", R.initializationOptions);
Sam McCallff8b8742017-11-30 21:32:29 +0000260 return true;
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000261}
262
Sam McCalld20d7982018-07-09 14:25:59 +0000263bool fromJSON(const json::Value &Params, DidOpenTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000264 json::ObjectMapper O(Params);
Sam McCall2eb6b402018-11-02 13:06:55 +0000265 return O && O.map("textDocument", R.textDocument);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000266}
267
Sam McCalld20d7982018-07-09 14:25:59 +0000268bool fromJSON(const json::Value &Params, DidCloseTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000269 json::ObjectMapper O(Params);
270 return O && O.map("textDocument", R.textDocument);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000271}
272
Sam McCalld20d7982018-07-09 14:25:59 +0000273bool fromJSON(const json::Value &Params, DidChangeTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000274 json::ObjectMapper O(Params);
275 return O && O.map("textDocument", R.textDocument) &&
Eric Liu51fed182018-02-22 18:40:39 +0000276 O.map("contentChanges", R.contentChanges) &&
277 O.map("wantDiagnostics", R.wantDiagnostics);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000278}
279
Sam McCalld20d7982018-07-09 14:25:59 +0000280bool fromJSON(const json::Value &E, FileChangeType &Out) {
281 if (auto T = E.getAsInteger()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000282 if (*T < static_cast<int>(FileChangeType::Created) ||
283 *T > static_cast<int>(FileChangeType::Deleted))
284 return false;
285 Out = static_cast<FileChangeType>(*T);
286 return true;
287 }
288 return false;
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000289}
290
Sam McCalld20d7982018-07-09 14:25:59 +0000291bool fromJSON(const json::Value &Params, FileEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000292 json::ObjectMapper O(Params);
293 return O && O.map("uri", R.uri) && O.map("type", R.type);
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000294}
295
Sam McCalld20d7982018-07-09 14:25:59 +0000296bool fromJSON(const json::Value &Params, DidChangeWatchedFilesParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000297 json::ObjectMapper O(Params);
298 return O && O.map("changes", R.changes);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000299}
300
Sam McCalld20d7982018-07-09 14:25:59 +0000301bool fromJSON(const json::Value &Params, TextDocumentContentChangeEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000302 json::ObjectMapper O(Params);
Simon Marchi98082622018-03-26 14:41:40 +0000303 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
304 O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000305}
306
Sam McCalld20d7982018-07-09 14:25:59 +0000307bool fromJSON(const json::Value &Params, FormattingOptions &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000308 json::ObjectMapper O(Params);
309 return O && O.map("tabSize", R.tabSize) &&
310 O.map("insertSpaces", R.insertSpaces);
311}
312
Sam McCalld20d7982018-07-09 14:25:59 +0000313json::Value toJSON(const FormattingOptions &P) {
314 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000315 {"tabSize", P.tabSize},
316 {"insertSpaces", P.insertSpaces},
317 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000318}
319
Sam McCalld20d7982018-07-09 14:25:59 +0000320bool fromJSON(const json::Value &Params, DocumentRangeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000321 json::ObjectMapper O(Params);
322 return O && O.map("textDocument", R.textDocument) &&
323 O.map("range", R.range) && O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000324}
325
Sam McCalld20d7982018-07-09 14:25:59 +0000326bool fromJSON(const json::Value &Params, DocumentOnTypeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000327 json::ObjectMapper O(Params);
328 return O && O.map("textDocument", R.textDocument) &&
329 O.map("position", R.position) && O.map("ch", R.ch) &&
330 O.map("options", R.options);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000331}
332
Sam McCalld20d7982018-07-09 14:25:59 +0000333bool fromJSON(const json::Value &Params, DocumentFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000334 json::ObjectMapper O(Params);
335 return O && O.map("textDocument", R.textDocument) &&
336 O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000337}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000338
Sam McCalld20d7982018-07-09 14:25:59 +0000339bool fromJSON(const json::Value &Params, DocumentSymbolParams &R) {
Marc-Andre Laperle1be69702018-07-05 19:35:01 +0000340 json::ObjectMapper O(Params);
341 return O && O.map("textDocument", R.textDocument);
342}
343
Sam McCallc008af62018-10-20 15:30:37 +0000344json::Value toJSON(const Diagnostic &D) {
Sam McCall20841d42018-10-16 16:29:41 +0000345 json::Object Diag{
346 {"range", D.range},
347 {"severity", D.severity},
348 {"message", D.message},
349 };
Sam McCall16e70702018-10-24 07:59:38 +0000350 if (D.category)
351 Diag["category"] = *D.category;
352 if (D.codeActions)
353 Diag["codeActions"] = D.codeActions;
Sam McCall20841d42018-10-16 16:29:41 +0000354 return std::move(Diag);
355}
356
Sam McCalld20d7982018-07-09 14:25:59 +0000357bool fromJSON(const json::Value &Params, Diagnostic &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000358 json::ObjectMapper O(Params);
359 if (!O || !O.map("range", R.range) || !O.map("message", R.message))
360 return false;
361 O.map("severity", R.severity);
Sam McCall16e70702018-10-24 07:59:38 +0000362 O.map("category", R.category);
Sam McCallff8b8742017-11-30 21:32:29 +0000363 return true;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000364}
365
Sam McCalld20d7982018-07-09 14:25:59 +0000366bool fromJSON(const json::Value &Params, CodeActionContext &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000367 json::ObjectMapper O(Params);
368 return O && O.map("diagnostics", R.diagnostics);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000369}
370
Sam McCallc008af62018-10-20 15:30:37 +0000371raw_ostream &operator<<(raw_ostream &OS, const Diagnostic &D) {
Sam McCall034e11a2018-01-25 17:29:17 +0000372 OS << D.range << " [";
373 switch (D.severity) {
374 case 1:
375 OS << "error";
376 break;
377 case 2:
378 OS << "warning";
379 break;
380 case 3:
381 OS << "note";
382 break;
383 case 4:
384 OS << "remark";
385 break;
386 default:
387 OS << "diagnostic";
388 break;
389 }
390 return OS << '(' << D.severity << "): " << D.message << "]";
391}
392
Sam McCalld20d7982018-07-09 14:25:59 +0000393bool fromJSON(const json::Value &Params, CodeActionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000394 json::ObjectMapper O(Params);
395 return O && O.map("textDocument", R.textDocument) &&
396 O.map("range", R.range) && O.map("context", R.context);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000397}
398
Sam McCalld20d7982018-07-09 14:25:59 +0000399bool fromJSON(const json::Value &Params, WorkspaceEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000400 json::ObjectMapper O(Params);
401 return O && O.map("changes", R.changes);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000402}
403
Sam McCallc008af62018-10-20 15:30:37 +0000404const StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000405 "clangd.applyFix";
Sam McCalld20d7982018-07-09 14:25:59 +0000406bool fromJSON(const json::Value &Params, ExecuteCommandParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000407 json::ObjectMapper O(Params);
408 if (!O || !O.map("command", R.command))
409 return false;
Sam McCallec109022017-11-28 09:37:43 +0000410
Sam McCalld20d7982018-07-09 14:25:59 +0000411 auto Args = Params.getAsObject()->getArray("arguments");
Sam McCallff8b8742017-11-30 21:32:29 +0000412 if (R.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
413 return Args && Args->size() == 1 &&
414 fromJSON(Args->front(), R.workspaceEdit);
415 }
416 return false; // Unrecognized command.
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000417}
418
Sam McCalld20d7982018-07-09 14:25:59 +0000419json::Value toJSON(const SymbolInformation &P) {
420 return json::Object{
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000421 {"name", P.name},
422 {"kind", static_cast<int>(P.kind)},
423 {"location", P.location},
424 {"containerName", P.containerName},
425 };
426}
427
Sam McCallc008af62018-10-20 15:30:37 +0000428raw_ostream &operator<<(raw_ostream &O, const SymbolInformation &SI) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000429 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
430 return O;
431}
432
Jan Korousb4067012018-11-27 16:40:46 +0000433bool operator==(const SymbolDetails &LHS, const SymbolDetails &RHS) {
434 return LHS.name == RHS.name && LHS.containerName == RHS.containerName &&
435 LHS.USR == RHS.USR && LHS.ID == RHS.ID;
436}
437
438llvm::json::Value toJSON(const SymbolDetails &P) {
439 json::Object result{{"name", llvm::json::Value(nullptr)},
440 {"containerName", llvm::json::Value(nullptr)},
441 {"usr", llvm::json::Value(nullptr)},
442 {"id", llvm::json::Value(nullptr)}};
443
444 if (!P.name.empty())
445 result["name"] = P.name;
446
447 if (!P.containerName.empty())
448 result["containerName"] = P.containerName;
449
450 if (!P.USR.empty())
451 result["usr"] = P.USR;
452
453 if (P.ID.hasValue())
454 result["id"] = P.ID.getValue().str();
455
Jan Korous613c80d2018-11-28 10:24:07 +0000456 // Older clang cannot compile 'return Result', even though it is legal.
457 return json::Value(std::move(result));
Jan Korousb4067012018-11-27 16:40:46 +0000458}
459
460llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) {
461 if (!S.containerName.empty()) {
462 O << S.containerName;
463 StringRef ContNameRef;
464 if (!ContNameRef.endswith("::")) {
465 O << " ";
466 }
467 }
468 O << S.name << " - " << toJSON(S);
469 return O;
470}
471
Sam McCalld20d7982018-07-09 14:25:59 +0000472bool fromJSON(const json::Value &Params, WorkspaceSymbolParams &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000473 json::ObjectMapper O(Params);
474 return O && O.map("query", R.query);
475}
476
Sam McCalld20d7982018-07-09 14:25:59 +0000477json::Value toJSON(const Command &C) {
478 auto Cmd = json::Object{{"title", C.title}, {"command", C.command}};
Eric Liuc5105f92018-02-16 14:15:55 +0000479 if (C.workspaceEdit)
480 Cmd["arguments"] = {*C.workspaceEdit};
Eric Liuc5105f92018-02-16 14:15:55 +0000481 return std::move(Cmd);
482}
483
Sam McCallc008af62018-10-20 15:30:37 +0000484const StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";
Sam McCall20841d42018-10-16 16:29:41 +0000485
Sam McCallc008af62018-10-20 15:30:37 +0000486json::Value toJSON(const CodeAction &CA) {
Sam McCall20841d42018-10-16 16:29:41 +0000487 auto CodeAction = json::Object{{"title", CA.title}};
488 if (CA.kind)
489 CodeAction["kind"] = *CA.kind;
490 if (CA.diagnostics)
491 CodeAction["diagnostics"] = json::Array(*CA.diagnostics);
492 if (CA.edit)
493 CodeAction["edit"] = *CA.edit;
494 if (CA.command)
495 CodeAction["command"] = *CA.command;
496 return std::move(CodeAction);
497}
498
Ilya Biryukov4174d092018-11-26 09:57:41 +0000499raw_ostream &operator<<(raw_ostream &O, const DocumentSymbol &S) {
Ilya Biryukov19d75602018-11-23 15:21:19 +0000500 return O << S.name << " - " << toJSON(S);
501}
502
Ilya Biryukov4174d092018-11-26 09:57:41 +0000503json::Value toJSON(const DocumentSymbol &S) {
Ilya Biryukov19d75602018-11-23 15:21:19 +0000504 json::Object Result{{"name", S.name},
505 {"kind", static_cast<int>(S.kind)},
506 {"range", S.range},
507 {"selectionRange", S.selectionRange}};
508
509 if (!S.detail.empty())
510 Result["detail"] = S.detail;
511 if (!S.children.empty())
512 Result["children"] = S.children;
513 if (S.deprecated)
514 Result["deprecated"] = true;
Ilya Biryukov4174d092018-11-26 09:57:41 +0000515 // Older gcc cannot compile 'return Result', even though it is legal.
516 return json::Value(std::move(Result));
Ilya Biryukov19d75602018-11-23 15:21:19 +0000517}
518
Sam McCalld20d7982018-07-09 14:25:59 +0000519json::Value toJSON(const WorkspaceEdit &WE) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000520 if (!WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000521 return json::Object{};
522 json::Object FileChanges;
Sam McCalldd0566b2017-11-06 15:40:30 +0000523 for (auto &Change : *WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000524 FileChanges[Change.first] = json::Array(Change.second);
525 return json::Object{{"changes", std::move(FileChanges)}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000526}
527
Sam McCalld20d7982018-07-09 14:25:59 +0000528json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
529 return json::Object{{"edit", Params.edit}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000530}
531
Sam McCalld20d7982018-07-09 14:25:59 +0000532bool fromJSON(const json::Value &Params, TextDocumentPositionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000533 json::ObjectMapper O(Params);
534 return O && O.map("textDocument", R.textDocument) &&
535 O.map("position", R.position);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000536}
537
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000538static StringRef toTextKind(MarkupKind Kind) {
539 switch (Kind) {
540 case MarkupKind::PlainText:
541 return "plaintext";
542 case MarkupKind::Markdown:
543 return "markdown";
544 }
545 llvm_unreachable("Invalid MarkupKind");
546}
547
Sam McCalld20d7982018-07-09 14:25:59 +0000548json::Value toJSON(const MarkupContent &MC) {
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000549 if (MC.value.empty())
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000550 return nullptr;
551
Sam McCalld20d7982018-07-09 14:25:59 +0000552 return json::Object{
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000553 {"kind", toTextKind(MC.kind)},
554 {"value", MC.value},
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000555 };
556}
557
Sam McCalld20d7982018-07-09 14:25:59 +0000558json::Value toJSON(const Hover &H) {
559 json::Object Result{{"contents", toJSON(H.contents)}};
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000560
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000561 if (H.range.hasValue())
562 Result["range"] = toJSON(*H.range);
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000563
564 return std::move(Result);
565}
566
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000567bool fromJSON(const json::Value &E, CompletionItemKind &Out) {
568 if (auto T = E.getAsInteger()) {
569 if (*T < static_cast<int>(CompletionItemKind::Text) ||
570 *T > static_cast<int>(CompletionItemKind::TypeParameter))
571 return false;
572 Out = static_cast<CompletionItemKind>(*T);
573 return true;
574 }
575 return false;
576}
577
578CompletionItemKind
579adjustKindToCapability(CompletionItemKind Kind,
580 CompletionItemKindBitset &supportedCompletionItemKinds) {
581 auto KindVal = static_cast<size_t>(Kind);
582 if (KindVal >= CompletionItemKindMin &&
583 KindVal <= supportedCompletionItemKinds.size() &&
584 supportedCompletionItemKinds[KindVal])
585 return Kind;
586
587 switch (Kind) {
588 // Provide some fall backs for common kinds that are close enough.
589 case CompletionItemKind::Folder:
590 return CompletionItemKind::File;
591 case CompletionItemKind::EnumMember:
592 return CompletionItemKind::Enum;
593 case CompletionItemKind::Struct:
594 return CompletionItemKind::Class;
595 default:
596 return CompletionItemKind::Text;
597 }
598}
599
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000600bool fromJSON(const json::Value &E, CompletionItemKindBitset &Out) {
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000601 if (auto *A = E.getAsArray()) {
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000602 for (size_t I = 0; I < A->size(); ++I) {
603 CompletionItemKind KindOut;
604 if (fromJSON((*A)[I], KindOut))
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000605 Out.set(size_t(KindOut));
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000606 }
607 return true;
608 }
609 return false;
610}
611
Sam McCalld20d7982018-07-09 14:25:59 +0000612json::Value toJSON(const CompletionItem &CI) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000613 assert(!CI.label.empty() && "completion item label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000614 json::Object Result{{"label", CI.label}};
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000615 if (CI.kind != CompletionItemKind::Missing)
Sam McCalldd0566b2017-11-06 15:40:30 +0000616 Result["kind"] = static_cast<int>(CI.kind);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000617 if (!CI.detail.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000618 Result["detail"] = CI.detail;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000619 if (!CI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000620 Result["documentation"] = CI.documentation;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000621 if (!CI.sortText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000622 Result["sortText"] = CI.sortText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000623 if (!CI.filterText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000624 Result["filterText"] = CI.filterText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000625 if (!CI.insertText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000626 Result["insertText"] = CI.insertText;
627 if (CI.insertTextFormat != InsertTextFormat::Missing)
628 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000629 if (CI.textEdit)
Sam McCalldd0566b2017-11-06 15:40:30 +0000630 Result["textEdit"] = *CI.textEdit;
631 if (!CI.additionalTextEdits.empty())
Sam McCalld20d7982018-07-09 14:25:59 +0000632 Result["additionalTextEdits"] = json::Array(CI.additionalTextEdits);
Eric Liu6df66002018-09-06 18:52:26 +0000633 if (CI.deprecated)
634 Result["deprecated"] = CI.deprecated;
Sam McCalldd0566b2017-11-06 15:40:30 +0000635 return std::move(Result);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000636}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000637
Sam McCallc008af62018-10-20 15:30:37 +0000638raw_ostream &operator<<(raw_ostream &O, const CompletionItem &I) {
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000639 O << I.label << " - " << toJSON(I);
640 return O;
641}
642
Sam McCallff8b8742017-11-30 21:32:29 +0000643bool operator<(const CompletionItem &L, const CompletionItem &R) {
Sam McCallc78ccbd2017-11-08 07:44:12 +0000644 return (L.sortText.empty() ? L.label : L.sortText) <
645 (R.sortText.empty() ? R.label : R.sortText);
646}
647
Sam McCalld20d7982018-07-09 14:25:59 +0000648json::Value toJSON(const CompletionList &L) {
649 return json::Object{
Sam McCalla40371b2017-11-15 09:16:29 +0000650 {"isIncomplete", L.isIncomplete},
Sam McCalld20d7982018-07-09 14:25:59 +0000651 {"items", json::Array(L.items)},
Sam McCalla40371b2017-11-15 09:16:29 +0000652 };
653}
654
Sam McCalld20d7982018-07-09 14:25:59 +0000655json::Value toJSON(const ParameterInformation &PI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000656 assert(!PI.label.empty() && "parameter information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000657 json::Object Result{{"label", PI.label}};
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000658 if (!PI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000659 Result["documentation"] = PI.documentation;
660 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000661}
662
Sam McCalld20d7982018-07-09 14:25:59 +0000663json::Value toJSON(const SignatureInformation &SI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000664 assert(!SI.label.empty() && "signature information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000665 json::Object Result{
Sam McCalldd0566b2017-11-06 15:40:30 +0000666 {"label", SI.label},
Sam McCalld20d7982018-07-09 14:25:59 +0000667 {"parameters", json::Array(SI.parameters)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000668 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000669 if (!SI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000670 Result["documentation"] = SI.documentation;
671 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000672}
673
Sam McCallc008af62018-10-20 15:30:37 +0000674raw_ostream &operator<<(raw_ostream &O, const SignatureInformation &I) {
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000675 O << I.label << " - " << toJSON(I);
676 return O;
677}
678
Sam McCalld20d7982018-07-09 14:25:59 +0000679json::Value toJSON(const SignatureHelp &SH) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000680 assert(SH.activeSignature >= 0 &&
681 "Unexpected negative value for number of active signatures.");
682 assert(SH.activeParameter >= 0 &&
683 "Unexpected negative value for active parameter index");
Sam McCalld20d7982018-07-09 14:25:59 +0000684 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000685 {"activeSignature", SH.activeSignature},
686 {"activeParameter", SH.activeParameter},
Sam McCalld20d7982018-07-09 14:25:59 +0000687 {"signatures", json::Array(SH.signatures)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000688 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000689}
Haojian Wu345099c2017-11-09 11:30:04 +0000690
Sam McCalld20d7982018-07-09 14:25:59 +0000691bool fromJSON(const json::Value &Params, RenameParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000692 json::ObjectMapper O(Params);
693 return O && O.map("textDocument", R.textDocument) &&
694 O.map("position", R.position) && O.map("newName", R.newName);
Haojian Wu345099c2017-11-09 11:30:04 +0000695}
Sam McCallff8b8742017-11-30 21:32:29 +0000696
Sam McCalld20d7982018-07-09 14:25:59 +0000697json::Value toJSON(const DocumentHighlight &DH) {
698 return json::Object{
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000699 {"range", toJSON(DH.range)},
700 {"kind", static_cast<int>(DH.kind)},
701 };
702}
703
Sam McCallc008af62018-10-20 15:30:37 +0000704raw_ostream &operator<<(raw_ostream &O, const DocumentHighlight &V) {
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000705 O << V.range;
706 if (V.kind == DocumentHighlightKind::Read)
707 O << "(r)";
708 if (V.kind == DocumentHighlightKind::Write)
709 O << "(w)";
710 return O;
711}
712
Sam McCalld20d7982018-07-09 14:25:59 +0000713bool fromJSON(const json::Value &Params, DidChangeConfigurationParams &CCP) {
Simon Marchi5178f922018-02-22 14:00:39 +0000714 json::ObjectMapper O(Params);
715 return O && O.map("settings", CCP.settings);
716}
717
Sam McCallc008af62018-10-20 15:30:37 +0000718bool fromJSON(const json::Value &Params, ClangdCompileCommand &CDbUpdate) {
Alex Lorenzf8087862018-08-01 17:39:29 +0000719 json::ObjectMapper O(Params);
720 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&
721 O.map("compilationCommand", CDbUpdate.compilationCommand);
722}
723
Sam McCallbc904612018-10-25 04:22:52 +0000724bool fromJSON(const json::Value &Params, ConfigurationSettings &S) {
Simon Marchi5178f922018-02-22 14:00:39 +0000725 json::ObjectMapper O(Params);
Sam McCallbc904612018-10-25 04:22:52 +0000726 if (!O)
727 return true; // 'any' type in LSP.
728 O.map("compilationDatabaseChanges", S.compilationDatabaseChanges);
729 return true;
Simon Marchi5178f922018-02-22 14:00:39 +0000730}
731
Sam McCallbc904612018-10-25 04:22:52 +0000732bool fromJSON(const json::Value &Params, InitializationOptions &Opts) {
Simon Marchiabeed662018-10-16 15:55:03 +0000733 json::ObjectMapper O(Params);
Sam McCallbc904612018-10-25 04:22:52 +0000734 if (!O)
735 return true; // 'any' type in LSP.
736
737 fromJSON(Params, Opts.ConfigSettings);
738 O.map("compilationDatabasePath", Opts.compilationDatabasePath);
Sam McCall6980edb2018-11-02 14:07:51 +0000739 O.map("fallbackFlags", Opts.fallbackFlags);
Sam McCallbc904612018-10-25 04:22:52 +0000740 return true;
Simon Marchiabeed662018-10-16 15:55:03 +0000741}
742
Sam McCall1ad142f2018-09-05 11:53:07 +0000743bool fromJSON(const json::Value &Params, ReferenceParams &R) {
744 TextDocumentPositionParams &Base = R;
745 return fromJSON(Params, Base);
746}
747
Sam McCallff8b8742017-11-30 21:32:29 +0000748} // namespace clangd
749} // namespace clang