1 //===--- Protocol.cpp - Language Server Protocol Implementation -----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the serialization code for the LSP structs.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "Protocol.h"
14 #include "URI.h"
15 #include "support/Logger.h"
16 #include "clang/Basic/LLVM.h"
17 #include "clang/Index/IndexSymbol.h"
18 #include "llvm/ADT/Hashing.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/ADT/StringSwitch.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/Format.h"
23 #include "llvm/Support/FormatVariadic.h"
24 #include "llvm/Support/JSON.h"
25 #include "llvm/Support/Path.h"
26 #include "llvm/Support/raw_ostream.h"
27
28 namespace clang {
29 namespace clangd {
30
31 char LSPError::ID;
32
canonicalize(llvm::StringRef AbsPath,llvm::StringRef TUPath)33 URIForFile URIForFile::canonicalize(llvm::StringRef AbsPath,
34 llvm::StringRef TUPath) {
35 assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative");
36 auto Resolved = URI::resolvePath(AbsPath, TUPath);
37 if (!Resolved) {
38 elog("URIForFile: failed to resolve path {0} with TU path {1}: "
39 "{2}.\nUsing unresolved path.",
40 AbsPath, TUPath, Resolved.takeError());
41 return URIForFile(std::string(AbsPath));
42 }
43 return URIForFile(std::move(*Resolved));
44 }
45
fromURI(const URI & U,llvm::StringRef HintPath)46 llvm::Expected<URIForFile> URIForFile::fromURI(const URI &U,
47 llvm::StringRef HintPath) {
48 auto Resolved = URI::resolve(U, HintPath);
49 if (!Resolved)
50 return Resolved.takeError();
51 return URIForFile(std::move(*Resolved));
52 }
53
fromJSON(const llvm::json::Value & E,URIForFile & R)54 bool fromJSON(const llvm::json::Value &E, URIForFile &R) {
55 if (auto S = E.getAsString()) {
56 auto Parsed = URI::parse(*S);
57 if (!Parsed) {
58 elog("Failed to parse URI {0}: {1}", *S, Parsed.takeError());
59 return false;
60 }
61 if (Parsed->scheme() != "file" && Parsed->scheme() != "test") {
62 elog("Clangd only supports 'file' URI scheme for workspace files: {0}",
63 *S);
64 return false;
65 }
66 // "file" and "test" schemes do not require hint path.
67 auto U = URIForFile::fromURI(*Parsed, /*HintPath=*/"");
68 if (!U) {
69 elog("{0}", U.takeError());
70 return false;
71 }
72 R = std::move(*U);
73 return true;
74 }
75 return false;
76 }
77
toJSON(const URIForFile & U)78 llvm::json::Value toJSON(const URIForFile &U) { return U.uri(); }
79
operator <<(llvm::raw_ostream & OS,const URIForFile & U)80 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) {
81 return OS << U.uri();
82 }
83
toJSON(const TextDocumentIdentifier & R)84 llvm::json::Value toJSON(const TextDocumentIdentifier &R) {
85 return llvm::json::Object{{"uri", R.uri}};
86 }
87
fromJSON(const llvm::json::Value & Params,TextDocumentIdentifier & R)88 bool fromJSON(const llvm::json::Value &Params, TextDocumentIdentifier &R) {
89 llvm::json::ObjectMapper O(Params);
90 return O && O.map("uri", R.uri);
91 }
92
toJSON(const VersionedTextDocumentIdentifier & R)93 llvm::json::Value toJSON(const VersionedTextDocumentIdentifier &R) {
94 auto Result = toJSON(static_cast<const TextDocumentIdentifier &>(R));
95 Result.getAsObject()->try_emplace("version", R.version);
96 return Result;
97 }
98
fromJSON(const llvm::json::Value & Params,VersionedTextDocumentIdentifier & R)99 bool fromJSON(const llvm::json::Value &Params,
100 VersionedTextDocumentIdentifier &R) {
101 llvm::json::ObjectMapper O(Params);
102 return fromJSON(Params, static_cast<TextDocumentIdentifier &>(R)) && O &&
103 O.map("version", R.version);
104 }
105
fromJSON(const llvm::json::Value & Params,Position & R)106 bool fromJSON(const llvm::json::Value &Params, Position &R) {
107 llvm::json::ObjectMapper O(Params);
108 return O && O.map("line", R.line) && O.map("character", R.character);
109 }
110
toJSON(const Position & P)111 llvm::json::Value toJSON(const Position &P) {
112 return llvm::json::Object{
113 {"line", P.line},
114 {"character", P.character},
115 };
116 }
117
operator <<(llvm::raw_ostream & OS,const Position & P)118 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) {
119 return OS << P.line << ':' << P.character;
120 }
121
fromJSON(const llvm::json::Value & Params,Range & R)122 bool fromJSON(const llvm::json::Value &Params, Range &R) {
123 llvm::json::ObjectMapper O(Params);
124 return O && O.map("start", R.start) && O.map("end", R.end);
125 }
126
toJSON(const Range & P)127 llvm::json::Value toJSON(const Range &P) {
128 return llvm::json::Object{
129 {"start", P.start},
130 {"end", P.end},
131 };
132 }
133
operator <<(llvm::raw_ostream & OS,const Range & R)134 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) {
135 return OS << R.start << '-' << R.end;
136 }
137
toJSON(const Location & P)138 llvm::json::Value toJSON(const Location &P) {
139 return llvm::json::Object{
140 {"uri", P.uri},
141 {"range", P.range},
142 };
143 }
144
operator <<(llvm::raw_ostream & OS,const Location & L)145 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) {
146 return OS << L.range << '@' << L.uri;
147 }
148
fromJSON(const llvm::json::Value & Params,TextDocumentItem & R)149 bool fromJSON(const llvm::json::Value &Params, TextDocumentItem &R) {
150 llvm::json::ObjectMapper O(Params);
151 return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&
152 O.map("version", R.version) && O.map("text", R.text);
153 }
154
fromJSON(const llvm::json::Value & Params,TextEdit & R)155 bool fromJSON(const llvm::json::Value &Params, TextEdit &R) {
156 llvm::json::ObjectMapper O(Params);
157 return O && O.map("range", R.range) && O.map("newText", R.newText);
158 }
159
toJSON(const TextEdit & P)160 llvm::json::Value toJSON(const TextEdit &P) {
161 return llvm::json::Object{
162 {"range", P.range},
163 {"newText", P.newText},
164 };
165 }
166
operator <<(llvm::raw_ostream & OS,const TextEdit & TE)167 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {
168 OS << TE.range << " => \"";
169 llvm::printEscapedString(TE.newText, OS);
170 return OS << '"';
171 }
172
fromJSON(const llvm::json::Value & E,TraceLevel & Out)173 bool fromJSON(const llvm::json::Value &E, TraceLevel &Out) {
174 if (auto S = E.getAsString()) {
175 if (*S == "off") {
176 Out = TraceLevel::Off;
177 return true;
178 } else if (*S == "messages") {
179 Out = TraceLevel::Messages;
180 return true;
181 } else if (*S == "verbose") {
182 Out = TraceLevel::Verbose;
183 return true;
184 }
185 }
186 return false;
187 }
188
fromJSON(const llvm::json::Value & E,SymbolKind & Out)189 bool fromJSON(const llvm::json::Value &E, SymbolKind &Out) {
190 if (auto T = E.getAsInteger()) {
191 if (*T < static_cast<int>(SymbolKind::File) ||
192 *T > static_cast<int>(SymbolKind::TypeParameter))
193 return false;
194 Out = static_cast<SymbolKind>(*T);
195 return true;
196 }
197 return false;
198 }
199
fromJSON(const llvm::json::Value & E,SymbolKindBitset & Out)200 bool fromJSON(const llvm::json::Value &E, SymbolKindBitset &Out) {
201 if (auto *A = E.getAsArray()) {
202 for (size_t I = 0; I < A->size(); ++I) {
203 SymbolKind KindOut;
204 if (fromJSON((*A)[I], KindOut))
205 Out.set(size_t(KindOut));
206 }
207 return true;
208 }
209 return false;
210 }
211
adjustKindToCapability(SymbolKind Kind,SymbolKindBitset & SupportedSymbolKinds)212 SymbolKind adjustKindToCapability(SymbolKind Kind,
213 SymbolKindBitset &SupportedSymbolKinds) {
214 auto KindVal = static_cast<size_t>(Kind);
215 if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() &&
216 SupportedSymbolKinds[KindVal])
217 return Kind;
218
219 switch (Kind) {
220 // Provide some fall backs for common kinds that are close enough.
221 case SymbolKind::Struct:
222 return SymbolKind::Class;
223 case SymbolKind::EnumMember:
224 return SymbolKind::Enum;
225 default:
226 return SymbolKind::String;
227 }
228 }
229
indexSymbolKindToSymbolKind(index::SymbolKind Kind)230 SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind) {
231 switch (Kind) {
232 case index::SymbolKind::Unknown:
233 return SymbolKind::Variable;
234 case index::SymbolKind::Module:
235 return SymbolKind::Module;
236 case index::SymbolKind::Namespace:
237 return SymbolKind::Namespace;
238 case index::SymbolKind::NamespaceAlias:
239 return SymbolKind::Namespace;
240 case index::SymbolKind::Macro:
241 return SymbolKind::String;
242 case index::SymbolKind::Enum:
243 return SymbolKind::Enum;
244 case index::SymbolKind::Struct:
245 return SymbolKind::Struct;
246 case index::SymbolKind::Class:
247 return SymbolKind::Class;
248 case index::SymbolKind::Protocol:
249 return SymbolKind::Interface;
250 case index::SymbolKind::Extension:
251 return SymbolKind::Interface;
252 case index::SymbolKind::Union:
253 return SymbolKind::Class;
254 case index::SymbolKind::TypeAlias:
255 return SymbolKind::Class;
256 case index::SymbolKind::Function:
257 return SymbolKind::Function;
258 case index::SymbolKind::Variable:
259 return SymbolKind::Variable;
260 case index::SymbolKind::Field:
261 return SymbolKind::Field;
262 case index::SymbolKind::EnumConstant:
263 return SymbolKind::EnumMember;
264 case index::SymbolKind::InstanceMethod:
265 case index::SymbolKind::ClassMethod:
266 case index::SymbolKind::StaticMethod:
267 return SymbolKind::Method;
268 case index::SymbolKind::InstanceProperty:
269 case index::SymbolKind::ClassProperty:
270 case index::SymbolKind::StaticProperty:
271 return SymbolKind::Property;
272 case index::SymbolKind::Constructor:
273 case index::SymbolKind::Destructor:
274 return SymbolKind::Constructor;
275 case index::SymbolKind::ConversionFunction:
276 return SymbolKind::Function;
277 case index::SymbolKind::Parameter:
278 case index::SymbolKind::NonTypeTemplateParm:
279 return SymbolKind::Variable;
280 case index::SymbolKind::Using:
281 return SymbolKind::Namespace;
282 case index::SymbolKind::TemplateTemplateParm:
283 case index::SymbolKind::TemplateTypeParm:
284 return SymbolKind::TypeParameter;
285 }
286 llvm_unreachable("invalid symbol kind");
287 }
288
fromJSON(const llvm::json::Value & Params,ClientCapabilities & R)289 bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R) {
290 const llvm::json::Object *O = Params.getAsObject();
291 if (!O)
292 return false;
293 if (auto *TextDocument = O->getObject("textDocument")) {
294 if (auto *SemanticHighlighting =
295 TextDocument->getObject("semanticHighlightingCapabilities")) {
296 if (auto SemanticHighlightingSupport =
297 SemanticHighlighting->getBoolean("semanticHighlighting"))
298 R.TheiaSemanticHighlighting = *SemanticHighlightingSupport;
299 }
300 if (TextDocument->getObject("semanticTokens"))
301 R.SemanticTokens = true;
302 if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {
303 if (auto CategorySupport = Diagnostics->getBoolean("categorySupport"))
304 R.DiagnosticCategory = *CategorySupport;
305 if (auto CodeActions = Diagnostics->getBoolean("codeActionsInline"))
306 R.DiagnosticFixes = *CodeActions;
307 if (auto RelatedInfo = Diagnostics->getBoolean("relatedInformation"))
308 R.DiagnosticRelatedInformation = *RelatedInfo;
309 }
310 if (auto *Completion = TextDocument->getObject("completion")) {
311 if (auto *Item = Completion->getObject("completionItem")) {
312 if (auto SnippetSupport = Item->getBoolean("snippetSupport"))
313 R.CompletionSnippets = *SnippetSupport;
314 if (auto DocumentationFormat = Item->getArray("documentationFormat")) {
315 for (const auto &Format : *DocumentationFormat) {
316 if (fromJSON(Format, R.CompletionDocumentationFormat))
317 break;
318 }
319 }
320 }
321 if (auto *ItemKind = Completion->getObject("completionItemKind")) {
322 if (auto *ValueSet = ItemKind->get("valueSet")) {
323 R.CompletionItemKinds.emplace();
324 if (!fromJSON(*ValueSet, *R.CompletionItemKinds))
325 return false;
326 }
327 }
328 if (auto EditsNearCursor = Completion->getBoolean("editsNearCursor"))
329 R.CompletionFixes = *EditsNearCursor;
330 }
331 if (auto *CodeAction = TextDocument->getObject("codeAction")) {
332 if (CodeAction->getObject("codeActionLiteralSupport"))
333 R.CodeActionStructure = true;
334 }
335 if (auto *DocumentSymbol = TextDocument->getObject("documentSymbol")) {
336 if (auto HierarchicalSupport =
337 DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
338 R.HierarchicalDocumentSymbol = *HierarchicalSupport;
339 }
340 if (auto *Hover = TextDocument->getObject("hover")) {
341 if (auto *ContentFormat = Hover->getArray("contentFormat")) {
342 for (const auto &Format : *ContentFormat) {
343 if (fromJSON(Format, R.HoverContentFormat))
344 break;
345 }
346 }
347 }
348 if (auto *Help = TextDocument->getObject("signatureHelp")) {
349 R.HasSignatureHelp = true;
350 if (auto *Info = Help->getObject("signatureInformation")) {
351 if (auto *Parameter = Info->getObject("parameterInformation")) {
352 if (auto OffsetSupport = Parameter->getBoolean("labelOffsetSupport"))
353 R.OffsetsInSignatureHelp = *OffsetSupport;
354 }
355 }
356 }
357 if (auto *Rename = TextDocument->getObject("rename")) {
358 if (auto RenameSupport = Rename->getBoolean("prepareSupport"))
359 R.RenamePrepareSupport = *RenameSupport;
360 }
361 }
362 if (auto *Workspace = O->getObject("workspace")) {
363 if (auto *Symbol = Workspace->getObject("symbol")) {
364 if (auto *SymbolKind = Symbol->getObject("symbolKind")) {
365 if (auto *ValueSet = SymbolKind->get("valueSet")) {
366 R.WorkspaceSymbolKinds.emplace();
367 if (!fromJSON(*ValueSet, *R.WorkspaceSymbolKinds))
368 return false;
369 }
370 }
371 }
372 }
373 if (auto *Window = O->getObject("window")) {
374 if (auto WorkDoneProgress = Window->getBoolean("workDoneProgress"))
375 R.WorkDoneProgress = *WorkDoneProgress;
376 if (auto Implicit = Window->getBoolean("implicitWorkDoneProgressCreate"))
377 R.ImplicitProgressCreation = *Implicit;
378 }
379 if (auto *OffsetEncoding = O->get("offsetEncoding")) {
380 R.offsetEncoding.emplace();
381 if (!fromJSON(*OffsetEncoding, *R.offsetEncoding))
382 return false;
383 }
384 return true;
385 }
386
fromJSON(const llvm::json::Value & Params,InitializeParams & R)387 bool fromJSON(const llvm::json::Value &Params, InitializeParams &R) {
388 llvm::json::ObjectMapper O(Params);
389 if (!O)
390 return false;
391 // We deliberately don't fail if we can't parse individual fields.
392 // Failing to handle a slightly malformed initialize would be a disaster.
393 O.map("processId", R.processId);
394 O.map("rootUri", R.rootUri);
395 O.map("rootPath", R.rootPath);
396 O.map("capabilities", R.capabilities);
397 O.map("trace", R.trace);
398 O.map("initializationOptions", R.initializationOptions);
399 return true;
400 }
401
toJSON(const WorkDoneProgressCreateParams & P)402 llvm::json::Value toJSON(const WorkDoneProgressCreateParams &P) {
403 return llvm::json::Object{{"token", P.token}};
404 }
405
toJSON(const WorkDoneProgressBegin & P)406 llvm::json::Value toJSON(const WorkDoneProgressBegin &P) {
407 llvm::json::Object Result{
408 {"kind", "begin"},
409 {"title", P.title},
410 };
411 if (P.cancellable)
412 Result["cancellable"] = true;
413 if (P.percentage)
414 Result["percentage"] = 0;
415
416 // FIXME: workaround for older gcc/clang
417 return std::move(Result);
418 }
419
toJSON(const WorkDoneProgressReport & P)420 llvm::json::Value toJSON(const WorkDoneProgressReport &P) {
421 llvm::json::Object Result{{"kind", "report"}};
422 if (P.cancellable)
423 Result["cancellable"] = *P.cancellable;
424 if (P.message)
425 Result["message"] = *P.message;
426 if (P.percentage)
427 Result["percentage"] = *P.percentage;
428 // FIXME: workaround for older gcc/clang
429 return std::move(Result);
430 }
431
toJSON(const WorkDoneProgressEnd & P)432 llvm::json::Value toJSON(const WorkDoneProgressEnd &P) {
433 llvm::json::Object Result{{"kind", "end"}};
434 if (P.message)
435 Result["message"] = *P.message;
436 // FIXME: workaround for older gcc/clang
437 return std::move(Result);
438 }
439
toJSON(const MessageType & R)440 llvm::json::Value toJSON(const MessageType &R) {
441 return static_cast<int64_t>(R);
442 }
443
toJSON(const ShowMessageParams & R)444 llvm::json::Value toJSON(const ShowMessageParams &R) {
445 return llvm::json::Object{{"type", R.type}, {"message", R.message}};
446 }
447
fromJSON(const llvm::json::Value & Params,DidOpenTextDocumentParams & R)448 bool fromJSON(const llvm::json::Value &Params, DidOpenTextDocumentParams &R) {
449 llvm::json::ObjectMapper O(Params);
450 return O && O.map("textDocument", R.textDocument);
451 }
452
fromJSON(const llvm::json::Value & Params,DidCloseTextDocumentParams & R)453 bool fromJSON(const llvm::json::Value &Params, DidCloseTextDocumentParams &R) {
454 llvm::json::ObjectMapper O(Params);
455 return O && O.map("textDocument", R.textDocument);
456 }
457
fromJSON(const llvm::json::Value & Params,DidSaveTextDocumentParams & R)458 bool fromJSON(const llvm::json::Value &Params, DidSaveTextDocumentParams &R) {
459 llvm::json::ObjectMapper O(Params);
460 return O && O.map("textDocument", R.textDocument);
461 }
462
fromJSON(const llvm::json::Value & Params,DidChangeTextDocumentParams & R)463 bool fromJSON(const llvm::json::Value &Params, DidChangeTextDocumentParams &R) {
464 llvm::json::ObjectMapper O(Params);
465 if (!O)
466 return false;
467 O.map("forceRebuild", R.forceRebuild); // Optional clangd extension.
468 return O.map("textDocument", R.textDocument) &&
469 O.map("contentChanges", R.contentChanges) &&
470 O.map("wantDiagnostics", R.wantDiagnostics);
471 }
472
fromJSON(const llvm::json::Value & E,FileChangeType & Out)473 bool fromJSON(const llvm::json::Value &E, FileChangeType &Out) {
474 if (auto T = E.getAsInteger()) {
475 if (*T < static_cast<int>(FileChangeType::Created) ||
476 *T > static_cast<int>(FileChangeType::Deleted))
477 return false;
478 Out = static_cast<FileChangeType>(*T);
479 return true;
480 }
481 return false;
482 }
483
fromJSON(const llvm::json::Value & Params,FileEvent & R)484 bool fromJSON(const llvm::json::Value &Params, FileEvent &R) {
485 llvm::json::ObjectMapper O(Params);
486 return O && O.map("uri", R.uri) && O.map("type", R.type);
487 }
488
fromJSON(const llvm::json::Value & Params,DidChangeWatchedFilesParams & R)489 bool fromJSON(const llvm::json::Value &Params, DidChangeWatchedFilesParams &R) {
490 llvm::json::ObjectMapper O(Params);
491 return O && O.map("changes", R.changes);
492 }
493
fromJSON(const llvm::json::Value & Params,TextDocumentContentChangeEvent & R)494 bool fromJSON(const llvm::json::Value &Params,
495 TextDocumentContentChangeEvent &R) {
496 llvm::json::ObjectMapper O(Params);
497 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
498 O.map("text", R.text);
499 }
500
fromJSON(const llvm::json::Value & Params,DocumentRangeFormattingParams & R)501 bool fromJSON(const llvm::json::Value &Params,
502 DocumentRangeFormattingParams &R) {
503 llvm::json::ObjectMapper O(Params);
504 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
505 }
506
fromJSON(const llvm::json::Value & Params,DocumentOnTypeFormattingParams & R)507 bool fromJSON(const llvm::json::Value &Params,
508 DocumentOnTypeFormattingParams &R) {
509 llvm::json::ObjectMapper O(Params);
510 return O && O.map("textDocument", R.textDocument) &&
511 O.map("position", R.position) && O.map("ch", R.ch);
512 }
513
fromJSON(const llvm::json::Value & Params,DocumentFormattingParams & R)514 bool fromJSON(const llvm::json::Value &Params, DocumentFormattingParams &R) {
515 llvm::json::ObjectMapper O(Params);
516 return O && O.map("textDocument", R.textDocument);
517 }
518
fromJSON(const llvm::json::Value & Params,DocumentSymbolParams & R)519 bool fromJSON(const llvm::json::Value &Params, DocumentSymbolParams &R) {
520 llvm::json::ObjectMapper O(Params);
521 return O && O.map("textDocument", R.textDocument);
522 }
523
toJSON(const DiagnosticRelatedInformation & DRI)524 llvm::json::Value toJSON(const DiagnosticRelatedInformation &DRI) {
525 return llvm::json::Object{
526 {"location", DRI.location},
527 {"message", DRI.message},
528 };
529 }
530
toJSON(const Diagnostic & D)531 llvm::json::Value toJSON(const Diagnostic &D) {
532 llvm::json::Object Diag{
533 {"range", D.range},
534 {"severity", D.severity},
535 {"message", D.message},
536 };
537 if (D.category)
538 Diag["category"] = *D.category;
539 if (D.codeActions)
540 Diag["codeActions"] = D.codeActions;
541 if (!D.code.empty())
542 Diag["code"] = D.code;
543 if (!D.source.empty())
544 Diag["source"] = D.source;
545 if (D.relatedInformation)
546 Diag["relatedInformation"] = *D.relatedInformation;
547 // FIXME: workaround for older gcc/clang
548 return std::move(Diag);
549 }
550
fromJSON(const llvm::json::Value & Params,Diagnostic & R)551 bool fromJSON(const llvm::json::Value &Params, Diagnostic &R) {
552 llvm::json::ObjectMapper O(Params);
553 if (!O || !O.map("range", R.range) || !O.map("message", R.message))
554 return false;
555 O.map("severity", R.severity);
556 O.map("category", R.category);
557 O.map("code", R.code);
558 O.map("source", R.source);
559 return true;
560 }
561
toJSON(const PublishDiagnosticsParams & PDP)562 llvm::json::Value toJSON(const PublishDiagnosticsParams &PDP) {
563 llvm::json::Object Result{
564 {"uri", PDP.uri},
565 {"diagnostics", PDP.diagnostics},
566 };
567 if (PDP.version)
568 Result["version"] = PDP.version;
569 return std::move(Result);
570 }
571
fromJSON(const llvm::json::Value & Params,CodeActionContext & R)572 bool fromJSON(const llvm::json::Value &Params, CodeActionContext &R) {
573 llvm::json::ObjectMapper O(Params);
574 return O && O.map("diagnostics", R.diagnostics);
575 }
576
operator <<(llvm::raw_ostream & OS,const Diagnostic & D)577 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
578 OS << D.range << " [";
579 switch (D.severity) {
580 case 1:
581 OS << "error";
582 break;
583 case 2:
584 OS << "warning";
585 break;
586 case 3:
587 OS << "note";
588 break;
589 case 4:
590 OS << "remark";
591 break;
592 default:
593 OS << "diagnostic";
594 break;
595 }
596 return OS << '(' << D.severity << "): " << D.message << "]";
597 }
598
fromJSON(const llvm::json::Value & Params,CodeActionParams & R)599 bool fromJSON(const llvm::json::Value &Params, CodeActionParams &R) {
600 llvm::json::ObjectMapper O(Params);
601 return O && O.map("textDocument", R.textDocument) &&
602 O.map("range", R.range) && O.map("context", R.context);
603 }
604
fromJSON(const llvm::json::Value & Params,WorkspaceEdit & R)605 bool fromJSON(const llvm::json::Value &Params, WorkspaceEdit &R) {
606 llvm::json::ObjectMapper O(Params);
607 return O && O.map("changes", R.changes);
608 }
609
610 const llvm::StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
611 "clangd.applyFix";
612 const llvm::StringLiteral ExecuteCommandParams::CLANGD_APPLY_TWEAK =
613 "clangd.applyTweak";
614
fromJSON(const llvm::json::Value & Params,ExecuteCommandParams & R)615 bool fromJSON(const llvm::json::Value &Params, ExecuteCommandParams &R) {
616 llvm::json::ObjectMapper O(Params);
617 if (!O || !O.map("command", R.command))
618 return false;
619
620 auto Args = Params.getAsObject()->getArray("arguments");
621 if (R.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
622 return Args && Args->size() == 1 &&
623 fromJSON(Args->front(), R.workspaceEdit);
624 }
625 if (R.command == ExecuteCommandParams::CLANGD_APPLY_TWEAK)
626 return Args && Args->size() == 1 && fromJSON(Args->front(), R.tweakArgs);
627 return false; // Unrecognized command.
628 }
629
toJSON(const SymbolInformation & P)630 llvm::json::Value toJSON(const SymbolInformation &P) {
631 return llvm::json::Object{
632 {"name", P.name},
633 {"kind", static_cast<int>(P.kind)},
634 {"location", P.location},
635 {"containerName", P.containerName},
636 };
637 }
638
operator <<(llvm::raw_ostream & O,const SymbolInformation & SI)639 llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
640 const SymbolInformation &SI) {
641 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
642 return O;
643 }
644
operator ==(const SymbolDetails & LHS,const SymbolDetails & RHS)645 bool operator==(const SymbolDetails &LHS, const SymbolDetails &RHS) {
646 return LHS.name == RHS.name && LHS.containerName == RHS.containerName &&
647 LHS.USR == RHS.USR && LHS.ID == RHS.ID;
648 }
649
toJSON(const SymbolDetails & P)650 llvm::json::Value toJSON(const SymbolDetails &P) {
651 llvm::json::Object Result{{"name", llvm::json::Value(nullptr)},
652 {"containerName", llvm::json::Value(nullptr)},
653 {"usr", llvm::json::Value(nullptr)},
654 {"id", llvm::json::Value(nullptr)}};
655
656 if (!P.name.empty())
657 Result["name"] = P.name;
658
659 if (!P.containerName.empty())
660 Result["containerName"] = P.containerName;
661
662 if (!P.USR.empty())
663 Result["usr"] = P.USR;
664
665 if (P.ID.hasValue())
666 Result["id"] = P.ID.getValue().str();
667
668 // FIXME: workaround for older gcc/clang
669 return std::move(Result);
670 }
671
operator <<(llvm::raw_ostream & O,const SymbolDetails & S)672 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) {
673 if (!S.containerName.empty()) {
674 O << S.containerName;
675 llvm::StringRef ContNameRef;
676 if (!ContNameRef.endswith("::")) {
677 O << " ";
678 }
679 }
680 O << S.name << " - " << toJSON(S);
681 return O;
682 }
683
fromJSON(const llvm::json::Value & Params,WorkspaceSymbolParams & R)684 bool fromJSON(const llvm::json::Value &Params, WorkspaceSymbolParams &R) {
685 llvm::json::ObjectMapper O(Params);
686 return O && O.map("query", R.query);
687 }
688
toJSON(const Command & C)689 llvm::json::Value toJSON(const Command &C) {
690 auto Cmd = llvm::json::Object{{"title", C.title}, {"command", C.command}};
691 if (C.workspaceEdit)
692 Cmd["arguments"] = {*C.workspaceEdit};
693 if (C.tweakArgs)
694 Cmd["arguments"] = {*C.tweakArgs};
695 return std::move(Cmd);
696 }
697
698 const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";
699 const llvm::StringLiteral CodeAction::REFACTOR_KIND = "refactor";
700 const llvm::StringLiteral CodeAction::INFO_KIND = "info";
701
toJSON(const CodeAction & CA)702 llvm::json::Value toJSON(const CodeAction &CA) {
703 auto CodeAction = llvm::json::Object{{"title", CA.title}};
704 if (CA.kind)
705 CodeAction["kind"] = *CA.kind;
706 if (CA.diagnostics)
707 CodeAction["diagnostics"] = llvm::json::Array(*CA.diagnostics);
708 if (CA.edit)
709 CodeAction["edit"] = *CA.edit;
710 if (CA.command)
711 CodeAction["command"] = *CA.command;
712 return std::move(CodeAction);
713 }
714
operator <<(llvm::raw_ostream & O,const DocumentSymbol & S)715 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S) {
716 return O << S.name << " - " << toJSON(S);
717 }
718
toJSON(const DocumentSymbol & S)719 llvm::json::Value toJSON(const DocumentSymbol &S) {
720 llvm::json::Object Result{{"name", S.name},
721 {"kind", static_cast<int>(S.kind)},
722 {"range", S.range},
723 {"selectionRange", S.selectionRange}};
724
725 if (!S.detail.empty())
726 Result["detail"] = S.detail;
727 if (!S.children.empty())
728 Result["children"] = S.children;
729 if (S.deprecated)
730 Result["deprecated"] = true;
731 // FIXME: workaround for older gcc/clang
732 return std::move(Result);
733 }
734
toJSON(const WorkspaceEdit & WE)735 llvm::json::Value toJSON(const WorkspaceEdit &WE) {
736 if (!WE.changes)
737 return llvm::json::Object{};
738 llvm::json::Object FileChanges;
739 for (auto &Change : *WE.changes)
740 FileChanges[Change.first] = llvm::json::Array(Change.second);
741 return llvm::json::Object{{"changes", std::move(FileChanges)}};
742 }
743
fromJSON(const llvm::json::Value & Params,TweakArgs & A)744 bool fromJSON(const llvm::json::Value &Params, TweakArgs &A) {
745 llvm::json::ObjectMapper O(Params);
746 return O && O.map("file", A.file) && O.map("selection", A.selection) &&
747 O.map("tweakID", A.tweakID);
748 }
749
toJSON(const TweakArgs & A)750 llvm::json::Value toJSON(const TweakArgs &A) {
751 return llvm::json::Object{
752 {"tweakID", A.tweakID}, {"selection", A.selection}, {"file", A.file}};
753 }
754
toJSON(const ApplyWorkspaceEditParams & Params)755 llvm::json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
756 return llvm::json::Object{{"edit", Params.edit}};
757 }
758
fromJSON(const llvm::json::Value & Response,ApplyWorkspaceEditResponse & R)759 bool fromJSON(const llvm::json::Value &Response,
760 ApplyWorkspaceEditResponse &R) {
761 llvm::json::ObjectMapper O(Response);
762 if (!O || !O.map("applied", R.applied))
763 return false;
764 O.map("failureReason", R.failureReason);
765 return true;
766 }
767
fromJSON(const llvm::json::Value & Params,TextDocumentPositionParams & R)768 bool fromJSON(const llvm::json::Value &Params, TextDocumentPositionParams &R) {
769 llvm::json::ObjectMapper O(Params);
770 return O && O.map("textDocument", R.textDocument) &&
771 O.map("position", R.position);
772 }
773
fromJSON(const llvm::json::Value & Params,CompletionContext & R)774 bool fromJSON(const llvm::json::Value &Params, CompletionContext &R) {
775 llvm::json::ObjectMapper O(Params);
776 if (!O)
777 return false;
778
779 int TriggerKind;
780 if (!O.map("triggerKind", TriggerKind))
781 return false;
782 R.triggerKind = static_cast<CompletionTriggerKind>(TriggerKind);
783
784 if (auto *TC = Params.getAsObject()->get("triggerCharacter"))
785 return fromJSON(*TC, R.triggerCharacter);
786 return true;
787 }
788
fromJSON(const llvm::json::Value & Params,CompletionParams & R)789 bool fromJSON(const llvm::json::Value &Params, CompletionParams &R) {
790 if (!fromJSON(Params, static_cast<TextDocumentPositionParams &>(R)))
791 return false;
792 if (auto *Context = Params.getAsObject()->get("context"))
793 return fromJSON(*Context, R.context);
794 return true;
795 }
796
toTextKind(MarkupKind Kind)797 static llvm::StringRef toTextKind(MarkupKind Kind) {
798 switch (Kind) {
799 case MarkupKind::PlainText:
800 return "plaintext";
801 case MarkupKind::Markdown:
802 return "markdown";
803 }
804 llvm_unreachable("Invalid MarkupKind");
805 }
806
fromJSON(const llvm::json::Value & V,MarkupKind & K)807 bool fromJSON(const llvm::json::Value &V, MarkupKind &K) {
808 auto Str = V.getAsString();
809 if (!Str) {
810 elog("Failed to parse markup kind: expected a string");
811 return false;
812 }
813 if (*Str == "plaintext")
814 K = MarkupKind::PlainText;
815 else if (*Str == "markdown")
816 K = MarkupKind::Markdown;
817 else {
818 elog("Unknown markup kind: {0}", *Str);
819 return false;
820 }
821 return true;
822 }
823
operator <<(llvm::raw_ostream & OS,MarkupKind K)824 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) {
825 return OS << toTextKind(K);
826 }
827
toJSON(const MarkupContent & MC)828 llvm::json::Value toJSON(const MarkupContent &MC) {
829 if (MC.value.empty())
830 return nullptr;
831
832 return llvm::json::Object{
833 {"kind", toTextKind(MC.kind)},
834 {"value", MC.value},
835 };
836 }
837
toJSON(const Hover & H)838 llvm::json::Value toJSON(const Hover &H) {
839 llvm::json::Object Result{{"contents", toJSON(H.contents)}};
840
841 if (H.range.hasValue())
842 Result["range"] = toJSON(*H.range);
843
844 return std::move(Result);
845 }
846
fromJSON(const llvm::json::Value & E,CompletionItemKind & Out)847 bool fromJSON(const llvm::json::Value &E, CompletionItemKind &Out) {
848 if (auto T = E.getAsInteger()) {
849 if (*T < static_cast<int>(CompletionItemKind::Text) ||
850 *T > static_cast<int>(CompletionItemKind::TypeParameter))
851 return false;
852 Out = static_cast<CompletionItemKind>(*T);
853 return true;
854 }
855 return false;
856 }
857
858 CompletionItemKind
adjustKindToCapability(CompletionItemKind Kind,CompletionItemKindBitset & SupportedCompletionItemKinds)859 adjustKindToCapability(CompletionItemKind Kind,
860 CompletionItemKindBitset &SupportedCompletionItemKinds) {
861 auto KindVal = static_cast<size_t>(Kind);
862 if (KindVal >= CompletionItemKindMin &&
863 KindVal <= SupportedCompletionItemKinds.size() &&
864 SupportedCompletionItemKinds[KindVal])
865 return Kind;
866
867 switch (Kind) {
868 // Provide some fall backs for common kinds that are close enough.
869 case CompletionItemKind::Folder:
870 return CompletionItemKind::File;
871 case CompletionItemKind::EnumMember:
872 return CompletionItemKind::Enum;
873 case CompletionItemKind::Struct:
874 return CompletionItemKind::Class;
875 default:
876 return CompletionItemKind::Text;
877 }
878 }
879
fromJSON(const llvm::json::Value & E,CompletionItemKindBitset & Out)880 bool fromJSON(const llvm::json::Value &E, CompletionItemKindBitset &Out) {
881 if (auto *A = E.getAsArray()) {
882 for (size_t I = 0; I < A->size(); ++I) {
883 CompletionItemKind KindOut;
884 if (fromJSON((*A)[I], KindOut))
885 Out.set(size_t(KindOut));
886 }
887 return true;
888 }
889 return false;
890 }
891
toJSON(const CompletionItem & CI)892 llvm::json::Value toJSON(const CompletionItem &CI) {
893 assert(!CI.label.empty() && "completion item label is required");
894 llvm::json::Object Result{{"label", CI.label}};
895 if (CI.kind != CompletionItemKind::Missing)
896 Result["kind"] = static_cast<int>(CI.kind);
897 if (!CI.detail.empty())
898 Result["detail"] = CI.detail;
899 if (CI.documentation)
900 Result["documentation"] = CI.documentation;
901 if (!CI.sortText.empty())
902 Result["sortText"] = CI.sortText;
903 if (!CI.filterText.empty())
904 Result["filterText"] = CI.filterText;
905 if (!CI.insertText.empty())
906 Result["insertText"] = CI.insertText;
907 if (CI.insertTextFormat != InsertTextFormat::Missing)
908 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
909 if (CI.textEdit)
910 Result["textEdit"] = *CI.textEdit;
911 if (!CI.additionalTextEdits.empty())
912 Result["additionalTextEdits"] = llvm::json::Array(CI.additionalTextEdits);
913 if (CI.deprecated)
914 Result["deprecated"] = CI.deprecated;
915 Result["score"] = CI.score;
916 return std::move(Result);
917 }
918
operator <<(llvm::raw_ostream & O,const CompletionItem & I)919 llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) {
920 O << I.label << " - " << toJSON(I);
921 return O;
922 }
923
operator <(const CompletionItem & L,const CompletionItem & R)924 bool operator<(const CompletionItem &L, const CompletionItem &R) {
925 return (L.sortText.empty() ? L.label : L.sortText) <
926 (R.sortText.empty() ? R.label : R.sortText);
927 }
928
toJSON(const CompletionList & L)929 llvm::json::Value toJSON(const CompletionList &L) {
930 return llvm::json::Object{
931 {"isIncomplete", L.isIncomplete},
932 {"items", llvm::json::Array(L.items)},
933 };
934 }
935
toJSON(const ParameterInformation & PI)936 llvm::json::Value toJSON(const ParameterInformation &PI) {
937 assert((PI.labelOffsets.hasValue() || !PI.labelString.empty()) &&
938 "parameter information label is required");
939 llvm::json::Object Result;
940 if (PI.labelOffsets)
941 Result["label"] =
942 llvm::json::Array({PI.labelOffsets->first, PI.labelOffsets->second});
943 else
944 Result["label"] = PI.labelString;
945 if (!PI.documentation.empty())
946 Result["documentation"] = PI.documentation;
947 return std::move(Result);
948 }
949
toJSON(const SignatureInformation & SI)950 llvm::json::Value toJSON(const SignatureInformation &SI) {
951 assert(!SI.label.empty() && "signature information label is required");
952 llvm::json::Object Result{
953 {"label", SI.label},
954 {"parameters", llvm::json::Array(SI.parameters)},
955 };
956 if (!SI.documentation.empty())
957 Result["documentation"] = SI.documentation;
958 return std::move(Result);
959 }
960
operator <<(llvm::raw_ostream & O,const SignatureInformation & I)961 llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
962 const SignatureInformation &I) {
963 O << I.label << " - " << toJSON(I);
964 return O;
965 }
966
toJSON(const SignatureHelp & SH)967 llvm::json::Value toJSON(const SignatureHelp &SH) {
968 assert(SH.activeSignature >= 0 &&
969 "Unexpected negative value for number of active signatures.");
970 assert(SH.activeParameter >= 0 &&
971 "Unexpected negative value for active parameter index");
972 return llvm::json::Object{
973 {"activeSignature", SH.activeSignature},
974 {"activeParameter", SH.activeParameter},
975 {"signatures", llvm::json::Array(SH.signatures)},
976 };
977 }
978
fromJSON(const llvm::json::Value & Params,RenameParams & R)979 bool fromJSON(const llvm::json::Value &Params, RenameParams &R) {
980 llvm::json::ObjectMapper O(Params);
981 return O && O.map("textDocument", R.textDocument) &&
982 O.map("position", R.position) && O.map("newName", R.newName);
983 }
984
toJSON(const DocumentHighlight & DH)985 llvm::json::Value toJSON(const DocumentHighlight &DH) {
986 return llvm::json::Object{
987 {"range", toJSON(DH.range)},
988 {"kind", static_cast<int>(DH.kind)},
989 };
990 }
991
toJSON(const FileStatus & FStatus)992 llvm::json::Value toJSON(const FileStatus &FStatus) {
993 return llvm::json::Object{
994 {"uri", FStatus.uri},
995 {"state", FStatus.state},
996 };
997 }
998
999 constexpr unsigned SemanticTokenEncodingSize = 5;
encodeTokens(llvm::ArrayRef<SemanticToken> Toks)1000 static llvm::json::Value encodeTokens(llvm::ArrayRef<SemanticToken> Toks) {
1001 llvm::json::Array Result;
1002 for (const auto &Tok : Toks) {
1003 Result.push_back(Tok.deltaLine);
1004 Result.push_back(Tok.deltaStart);
1005 Result.push_back(Tok.length);
1006 Result.push_back(Tok.tokenType);
1007 Result.push_back(Tok.tokenModifiers);
1008 }
1009 assert(Result.size() == SemanticTokenEncodingSize * Toks.size());
1010 return std::move(Result);
1011 }
1012
operator ==(const SemanticToken & L,const SemanticToken & R)1013 bool operator==(const SemanticToken &L, const SemanticToken &R) {
1014 return std::tie(L.deltaLine, L.deltaStart, L.length, L.tokenType,
1015 L.tokenModifiers) == std::tie(R.deltaLine, R.deltaStart,
1016 R.length, R.tokenType,
1017 R.tokenModifiers);
1018 }
1019
toJSON(const SemanticTokens & Tokens)1020 llvm::json::Value toJSON(const SemanticTokens &Tokens) {
1021 return llvm::json::Object{{"resultId", Tokens.resultId},
1022 {"data", encodeTokens(Tokens.tokens)}};
1023 }
1024
toJSON(const SemanticTokensEdit & Edit)1025 llvm::json::Value toJSON(const SemanticTokensEdit &Edit) {
1026 return llvm::json::Object{
1027 {"start", SemanticTokenEncodingSize * Edit.startToken},
1028 {"deleteCount", SemanticTokenEncodingSize * Edit.deleteTokens},
1029 {"data", encodeTokens(Edit.tokens)}};
1030 }
1031
toJSON(const SemanticTokensOrDelta & TE)1032 llvm::json::Value toJSON(const SemanticTokensOrDelta &TE) {
1033 llvm::json::Object Result{{"resultId", TE.resultId}};
1034 if (TE.edits)
1035 Result["edits"] = *TE.edits;
1036 if (TE.tokens)
1037 Result["data"] = encodeTokens(*TE.tokens);
1038 return std::move(Result);
1039 }
1040
fromJSON(const llvm::json::Value & Params,SemanticTokensParams & R)1041 bool fromJSON(const llvm::json::Value &Params, SemanticTokensParams &R) {
1042 llvm::json::ObjectMapper O(Params);
1043 return O && O.map("textDocument", R.textDocument);
1044 }
1045
fromJSON(const llvm::json::Value & Params,SemanticTokensDeltaParams & R)1046 bool fromJSON(const llvm::json::Value &Params, SemanticTokensDeltaParams &R) {
1047 llvm::json::ObjectMapper O(Params);
1048 return O && O.map("textDocument", R.textDocument) &&
1049 O.map("previousResultId", R.previousResultId);
1050 }
1051
operator <<(llvm::raw_ostream & O,const DocumentHighlight & V)1052 llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1053 const DocumentHighlight &V) {
1054 O << V.range;
1055 if (V.kind == DocumentHighlightKind::Read)
1056 O << "(r)";
1057 if (V.kind == DocumentHighlightKind::Write)
1058 O << "(w)";
1059 return O;
1060 }
1061
fromJSON(const llvm::json::Value & Params,DidChangeConfigurationParams & CCP)1062 bool fromJSON(const llvm::json::Value &Params,
1063 DidChangeConfigurationParams &CCP) {
1064 llvm::json::ObjectMapper O(Params);
1065 return O && O.map("settings", CCP.settings);
1066 }
1067
fromJSON(const llvm::json::Value & Params,ClangdCompileCommand & CDbUpdate)1068 bool fromJSON(const llvm::json::Value &Params,
1069 ClangdCompileCommand &CDbUpdate) {
1070 llvm::json::ObjectMapper O(Params);
1071 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&
1072 O.map("compilationCommand", CDbUpdate.compilationCommand);
1073 }
1074
fromJSON(const llvm::json::Value & Params,ConfigurationSettings & S)1075 bool fromJSON(const llvm::json::Value &Params, ConfigurationSettings &S) {
1076 llvm::json::ObjectMapper O(Params);
1077 if (!O)
1078 return true; // 'any' type in LSP.
1079 O.map("compilationDatabaseChanges", S.compilationDatabaseChanges);
1080 return true;
1081 }
1082
fromJSON(const llvm::json::Value & Params,InitializationOptions & Opts)1083 bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts) {
1084 llvm::json::ObjectMapper O(Params);
1085 if (!O)
1086 return true; // 'any' type in LSP.
1087
1088 fromJSON(Params, Opts.ConfigSettings);
1089 O.map("compilationDatabasePath", Opts.compilationDatabasePath);
1090 O.map("fallbackFlags", Opts.fallbackFlags);
1091 O.map("clangdFileStatus", Opts.FileStatus);
1092 return true;
1093 }
1094
fromJSON(const llvm::json::Value & E,TypeHierarchyDirection & Out)1095 bool fromJSON(const llvm::json::Value &E, TypeHierarchyDirection &Out) {
1096 auto T = E.getAsInteger();
1097 if (!T)
1098 return false;
1099 if (*T < static_cast<int>(TypeHierarchyDirection::Children) ||
1100 *T > static_cast<int>(TypeHierarchyDirection::Both))
1101 return false;
1102 Out = static_cast<TypeHierarchyDirection>(*T);
1103 return true;
1104 }
1105
fromJSON(const llvm::json::Value & Params,TypeHierarchyParams & R)1106 bool fromJSON(const llvm::json::Value &Params, TypeHierarchyParams &R) {
1107 llvm::json::ObjectMapper O(Params);
1108 return O && O.map("textDocument", R.textDocument) &&
1109 O.map("position", R.position) && O.map("resolve", R.resolve) &&
1110 O.map("direction", R.direction);
1111 }
1112
operator <<(llvm::raw_ostream & O,const TypeHierarchyItem & I)1113 llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1114 const TypeHierarchyItem &I) {
1115 return O << I.name << " - " << toJSON(I);
1116 }
1117
toJSON(const TypeHierarchyItem & I)1118 llvm::json::Value toJSON(const TypeHierarchyItem &I) {
1119 llvm::json::Object Result{{"name", I.name},
1120 {"kind", static_cast<int>(I.kind)},
1121 {"range", I.range},
1122 {"selectionRange", I.selectionRange},
1123 {"uri", I.uri}};
1124
1125 if (I.detail)
1126 Result["detail"] = I.detail;
1127 if (I.deprecated)
1128 Result["deprecated"] = I.deprecated;
1129 if (I.parents)
1130 Result["parents"] = I.parents;
1131 if (I.children)
1132 Result["children"] = I.children;
1133 if (I.data)
1134 Result["data"] = I.data;
1135 return std::move(Result);
1136 }
1137
fromJSON(const llvm::json::Value & Params,TypeHierarchyItem & I)1138 bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I) {
1139 llvm::json::ObjectMapper O(Params);
1140
1141 // Required fields.
1142 if (!(O && O.map("name", I.name) && O.map("kind", I.kind) &&
1143 O.map("uri", I.uri) && O.map("range", I.range) &&
1144 O.map("selectionRange", I.selectionRange))) {
1145 return false;
1146 }
1147
1148 // Optional fields.
1149 O.map("detail", I.detail);
1150 O.map("deprecated", I.deprecated);
1151 O.map("parents", I.parents);
1152 O.map("children", I.children);
1153 O.map("data", I.data);
1154
1155 return true;
1156 }
1157
fromJSON(const llvm::json::Value & Params,ResolveTypeHierarchyItemParams & P)1158 bool fromJSON(const llvm::json::Value &Params,
1159 ResolveTypeHierarchyItemParams &P) {
1160 llvm::json::ObjectMapper O(Params);
1161 return O && O.map("item", P.item) && O.map("resolve", P.resolve) &&
1162 O.map("direction", P.direction);
1163 }
1164
fromJSON(const llvm::json::Value & Params,ReferenceParams & R)1165 bool fromJSON(const llvm::json::Value &Params, ReferenceParams &R) {
1166 TextDocumentPositionParams &Base = R;
1167 return fromJSON(Params, Base);
1168 }
1169
toString(OffsetEncoding OE)1170 static const char *toString(OffsetEncoding OE) {
1171 switch (OE) {
1172 case OffsetEncoding::UTF8:
1173 return "utf-8";
1174 case OffsetEncoding::UTF16:
1175 return "utf-16";
1176 case OffsetEncoding::UTF32:
1177 return "utf-32";
1178 case OffsetEncoding::UnsupportedEncoding:
1179 return "unknown";
1180 }
1181 llvm_unreachable("Unknown clang.clangd.OffsetEncoding");
1182 }
toJSON(const OffsetEncoding & OE)1183 llvm::json::Value toJSON(const OffsetEncoding &OE) { return toString(OE); }
fromJSON(const llvm::json::Value & V,OffsetEncoding & OE)1184 bool fromJSON(const llvm::json::Value &V, OffsetEncoding &OE) {
1185 auto Str = V.getAsString();
1186 if (!Str)
1187 return false;
1188 OE = llvm::StringSwitch<OffsetEncoding>(*Str)
1189 .Case("utf-8", OffsetEncoding::UTF8)
1190 .Case("utf-16", OffsetEncoding::UTF16)
1191 .Case("utf-32", OffsetEncoding::UTF32)
1192 .Default(OffsetEncoding::UnsupportedEncoding);
1193 return true;
1194 }
operator <<(llvm::raw_ostream & OS,OffsetEncoding Enc)1195 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OffsetEncoding Enc) {
1196 return OS << toString(Enc);
1197 }
1198
operator ==(const TheiaSemanticHighlightingInformation & Lhs,const TheiaSemanticHighlightingInformation & Rhs)1199 bool operator==(const TheiaSemanticHighlightingInformation &Lhs,
1200 const TheiaSemanticHighlightingInformation &Rhs) {
1201 return Lhs.Line == Rhs.Line && Lhs.Tokens == Rhs.Tokens;
1202 }
1203
1204 llvm::json::Value
toJSON(const TheiaSemanticHighlightingInformation & Highlighting)1205 toJSON(const TheiaSemanticHighlightingInformation &Highlighting) {
1206 return llvm::json::Object{{"line", Highlighting.Line},
1207 {"tokens", Highlighting.Tokens},
1208 {"isInactive", Highlighting.IsInactive}};
1209 }
1210
toJSON(const TheiaSemanticHighlightingParams & Highlighting)1211 llvm::json::Value toJSON(const TheiaSemanticHighlightingParams &Highlighting) {
1212 return llvm::json::Object{
1213 {"textDocument", Highlighting.TextDocument},
1214 {"lines", std::move(Highlighting.Lines)},
1215 };
1216 }
1217
fromJSON(const llvm::json::Value & Params,SelectionRangeParams & P)1218 bool fromJSON(const llvm::json::Value &Params, SelectionRangeParams &P) {
1219 llvm::json::ObjectMapper O(Params);
1220 return O && O.map("textDocument", P.textDocument) &&
1221 O.map("positions", P.positions);
1222 }
1223
toJSON(const SelectionRange & Out)1224 llvm::json::Value toJSON(const SelectionRange &Out) {
1225 if (Out.parent) {
1226 return llvm::json::Object{{"range", Out.range},
1227 {"parent", toJSON(*Out.parent)}};
1228 }
1229 return llvm::json::Object{{"range", Out.range}};
1230 }
1231
fromJSON(const llvm::json::Value & Params,DocumentLinkParams & R)1232 bool fromJSON(const llvm::json::Value &Params, DocumentLinkParams &R) {
1233 llvm::json::ObjectMapper O(Params);
1234 return O && O.map("textDocument", R.textDocument);
1235 }
1236
toJSON(const DocumentLink & DocumentLink)1237 llvm::json::Value toJSON(const DocumentLink &DocumentLink) {
1238 return llvm::json::Object{
1239 {"range", DocumentLink.range},
1240 {"target", DocumentLink.target},
1241 };
1242 }
1243
fromJSON(const llvm::json::Value & Params,FoldingRangeParams & R)1244 bool fromJSON(const llvm::json::Value &Params, FoldingRangeParams &R) {
1245 llvm::json::ObjectMapper O(Params);
1246 return O && O.map("textDocument", R.textDocument);
1247 }
1248
toJSON(const FoldingRange & Range)1249 llvm::json::Value toJSON(const FoldingRange &Range) {
1250 llvm::json::Object Result{
1251 {"startLine", Range.startLine},
1252 {"endLine", Range.endLine},
1253 };
1254 if (Range.startCharacter)
1255 Result["startCharacter"] = Range.startCharacter;
1256 if (Range.endCharacter)
1257 Result["endCharacter"] = Range.endCharacter;
1258 if (Range.kind)
1259 Result["kind"] = *Range.kind;
1260 return Result;
1261 }
1262
1263 } // namespace clangd
1264 } // namespace clang
1265