blob: 3c1fc7f005075defc1f8a1c77d2c419138d06a53 [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
Eric Liu4d814a92018-11-28 10:30:42 +000033URIForFile URIForFile::canonicalize(StringRef AbsPath, StringRef TUPath) {
Sam McCallc008af62018-10-20 15:30:37 +000034 assert(sys::path::is_absolute(AbsPath) && "the path is relative");
Eric Liu4d814a92018-11-28 10:30:42 +000035 auto Resolved = URI::resolvePath(AbsPath, TUPath);
36 if (!Resolved) {
37 elog("URIForFile: failed to resolve path {0} with TU path {1}: "
38 "{2}.\nUsing unresolved path.",
39 AbsPath, TUPath, Resolved.takeError());
40 return URIForFile(AbsPath);
41 }
42 return URIForFile(std::move(*Resolved));
43}
44
45Expected<URIForFile> URIForFile::fromURI(const URI &U, StringRef HintPath) {
46 auto Resolved = URI::resolve(U, HintPath);
47 if (!Resolved)
48 return Resolved.takeError();
49 return URIForFile(std::move(*Resolved));
Ilya Biryukov7d60d202018-02-16 12:20:47 +000050}
51
Sam McCalld20d7982018-07-09 14:25:59 +000052bool fromJSON(const json::Value &E, URIForFile &R) {
53 if (auto S = E.getAsString()) {
Eric Liu4d814a92018-11-28 10:30:42 +000054 auto Parsed = URI::parse(*S);
55 if (!Parsed) {
56 elog("Failed to parse URI {0}: {1}", *S, Parsed.takeError());
Eric Liu78ed91a72018-01-29 15:37:46 +000057 return false;
58 }
Eric Liu4d814a92018-11-28 10:30:42 +000059 if (Parsed->scheme() != "file" && Parsed->scheme() != "test") {
Sam McCallbed58852018-07-11 10:35:11 +000060 elog("Clangd only supports 'file' URI scheme for workspace files: {0}",
61 *S);
Eric Liu78ed91a72018-01-29 15:37:46 +000062 return false;
63 }
Eric Liu4d814a92018-11-28 10:30:42 +000064 // "file" and "test" schemes do not require hint path.
65 auto U = URIForFile::fromURI(*Parsed, /*HintPath=*/"");
66 if (!U) {
67 elog("{0}", U.takeError());
Sam McCall41d21522018-01-30 11:23:11 +000068 return false;
69 }
Eric Liu4d814a92018-11-28 10:30:42 +000070 R = std::move(*U);
Sam McCallff8b8742017-11-30 21:32:29 +000071 return true;
72 }
73 return false;
Sam McCall38a04912017-11-29 11:36:46 +000074}
75
Sam McCalld20d7982018-07-09 14:25:59 +000076json::Value toJSON(const URIForFile &U) { return U.uri(); }
Krasimir Georgiev50117372017-04-07 11:03:26 +000077
Sam McCallc008af62018-10-20 15:30:37 +000078raw_ostream &operator<<(raw_ostream &OS, const URIForFile &U) {
Eric Liu78ed91a72018-01-29 15:37:46 +000079 return OS << U.uri();
Sam McCallfffa8222017-12-20 10:26:53 +000080}
81
Sam McCalld20d7982018-07-09 14:25:59 +000082json::Value toJSON(const TextDocumentIdentifier &R) {
83 return json::Object{{"uri", R.uri}};
Eric Liuc5105f92018-02-16 14:15:55 +000084}
85
Sam McCalld20d7982018-07-09 14:25:59 +000086bool fromJSON(const json::Value &Params, TextDocumentIdentifier &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000087 json::ObjectMapper O(Params);
88 return O && O.map("uri", R.uri);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000089}
90
Sam McCalld20d7982018-07-09 14:25:59 +000091bool fromJSON(const json::Value &Params, Position &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000092 json::ObjectMapper O(Params);
93 return O && O.map("line", R.line) && O.map("character", R.character);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000094}
95
Sam McCalld20d7982018-07-09 14:25:59 +000096json::Value toJSON(const Position &P) {
97 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +000098 {"line", P.line},
99 {"character", P.character},
100 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000101}
102
Sam McCallc008af62018-10-20 15:30:37 +0000103raw_ostream &operator<<(raw_ostream &OS, const Position &P) {
Sam McCallfffa8222017-12-20 10:26:53 +0000104 return OS << P.line << ':' << P.character;
105}
106
Sam McCalld20d7982018-07-09 14:25:59 +0000107bool fromJSON(const json::Value &Params, Range &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000108 json::ObjectMapper O(Params);
109 return O && O.map("start", R.start) && O.map("end", R.end);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000110}
111
Sam McCalld20d7982018-07-09 14:25:59 +0000112json::Value toJSON(const Range &P) {
113 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000114 {"start", P.start},
115 {"end", P.end},
116 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000117}
118
Sam McCallc008af62018-10-20 15:30:37 +0000119raw_ostream &operator<<(raw_ostream &OS, const Range &R) {
Sam McCallfffa8222017-12-20 10:26:53 +0000120 return OS << R.start << '-' << R.end;
121}
122
Sam McCalld20d7982018-07-09 14:25:59 +0000123json::Value toJSON(const Location &P) {
124 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000125 {"uri", P.uri},
126 {"range", P.range},
127 };
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000128}
129
Sam McCallc008af62018-10-20 15:30:37 +0000130raw_ostream &operator<<(raw_ostream &OS, const Location &L) {
Sam McCallfffa8222017-12-20 10:26:53 +0000131 return OS << L.range << '@' << L.uri;
132}
133
Sam McCalld20d7982018-07-09 14:25:59 +0000134bool fromJSON(const json::Value &Params, TextDocumentItem &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000135 json::ObjectMapper O(Params);
136 return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&
137 O.map("version", R.version) && O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000138}
139
Sam McCalld20d7982018-07-09 14:25:59 +0000140bool fromJSON(const json::Value &Params, TextEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000141 json::ObjectMapper O(Params);
142 return O && O.map("range", R.range) && O.map("newText", R.newText);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000143}
144
Sam McCalld20d7982018-07-09 14:25:59 +0000145json::Value toJSON(const TextEdit &P) {
146 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000147 {"range", P.range},
148 {"newText", P.newText},
149 };
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000150}
151
Sam McCallc008af62018-10-20 15:30:37 +0000152raw_ostream &operator<<(raw_ostream &OS, const TextEdit &TE) {
Sam McCall034e11a2018-01-25 17:29:17 +0000153 OS << TE.range << " => \"";
Jonas Devlieghere1ab6a7a2018-05-31 17:36:31 +0000154 printEscapedString(TE.newText, OS);
Sam McCall034e11a2018-01-25 17:29:17 +0000155 return OS << '"';
156}
157
Sam McCalld20d7982018-07-09 14:25:59 +0000158bool fromJSON(const json::Value &E, TraceLevel &Out) {
159 if (auto S = E.getAsString()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000160 if (*S == "off") {
161 Out = TraceLevel::Off;
162 return true;
163 } else if (*S == "messages") {
164 Out = TraceLevel::Messages;
165 return true;
166 } else if (*S == "verbose") {
167 Out = TraceLevel::Verbose;
168 return true;
169 }
170 }
171 return false;
172}
173
Sam McCalld20d7982018-07-09 14:25:59 +0000174bool fromJSON(const json::Value &E, SymbolKind &Out) {
175 if (auto T = E.getAsInteger()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000176 if (*T < static_cast<int>(SymbolKind::File) ||
177 *T > static_cast<int>(SymbolKind::TypeParameter))
178 return false;
179 Out = static_cast<SymbolKind>(*T);
180 return true;
181 }
182 return false;
183}
184
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000185bool fromJSON(const json::Value &E, SymbolKindBitset &Out) {
Sam McCalld20d7982018-07-09 14:25:59 +0000186 if (auto *A = E.getAsArray()) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000187 for (size_t I = 0; I < A->size(); ++I) {
188 SymbolKind KindOut;
189 if (fromJSON((*A)[I], KindOut))
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000190 Out.set(size_t(KindOut));
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000191 }
192 return true;
193 }
194 return false;
195}
196
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000197SymbolKind adjustKindToCapability(SymbolKind Kind,
Ilya Biryukov74f26552018-07-26 12:05:31 +0000198 SymbolKindBitset &SupportedSymbolKinds) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000199 auto KindVal = static_cast<size_t>(Kind);
Ilya Biryukov74f26552018-07-26 12:05:31 +0000200 if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() &&
201 SupportedSymbolKinds[KindVal])
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000202 return Kind;
203
204 switch (Kind) {
205 // Provide some fall backs for common kinds that are close enough.
206 case SymbolKind::Struct:
207 return SymbolKind::Class;
208 case SymbolKind::EnumMember:
209 return SymbolKind::Enum;
210 default:
211 return SymbolKind::String;
212 }
213}
214
Sam McCalld20d7982018-07-09 14:25:59 +0000215bool fromJSON(const json::Value &Params, ClientCapabilities &R) {
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000216 const json::Object *O = Params.getAsObject();
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000217 if (!O)
218 return false;
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000219 if (auto *TextDocument = O->getObject("textDocument")) {
220 if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {
221 if (auto CategorySupport = Diagnostics->getBoolean("categorySupport"))
222 R.DiagnosticCategory = *CategorySupport;
Sam McCall16e70702018-10-24 07:59:38 +0000223 if (auto CodeActions = Diagnostics->getBoolean("codeActionsInline"))
224 R.DiagnosticFixes = *CodeActions;
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000225 }
226 if (auto *Completion = TextDocument->getObject("completion")) {
227 if (auto *Item = Completion->getObject("completionItem")) {
228 if (auto SnippetSupport = Item->getBoolean("snippetSupport"))
229 R.CompletionSnippets = *SnippetSupport;
230 }
231 if (auto *ItemKind = Completion->getObject("completionItemKind")) {
232 if (auto *ValueSet = ItemKind->get("valueSet")) {
233 R.CompletionItemKinds.emplace();
234 if (!fromJSON(*ValueSet, *R.CompletionItemKinds))
235 return false;
236 }
237 }
238 }
239 if (auto *CodeAction = TextDocument->getObject("codeAction")) {
240 if (CodeAction->getObject("codeActionLiteralSupport"))
241 R.CodeActionStructure = true;
242 }
Ilya Biryukov19d75602018-11-23 15:21:19 +0000243 if (auto *DocumentSymbol = TextDocument->getObject("documentSymbol")) {
244 if (auto HierarchicalSupport =
245 DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
246 R.HierarchicalDocumentSymbol = *HierarchicalSupport;
247 }
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000248 }
249 if (auto *Workspace = O->getObject("workspace")) {
250 if (auto *Symbol = Workspace->getObject("symbol")) {
251 if (auto *SymbolKind = Symbol->getObject("symbolKind")) {
252 if (auto *ValueSet = SymbolKind->get("valueSet")) {
253 R.WorkspaceSymbolKinds.emplace();
254 if (!fromJSON(*ValueSet, *R.WorkspaceSymbolKinds))
255 return false;
256 }
257 }
258 }
259 }
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000260 return true;
261}
262
Sam McCalld20d7982018-07-09 14:25:59 +0000263bool fromJSON(const json::Value &Params, InitializeParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000264 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000265 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000266 return false;
Sam McCall38a04912017-11-29 11:36:46 +0000267 // We deliberately don't fail if we can't parse individual fields.
268 // Failing to handle a slightly malformed initialize would be a disaster.
Sam McCallff8b8742017-11-30 21:32:29 +0000269 O.map("processId", R.processId);
270 O.map("rootUri", R.rootUri);
271 O.map("rootPath", R.rootPath);
Ilya Biryukov23bc73b2018-02-15 14:32:57 +0000272 O.map("capabilities", R.capabilities);
Sam McCallff8b8742017-11-30 21:32:29 +0000273 O.map("trace", R.trace);
Simon Marchi88016782018-08-01 11:28:49 +0000274 O.map("initializationOptions", R.initializationOptions);
Sam McCallff8b8742017-11-30 21:32:29 +0000275 return true;
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000276}
277
Sam McCalld20d7982018-07-09 14:25:59 +0000278bool fromJSON(const json::Value &Params, DidOpenTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000279 json::ObjectMapper O(Params);
Sam McCall2eb6b402018-11-02 13:06:55 +0000280 return O && O.map("textDocument", R.textDocument);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000281}
282
Sam McCalld20d7982018-07-09 14:25:59 +0000283bool fromJSON(const json::Value &Params, DidCloseTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000284 json::ObjectMapper O(Params);
285 return O && O.map("textDocument", R.textDocument);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000286}
287
Sam McCalld20d7982018-07-09 14:25:59 +0000288bool fromJSON(const json::Value &Params, DidChangeTextDocumentParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000289 json::ObjectMapper O(Params);
290 return O && O.map("textDocument", R.textDocument) &&
Eric Liu51fed182018-02-22 18:40:39 +0000291 O.map("contentChanges", R.contentChanges) &&
292 O.map("wantDiagnostics", R.wantDiagnostics);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000293}
294
Sam McCalld20d7982018-07-09 14:25:59 +0000295bool fromJSON(const json::Value &E, FileChangeType &Out) {
296 if (auto T = E.getAsInteger()) {
Sam McCallff8b8742017-11-30 21:32:29 +0000297 if (*T < static_cast<int>(FileChangeType::Created) ||
298 *T > static_cast<int>(FileChangeType::Deleted))
299 return false;
300 Out = static_cast<FileChangeType>(*T);
301 return true;
302 }
303 return false;
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000304}
305
Sam McCalld20d7982018-07-09 14:25:59 +0000306bool fromJSON(const json::Value &Params, FileEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000307 json::ObjectMapper O(Params);
308 return O && O.map("uri", R.uri) && O.map("type", R.type);
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000309}
310
Sam McCalld20d7982018-07-09 14:25:59 +0000311bool fromJSON(const json::Value &Params, DidChangeWatchedFilesParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000312 json::ObjectMapper O(Params);
313 return O && O.map("changes", R.changes);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000314}
315
Sam McCalld20d7982018-07-09 14:25:59 +0000316bool fromJSON(const json::Value &Params, TextDocumentContentChangeEvent &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000317 json::ObjectMapper O(Params);
Simon Marchi98082622018-03-26 14:41:40 +0000318 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
319 O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000320}
321
Sam McCalld20d7982018-07-09 14:25:59 +0000322bool fromJSON(const json::Value &Params, FormattingOptions &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000323 json::ObjectMapper O(Params);
324 return O && O.map("tabSize", R.tabSize) &&
325 O.map("insertSpaces", R.insertSpaces);
326}
327
Sam McCalld20d7982018-07-09 14:25:59 +0000328json::Value toJSON(const FormattingOptions &P) {
329 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000330 {"tabSize", P.tabSize},
331 {"insertSpaces", P.insertSpaces},
332 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000333}
334
Sam McCalld20d7982018-07-09 14:25:59 +0000335bool fromJSON(const json::Value &Params, DocumentRangeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000336 json::ObjectMapper O(Params);
337 return O && O.map("textDocument", R.textDocument) &&
338 O.map("range", R.range) && O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000339}
340
Sam McCalld20d7982018-07-09 14:25:59 +0000341bool fromJSON(const json::Value &Params, DocumentOnTypeFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000342 json::ObjectMapper O(Params);
343 return O && O.map("textDocument", R.textDocument) &&
344 O.map("position", R.position) && O.map("ch", R.ch) &&
345 O.map("options", R.options);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000346}
347
Sam McCalld20d7982018-07-09 14:25:59 +0000348bool fromJSON(const json::Value &Params, DocumentFormattingParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000349 json::ObjectMapper O(Params);
350 return O && O.map("textDocument", R.textDocument) &&
351 O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000352}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000353
Sam McCalld20d7982018-07-09 14:25:59 +0000354bool fromJSON(const json::Value &Params, DocumentSymbolParams &R) {
Marc-Andre Laperle1be69702018-07-05 19:35:01 +0000355 json::ObjectMapper O(Params);
356 return O && O.map("textDocument", R.textDocument);
357}
358
Sam McCallc008af62018-10-20 15:30:37 +0000359json::Value toJSON(const Diagnostic &D) {
Sam McCall20841d42018-10-16 16:29:41 +0000360 json::Object Diag{
361 {"range", D.range},
362 {"severity", D.severity},
363 {"message", D.message},
364 };
Sam McCall16e70702018-10-24 07:59:38 +0000365 if (D.category)
366 Diag["category"] = *D.category;
367 if (D.codeActions)
368 Diag["codeActions"] = D.codeActions;
Sam McCall20841d42018-10-16 16:29:41 +0000369 return std::move(Diag);
370}
371
Sam McCalld20d7982018-07-09 14:25:59 +0000372bool fromJSON(const json::Value &Params, Diagnostic &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000373 json::ObjectMapper O(Params);
374 if (!O || !O.map("range", R.range) || !O.map("message", R.message))
375 return false;
376 O.map("severity", R.severity);
Sam McCall16e70702018-10-24 07:59:38 +0000377 O.map("category", R.category);
Sam McCallff8b8742017-11-30 21:32:29 +0000378 return true;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000379}
380
Sam McCalld20d7982018-07-09 14:25:59 +0000381bool fromJSON(const json::Value &Params, CodeActionContext &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000382 json::ObjectMapper O(Params);
383 return O && O.map("diagnostics", R.diagnostics);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000384}
385
Sam McCallc008af62018-10-20 15:30:37 +0000386raw_ostream &operator<<(raw_ostream &OS, const Diagnostic &D) {
Sam McCall034e11a2018-01-25 17:29:17 +0000387 OS << D.range << " [";
388 switch (D.severity) {
389 case 1:
390 OS << "error";
391 break;
392 case 2:
393 OS << "warning";
394 break;
395 case 3:
396 OS << "note";
397 break;
398 case 4:
399 OS << "remark";
400 break;
401 default:
402 OS << "diagnostic";
403 break;
404 }
405 return OS << '(' << D.severity << "): " << D.message << "]";
406}
407
Sam McCalld20d7982018-07-09 14:25:59 +0000408bool fromJSON(const json::Value &Params, CodeActionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000409 json::ObjectMapper O(Params);
410 return O && O.map("textDocument", R.textDocument) &&
411 O.map("range", R.range) && O.map("context", R.context);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000412}
413
Sam McCalld20d7982018-07-09 14:25:59 +0000414bool fromJSON(const json::Value &Params, WorkspaceEdit &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000415 json::ObjectMapper O(Params);
416 return O && O.map("changes", R.changes);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000417}
418
Sam McCallc008af62018-10-20 15:30:37 +0000419const StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000420 "clangd.applyFix";
Sam McCalld20d7982018-07-09 14:25:59 +0000421bool fromJSON(const json::Value &Params, ExecuteCommandParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000422 json::ObjectMapper O(Params);
423 if (!O || !O.map("command", R.command))
424 return false;
Sam McCallec109022017-11-28 09:37:43 +0000425
Sam McCalld20d7982018-07-09 14:25:59 +0000426 auto Args = Params.getAsObject()->getArray("arguments");
Sam McCallff8b8742017-11-30 21:32:29 +0000427 if (R.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
428 return Args && Args->size() == 1 &&
429 fromJSON(Args->front(), R.workspaceEdit);
430 }
431 return false; // Unrecognized command.
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000432}
433
Sam McCalld20d7982018-07-09 14:25:59 +0000434json::Value toJSON(const SymbolInformation &P) {
435 return json::Object{
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000436 {"name", P.name},
437 {"kind", static_cast<int>(P.kind)},
438 {"location", P.location},
439 {"containerName", P.containerName},
440 };
441}
442
Sam McCallc008af62018-10-20 15:30:37 +0000443raw_ostream &operator<<(raw_ostream &O, const SymbolInformation &SI) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000444 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
445 return O;
446}
447
Jan Korousb4067012018-11-27 16:40:46 +0000448bool operator==(const SymbolDetails &LHS, const SymbolDetails &RHS) {
449 return LHS.name == RHS.name && LHS.containerName == RHS.containerName &&
450 LHS.USR == RHS.USR && LHS.ID == RHS.ID;
451}
452
453llvm::json::Value toJSON(const SymbolDetails &P) {
454 json::Object result{{"name", llvm::json::Value(nullptr)},
455 {"containerName", llvm::json::Value(nullptr)},
456 {"usr", llvm::json::Value(nullptr)},
457 {"id", llvm::json::Value(nullptr)}};
458
459 if (!P.name.empty())
460 result["name"] = P.name;
461
462 if (!P.containerName.empty())
463 result["containerName"] = P.containerName;
464
465 if (!P.USR.empty())
466 result["usr"] = P.USR;
467
468 if (P.ID.hasValue())
469 result["id"] = P.ID.getValue().str();
470
Jan Korous613c80d2018-11-28 10:24:07 +0000471 // Older clang cannot compile 'return Result', even though it is legal.
472 return json::Value(std::move(result));
Jan Korousb4067012018-11-27 16:40:46 +0000473}
474
475llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) {
476 if (!S.containerName.empty()) {
477 O << S.containerName;
478 StringRef ContNameRef;
479 if (!ContNameRef.endswith("::")) {
480 O << " ";
481 }
482 }
483 O << S.name << " - " << toJSON(S);
484 return O;
485}
486
Sam McCalld20d7982018-07-09 14:25:59 +0000487bool fromJSON(const json::Value &Params, WorkspaceSymbolParams &R) {
Marc-Andre Laperleb387b6e2018-04-23 20:00:52 +0000488 json::ObjectMapper O(Params);
489 return O && O.map("query", R.query);
490}
491
Sam McCalld20d7982018-07-09 14:25:59 +0000492json::Value toJSON(const Command &C) {
493 auto Cmd = json::Object{{"title", C.title}, {"command", C.command}};
Eric Liuc5105f92018-02-16 14:15:55 +0000494 if (C.workspaceEdit)
495 Cmd["arguments"] = {*C.workspaceEdit};
Eric Liuc5105f92018-02-16 14:15:55 +0000496 return std::move(Cmd);
497}
498
Sam McCallc008af62018-10-20 15:30:37 +0000499const StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";
Sam McCall20841d42018-10-16 16:29:41 +0000500
Sam McCallc008af62018-10-20 15:30:37 +0000501json::Value toJSON(const CodeAction &CA) {
Sam McCall20841d42018-10-16 16:29:41 +0000502 auto CodeAction = json::Object{{"title", CA.title}};
503 if (CA.kind)
504 CodeAction["kind"] = *CA.kind;
505 if (CA.diagnostics)
506 CodeAction["diagnostics"] = json::Array(*CA.diagnostics);
507 if (CA.edit)
508 CodeAction["edit"] = *CA.edit;
509 if (CA.command)
510 CodeAction["command"] = *CA.command;
511 return std::move(CodeAction);
512}
513
Ilya Biryukov4174d092018-11-26 09:57:41 +0000514raw_ostream &operator<<(raw_ostream &O, const DocumentSymbol &S) {
Ilya Biryukov19d75602018-11-23 15:21:19 +0000515 return O << S.name << " - " << toJSON(S);
516}
517
Ilya Biryukov4174d092018-11-26 09:57:41 +0000518json::Value toJSON(const DocumentSymbol &S) {
Ilya Biryukov19d75602018-11-23 15:21:19 +0000519 json::Object Result{{"name", S.name},
520 {"kind", static_cast<int>(S.kind)},
521 {"range", S.range},
522 {"selectionRange", S.selectionRange}};
523
524 if (!S.detail.empty())
525 Result["detail"] = S.detail;
526 if (!S.children.empty())
527 Result["children"] = S.children;
528 if (S.deprecated)
529 Result["deprecated"] = true;
Ilya Biryukov4174d092018-11-26 09:57:41 +0000530 // Older gcc cannot compile 'return Result', even though it is legal.
531 return json::Value(std::move(Result));
Ilya Biryukov19d75602018-11-23 15:21:19 +0000532}
533
Sam McCalld20d7982018-07-09 14:25:59 +0000534json::Value toJSON(const WorkspaceEdit &WE) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000535 if (!WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000536 return json::Object{};
537 json::Object FileChanges;
Sam McCalldd0566b2017-11-06 15:40:30 +0000538 for (auto &Change : *WE.changes)
Sam McCalld20d7982018-07-09 14:25:59 +0000539 FileChanges[Change.first] = json::Array(Change.second);
540 return json::Object{{"changes", std::move(FileChanges)}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000541}
542
Sam McCalld20d7982018-07-09 14:25:59 +0000543json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
544 return json::Object{{"edit", Params.edit}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000545}
546
Sam McCalld20d7982018-07-09 14:25:59 +0000547bool fromJSON(const json::Value &Params, TextDocumentPositionParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000548 json::ObjectMapper O(Params);
549 return O && O.map("textDocument", R.textDocument) &&
550 O.map("position", R.position);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000551}
552
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000553static StringRef toTextKind(MarkupKind Kind) {
554 switch (Kind) {
555 case MarkupKind::PlainText:
556 return "plaintext";
557 case MarkupKind::Markdown:
558 return "markdown";
559 }
560 llvm_unreachable("Invalid MarkupKind");
561}
562
Sam McCalld20d7982018-07-09 14:25:59 +0000563json::Value toJSON(const MarkupContent &MC) {
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000564 if (MC.value.empty())
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000565 return nullptr;
566
Sam McCalld20d7982018-07-09 14:25:59 +0000567 return json::Object{
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000568 {"kind", toTextKind(MC.kind)},
569 {"value", MC.value},
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000570 };
571}
572
Sam McCalld20d7982018-07-09 14:25:59 +0000573json::Value toJSON(const Hover &H) {
574 json::Object Result{{"contents", toJSON(H.contents)}};
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000575
Marc-Andre Laperle373e30a2018-02-16 23:12:26 +0000576 if (H.range.hasValue())
577 Result["range"] = toJSON(*H.range);
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000578
579 return std::move(Result);
580}
581
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000582bool fromJSON(const json::Value &E, CompletionItemKind &Out) {
583 if (auto T = E.getAsInteger()) {
584 if (*T < static_cast<int>(CompletionItemKind::Text) ||
585 *T > static_cast<int>(CompletionItemKind::TypeParameter))
586 return false;
587 Out = static_cast<CompletionItemKind>(*T);
588 return true;
589 }
590 return false;
591}
592
593CompletionItemKind
594adjustKindToCapability(CompletionItemKind Kind,
595 CompletionItemKindBitset &supportedCompletionItemKinds) {
596 auto KindVal = static_cast<size_t>(Kind);
597 if (KindVal >= CompletionItemKindMin &&
598 KindVal <= supportedCompletionItemKinds.size() &&
599 supportedCompletionItemKinds[KindVal])
600 return Kind;
601
602 switch (Kind) {
603 // Provide some fall backs for common kinds that are close enough.
604 case CompletionItemKind::Folder:
605 return CompletionItemKind::File;
606 case CompletionItemKind::EnumMember:
607 return CompletionItemKind::Enum;
608 case CompletionItemKind::Struct:
609 return CompletionItemKind::Class;
610 default:
611 return CompletionItemKind::Text;
612 }
613}
614
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000615bool fromJSON(const json::Value &E, CompletionItemKindBitset &Out) {
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000616 if (auto *A = E.getAsArray()) {
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000617 for (size_t I = 0; I < A->size(); ++I) {
618 CompletionItemKind KindOut;
619 if (fromJSON((*A)[I], KindOut))
Sam McCallbf6a2fc2018-10-17 07:33:42 +0000620 Out.set(size_t(KindOut));
Kadir Cetinkaya133d46f2018-09-27 17:13:07 +0000621 }
622 return true;
623 }
624 return false;
625}
626
Sam McCalld20d7982018-07-09 14:25:59 +0000627json::Value toJSON(const CompletionItem &CI) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000628 assert(!CI.label.empty() && "completion item label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000629 json::Object Result{{"label", CI.label}};
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000630 if (CI.kind != CompletionItemKind::Missing)
Sam McCalldd0566b2017-11-06 15:40:30 +0000631 Result["kind"] = static_cast<int>(CI.kind);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000632 if (!CI.detail.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000633 Result["detail"] = CI.detail;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000634 if (!CI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000635 Result["documentation"] = CI.documentation;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000636 if (!CI.sortText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000637 Result["sortText"] = CI.sortText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000638 if (!CI.filterText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000639 Result["filterText"] = CI.filterText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000640 if (!CI.insertText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000641 Result["insertText"] = CI.insertText;
642 if (CI.insertTextFormat != InsertTextFormat::Missing)
643 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000644 if (CI.textEdit)
Sam McCalldd0566b2017-11-06 15:40:30 +0000645 Result["textEdit"] = *CI.textEdit;
646 if (!CI.additionalTextEdits.empty())
Sam McCalld20d7982018-07-09 14:25:59 +0000647 Result["additionalTextEdits"] = json::Array(CI.additionalTextEdits);
Eric Liu6df66002018-09-06 18:52:26 +0000648 if (CI.deprecated)
649 Result["deprecated"] = CI.deprecated;
Sam McCalldd0566b2017-11-06 15:40:30 +0000650 return std::move(Result);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000651}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000652
Sam McCallc008af62018-10-20 15:30:37 +0000653raw_ostream &operator<<(raw_ostream &O, const CompletionItem &I) {
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000654 O << I.label << " - " << toJSON(I);
655 return O;
656}
657
Sam McCallff8b8742017-11-30 21:32:29 +0000658bool operator<(const CompletionItem &L, const CompletionItem &R) {
Sam McCallc78ccbd2017-11-08 07:44:12 +0000659 return (L.sortText.empty() ? L.label : L.sortText) <
660 (R.sortText.empty() ? R.label : R.sortText);
661}
662
Sam McCalld20d7982018-07-09 14:25:59 +0000663json::Value toJSON(const CompletionList &L) {
664 return json::Object{
Sam McCalla40371b2017-11-15 09:16:29 +0000665 {"isIncomplete", L.isIncomplete},
Sam McCalld20d7982018-07-09 14:25:59 +0000666 {"items", json::Array(L.items)},
Sam McCalla40371b2017-11-15 09:16:29 +0000667 };
668}
669
Sam McCalld20d7982018-07-09 14:25:59 +0000670json::Value toJSON(const ParameterInformation &PI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000671 assert(!PI.label.empty() && "parameter information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000672 json::Object Result{{"label", PI.label}};
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000673 if (!PI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000674 Result["documentation"] = PI.documentation;
675 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000676}
677
Sam McCalld20d7982018-07-09 14:25:59 +0000678json::Value toJSON(const SignatureInformation &SI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000679 assert(!SI.label.empty() && "signature information label is required");
Sam McCalld20d7982018-07-09 14:25:59 +0000680 json::Object Result{
Sam McCalldd0566b2017-11-06 15:40:30 +0000681 {"label", SI.label},
Sam McCalld20d7982018-07-09 14:25:59 +0000682 {"parameters", json::Array(SI.parameters)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000683 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000684 if (!SI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000685 Result["documentation"] = SI.documentation;
686 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000687}
688
Sam McCallc008af62018-10-20 15:30:37 +0000689raw_ostream &operator<<(raw_ostream &O, const SignatureInformation &I) {
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000690 O << I.label << " - " << toJSON(I);
691 return O;
692}
693
Sam McCalld20d7982018-07-09 14:25:59 +0000694json::Value toJSON(const SignatureHelp &SH) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000695 assert(SH.activeSignature >= 0 &&
696 "Unexpected negative value for number of active signatures.");
697 assert(SH.activeParameter >= 0 &&
698 "Unexpected negative value for active parameter index");
Sam McCalld20d7982018-07-09 14:25:59 +0000699 return json::Object{
Sam McCalldd0566b2017-11-06 15:40:30 +0000700 {"activeSignature", SH.activeSignature},
701 {"activeParameter", SH.activeParameter},
Sam McCalld20d7982018-07-09 14:25:59 +0000702 {"signatures", json::Array(SH.signatures)},
Sam McCalldd0566b2017-11-06 15:40:30 +0000703 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000704}
Haojian Wu345099c2017-11-09 11:30:04 +0000705
Sam McCalld20d7982018-07-09 14:25:59 +0000706bool fromJSON(const json::Value &Params, RenameParams &R) {
Sam McCallff8b8742017-11-30 21:32:29 +0000707 json::ObjectMapper O(Params);
708 return O && O.map("textDocument", R.textDocument) &&
709 O.map("position", R.position) && O.map("newName", R.newName);
Haojian Wu345099c2017-11-09 11:30:04 +0000710}
Sam McCallff8b8742017-11-30 21:32:29 +0000711
Sam McCalld20d7982018-07-09 14:25:59 +0000712json::Value toJSON(const DocumentHighlight &DH) {
713 return json::Object{
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000714 {"range", toJSON(DH.range)},
715 {"kind", static_cast<int>(DH.kind)},
716 };
717}
718
Haojian Wub6188492018-12-20 15:39:12 +0000719llvm::json::Value toJSON(const FileStatus &FStatus) {
720 return json::Object{
721 {"uri", FStatus.uri}, {"state", FStatus.state},
722 };
723}
724
Sam McCallc008af62018-10-20 15:30:37 +0000725raw_ostream &operator<<(raw_ostream &O, const DocumentHighlight &V) {
Marc-Andre Laperle90a937e2018-04-10 17:34:46 +0000726 O << V.range;
727 if (V.kind == DocumentHighlightKind::Read)
728 O << "(r)";
729 if (V.kind == DocumentHighlightKind::Write)
730 O << "(w)";
731 return O;
732}
733
Sam McCalld20d7982018-07-09 14:25:59 +0000734bool fromJSON(const json::Value &Params, DidChangeConfigurationParams &CCP) {
Simon Marchi5178f922018-02-22 14:00:39 +0000735 json::ObjectMapper O(Params);
736 return O && O.map("settings", CCP.settings);
737}
738
Sam McCallc008af62018-10-20 15:30:37 +0000739bool fromJSON(const json::Value &Params, ClangdCompileCommand &CDbUpdate) {
Alex Lorenzf8087862018-08-01 17:39:29 +0000740 json::ObjectMapper O(Params);
741 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&
742 O.map("compilationCommand", CDbUpdate.compilationCommand);
743}
744
Sam McCallbc904612018-10-25 04:22:52 +0000745bool fromJSON(const json::Value &Params, ConfigurationSettings &S) {
Simon Marchi5178f922018-02-22 14:00:39 +0000746 json::ObjectMapper O(Params);
Sam McCallbc904612018-10-25 04:22:52 +0000747 if (!O)
748 return true; // 'any' type in LSP.
749 O.map("compilationDatabaseChanges", S.compilationDatabaseChanges);
750 return true;
Simon Marchi5178f922018-02-22 14:00:39 +0000751}
752
Sam McCallbc904612018-10-25 04:22:52 +0000753bool fromJSON(const json::Value &Params, InitializationOptions &Opts) {
Simon Marchiabeed662018-10-16 15:55:03 +0000754 json::ObjectMapper O(Params);
Sam McCallbc904612018-10-25 04:22:52 +0000755 if (!O)
756 return true; // 'any' type in LSP.
757
758 fromJSON(Params, Opts.ConfigSettings);
759 O.map("compilationDatabasePath", Opts.compilationDatabasePath);
Sam McCall6980edb2018-11-02 14:07:51 +0000760 O.map("fallbackFlags", Opts.fallbackFlags);
Haojian Wub6188492018-12-20 15:39:12 +0000761 O.map("clangdFileStatus", Opts.FileStatus);
Sam McCallbc904612018-10-25 04:22:52 +0000762 return true;
Simon Marchiabeed662018-10-16 15:55:03 +0000763}
764
Sam McCall1ad142f2018-09-05 11:53:07 +0000765bool fromJSON(const json::Value &Params, ReferenceParams &R) {
766 TextDocumentPositionParams &Base = R;
767 return fromJSON(Params, Base);
768}
769
Sam McCallff8b8742017-11-30 21:32:29 +0000770} // namespace clangd
771} // namespace clang