nixd
Loading...
Searching...
No Matches
lspserver/src/Protocol.cpp
Go to the documentation of this file.
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 "lspserver/Protocol.h"
14#include "lspserver/Logger.h"
15#include "lspserver/URI.h"
16#include <llvm/ADT/StringRef.h>
17#include <llvm/ADT/StringSwitch.h>
18#include <llvm/Support/ErrorHandling.h>
19#include <llvm/Support/JSON.h>
20#include <llvm/Support/Path.h>
21#include <llvm/Support/raw_ostream.h>
22
23namespace lspserver {
24namespace {
25
26// Helper that doesn't treat `null` and absent fields as failures.
27template <typename T>
28bool mapOptOrNull(const llvm::json::Value &Params, llvm::StringLiteral Prop,
29 T &Out, llvm::json::Path P) {
30 auto *O = Params.getAsObject();
31 assert(O);
32 auto *V = O->get(Prop);
33 // Field is missing or null.
34 if (!V || V->getAsNull())
35 return true;
36 return fromJSON(*V, Out, P.field(Prop));
37}
38} // namespace
39
40char LSPError::ID;
41
43 llvm::StringRef TUPath) {
44 assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative");
46 if (!Resolved) {
47 elog("URIForFile: failed to resolve path {0} with TU path {1}: "
48 "{2}.\nUsing unresolved path.",
49 AbsPath, TUPath, Resolved.takeError());
50 return URIForFile(std::string(AbsPath));
51 }
52 return URIForFile(std::move(*Resolved));
53}
54
55llvm::Expected<URIForFile> URIForFile::fromURI(const URI &U,
56 llvm::StringRef HintPath) {
58 if (!Resolved)
59 return Resolved.takeError();
60 return URIForFile(std::move(*Resolved));
61}
62
63bool fromJSON(const llvm::json::Value &E, URIForFile &R, llvm::json::Path P) {
64 if (auto S = E.getAsString()) {
65 auto Parsed = URI::parse(*S);
66 if (!Parsed) {
67 consumeError(Parsed.takeError());
68 P.report("failed to parse URI");
69 return false;
70 }
71 if (Parsed->scheme() != "file" && Parsed->scheme() != "test") {
72 P.report("clangd only supports 'file' URI scheme for workspace files");
73 return false;
74 }
75 // "file" and "test" schemes do not require hint path.
76 auto U = URIForFile::fromURI(*Parsed, /*HintPath=*/"");
77 if (!U) {
78 P.report("unresolvable URI");
79 consumeError(U.takeError());
80 return false;
81 }
82 R = std::move(*U);
83 return true;
84 }
85 return false;
86}
87
88llvm::json::Value toJSON(const URIForFile &U) { return U.uri(); }
89
90llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) {
91 return OS << U.uri();
92}
93
94llvm::json::Value toJSON(const TextDocumentIdentifier &R) {
95 return llvm::json::Object{{"uri", R.uri}};
96}
97
98bool fromJSON(const llvm::json::Value &Params, TextDocumentIdentifier &R,
99 llvm::json::Path P) {
100 llvm::json::ObjectMapper O(Params, P);
101 return O && O.map("uri", R.uri);
102}
103
104llvm::json::Value toJSON(const VersionedTextDocumentIdentifier &R) {
105 auto Result = toJSON(static_cast<const TextDocumentIdentifier &>(R));
106 Result.getAsObject()->try_emplace("version", R.version);
107 return Result;
108}
109
110bool fromJSON(const llvm::json::Value &Params,
111 VersionedTextDocumentIdentifier &R, llvm::json::Path P) {
112 llvm::json::ObjectMapper O(Params, P);
113 return fromJSON(Params, static_cast<TextDocumentIdentifier &>(R), P) && O &&
114 O.map("version", R.version);
115}
116
117bool fromJSON(const llvm::json::Value &Params, Position &R,
118 llvm::json::Path P) {
119 llvm::json::ObjectMapper O(Params, P);
120 return O && O.map("line", R.line) && O.map("character", R.character);
121}
122
123llvm::json::Value toJSON(const Position &P) {
124 return llvm::json::Object{
125 {"line", P.line},
126 {"character", P.character},
127 };
128}
129
130llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) {
131 return OS << P.line << ':' << P.character;
132}
133
134bool fromJSON(const llvm::json::Value &Params, Range &R, llvm::json::Path P) {
135 llvm::json::ObjectMapper O(Params, P);
136 return O && O.map("start", R.start) && O.map("end", R.end);
137}
138
139llvm::json::Value toJSON(const Range &P) {
140 return llvm::json::Object{
141 {"start", P.start},
142 {"end", P.end},
143 };
144}
145
146llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) {
147 return OS << R.start << '-' << R.end;
148}
149
150llvm::json::Value toJSON(const Location &P) {
151 return llvm::json::Object{
152 {"uri", P.uri},
153 {"range", P.range},
154 };
155}
156
157bool fromJSON(const llvm::json::Value &Params, Location &R,
158 llvm::json::Path P) {
159 llvm::json::ObjectMapper O(Params, P);
160 return O && O.map("uri", R.uri) && O.map("range", R.range);
161}
162
163llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) {
164 return OS << L.range << '@' << L.uri;
165}
166
167llvm::json::Value toJSON(const ReferenceLocation &P) {
168 llvm::json::Object Result{
169 {"uri", P.uri},
170 {"range", P.range},
171 };
172 if (P.containerName)
173 Result.insert({"containerName", P.containerName});
174 return Result;
175}
176
177llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
178 const ReferenceLocation &L) {
179 return OS << L.range << '@' << L.uri << " (container: " << L.containerName
180 << ")";
181}
182
183bool fromJSON(const llvm::json::Value &Params, TextDocumentItem &R,
184 llvm::json::Path P) {
185 llvm::json::ObjectMapper O(Params, P);
186 return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&
187 O.map("version", R.version) && O.map("text", R.text);
188}
189
190bool fromJSON(const llvm::json::Value &Params, TextEdit &R,
191 llvm::json::Path P) {
192 llvm::json::ObjectMapper O(Params, P);
193 return O && O.map("range", R.range) && O.map("newText", R.newText) &&
194 O.mapOptional("annotationId", R.annotationId);
195}
196
197llvm::json::Value toJSON(const TextEdit &P) {
198 llvm::json::Object Result{
199 {"range", P.range},
200 {"newText", P.newText},
201 };
202 if (!P.annotationId.empty())
203 Result["annotationId"] = P.annotationId;
204 return Result;
205}
206
207bool fromJSON(const llvm::json::Value &Params, ChangeAnnotation &R,
208 llvm::json::Path P) {
209 llvm::json::ObjectMapper O(Params, P);
210 return O && O.map("label", R.label) &&
211 O.map("needsConfirmation", R.needsConfirmation) &&
212 O.mapOptional("description", R.description);
213}
214llvm::json::Value toJSON(const ChangeAnnotation &CA) {
215 llvm::json::Object Result{{"label", CA.label}};
216 if (CA.needsConfirmation)
217 Result["needsConfirmation"] = *CA.needsConfirmation;
218 if (!CA.description.empty())
219 Result["description"] = CA.description;
220 return Result;
221}
222
223bool fromJSON(const llvm::json::Value &Params, TextDocumentEdit &R,
224 llvm::json::Path P) {
225 llvm::json::ObjectMapper O(Params, P);
226 return O && O.map("textDocument", R.textDocument) && O.map("edits", R.edits);
227}
228llvm::json::Value toJSON(const TextDocumentEdit &P) {
229 llvm::json::Object Result{{"textDocument", P.textDocument},
230 {"edits", P.edits}};
231 return Result;
232}
233
234llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {
235 OS << TE.range << " => \"";
236 llvm::printEscapedString(TE.newText, OS);
237 return OS << '"';
238}
239
240bool fromJSON(const llvm::json::Value &E, TraceLevel &Out, llvm::json::Path P) {
241 if (auto S = E.getAsString()) {
242 if (*S == "off") {
243 Out = TraceLevel::Off;
244 return true;
245 }
246 if (*S == "messages") {
248 return true;
249 }
250 if (*S == "verbose") {
252 return true;
253 }
254 }
255 return false;
256}
257
258bool fromJSON(const llvm::json::Value &E, SymbolKind &Out, llvm::json::Path P) {
259 if (auto T = E.getAsInteger()) {
260 if (*T < static_cast<int>(SymbolKind::File) ||
261 *T > static_cast<int>(SymbolKind::TypeParameter))
262 return false;
263 Out = static_cast<SymbolKind>(*T);
264 return true;
265 }
266 return false;
267}
268
269bool fromJSON(const llvm::json::Value &E, SymbolKindBitset &Out,
270 llvm::json::Path P) {
271 if (auto *A = E.getAsArray()) {
272 for (size_t I = 0; I < A->size(); ++I) {
274 if (fromJSON((*A)[I], KindOut, P.index(I)))
275 Out.set(size_t(KindOut));
276 }
277 return true;
278 }
279 return false;
280}
281
284 auto KindVal = static_cast<size_t>(Kind);
287 return Kind;
288
289 switch (Kind) {
290 // Provide some fall backs for common kinds that are close enough.
292 return SymbolKind::Class;
294 return SymbolKind::Enum;
295 default:
296 return SymbolKind::String;
297 }
298}
299
300bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R,
301 llvm::json::Path P) {
302 const llvm::json::Object *O = Params.getAsObject();
303 if (!O) {
304 P.report("expected object");
305 return false;
306 }
307 if (auto *TextDocument = O->getObject("textDocument")) {
308 if (auto *SemanticHighlighting =
309 TextDocument->getObject("semanticHighlightingCapabilities")) {
311 SemanticHighlighting->getBoolean("semanticHighlighting"))
313 }
314 if (auto *InactiveRegions =
315 TextDocument->getObject("inactiveRegionsCapabilities")) {
316 if (auto InactiveRegionsSupport =
317 InactiveRegions->getBoolean("inactiveRegions")) {
319 }
320 }
321 if (TextDocument->getObject("semanticTokens"))
322 R.SemanticTokens = true;
323 if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {
324 if (auto CategorySupport = Diagnostics->getBoolean("categorySupport"))
326 if (auto CodeActions = Diagnostics->getBoolean("codeActionsInline"))
328 if (auto RelatedInfo = Diagnostics->getBoolean("relatedInformation"))
330 }
331 if (auto *References = TextDocument->getObject("references"))
332 if (auto ContainerSupport = References->getBoolean("container"))
334 if (auto *Completion = TextDocument->getObject("completion")) {
335 if (auto *Item = Completion->getObject("completionItem")) {
336 if (auto SnippetSupport = Item->getBoolean("snippetSupport"))
338 if (const auto *DocumentationFormat =
339 Item->getArray("documentationFormat")) {
340 for (const auto &Format : *DocumentationFormat) {
342 break;
343 }
344 }
345 }
346 if (auto *ItemKind = Completion->getObject("completionItemKind")) {
347 if (auto *ValueSet = ItemKind->get("valueSet")) {
348 R.CompletionItemKinds.emplace();
350 P.field("textDocument")
351 .field("completion")
352 .field("completionItemKind")
353 .field("valueSet")))
354 return false;
355 }
356 }
357 if (auto EditsNearCursor = Completion->getBoolean("editsNearCursor"))
359 }
360 if (auto *CodeAction = TextDocument->getObject("codeAction")) {
361 if (CodeAction->getObject("codeActionLiteralSupport"))
362 R.CodeActionStructure = true;
363 }
364 if (auto *DocumentSymbol = TextDocument->getObject("documentSymbol")) {
365 if (auto HierarchicalSupport =
366 DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
368 }
369 if (auto *Hover = TextDocument->getObject("hover")) {
370 if (auto *ContentFormat = Hover->getArray("contentFormat")) {
371 for (const auto &Format : *ContentFormat) {
373 break;
374 }
375 }
376 }
377 if (auto *Help = TextDocument->getObject("signatureHelp")) {
378 R.HasSignatureHelp = true;
379 if (auto *Info = Help->getObject("signatureInformation")) {
380 if (auto *Parameter = Info->getObject("parameterInformation")) {
381 if (auto OffsetSupport = Parameter->getBoolean("labelOffsetSupport"))
383 }
384 if (const auto *DocumentationFormat =
385 Info->getArray("documentationFormat")) {
386 for (const auto &Format : *DocumentationFormat) {
388 break;
389 }
390 }
391 }
392 }
393 if (auto *Folding = TextDocument->getObject("foldingRange")) {
394 if (auto LineFolding = Folding->getBoolean("lineFoldingOnly"))
396 }
397 if (auto *Rename = TextDocument->getObject("rename")) {
398 if (auto RenameSupport = Rename->getBoolean("prepareSupport"))
400 }
401 }
402 if (auto *Workspace = O->getObject("workspace")) {
403 if (auto *Symbol = Workspace->getObject("symbol")) {
404 if (auto *SymbolKind = Symbol->getObject("symbolKind")) {
405 if (auto *ValueSet = SymbolKind->get("valueSet")) {
406 R.WorkspaceSymbolKinds.emplace();
408 P.field("workspace")
409 .field("symbol")
410 .field("symbolKind")
411 .field("valueSet")))
412 return false;
413 }
414 }
415 }
416
417 if (auto WorkspaceConfiguration = Workspace->getBoolean("configuration")) {
418 R.WorkspaceConfiguration = *WorkspaceConfiguration;
419 }
420
421 if (auto *SemanticTokens = Workspace->getObject("semanticTokens")) {
422 if (auto RefreshSupport = SemanticTokens->getBoolean("refreshSupport"))
424 }
425 if (auto *WorkspaceEdit = Workspace->getObject("workspaceEdit")) {
426 if (auto DocumentChanges = WorkspaceEdit->getBoolean("documentChanges"))
427 R.DocumentChanges = *DocumentChanges;
428 if (WorkspaceEdit->getObject("changeAnnotationSupport")) {
429 R.ChangeAnnotation = true;
430 }
431 }
432 }
433 if (auto *Window = O->getObject("window")) {
434 if (auto WorkDoneProgress = Window->getBoolean("workDoneProgress"))
435 R.WorkDoneProgress = *WorkDoneProgress;
436 if (auto Implicit = Window->getBoolean("implicitWorkDoneProgressCreate"))
438 }
439 if (auto *General = O->getObject("general")) {
440 if (auto *StaleRequestSupport = General->getObject("staleRequestSupport")) {
441 if (auto Cancel = StaleRequestSupport->getBoolean("cancel"))
443 }
444 }
445 if (auto *OffsetEncoding = O->get("offsetEncoding")) {
446 R.offsetEncoding.emplace();
448 P.field("offsetEncoding")))
449 return false;
450 }
451 return true;
452}
453
454bool fromJSON(const llvm::json::Value &Params, InitializeParams &R,
455 llvm::json::Path P) {
456 llvm::json::ObjectMapper O(Params, P);
457 if (!O)
458 return false;
459 // We deliberately don't fail if we can't parse individual fields.
460 // Failing to handle a slightly malformed initialize would be a disaster.
461 O.map("processId", R.processId);
462 O.map("rootUri", R.rootUri);
463 O.map("rootPath", R.rootPath);
464 O.map("capabilities", R.capabilities);
465 if (auto *RawCaps = Params.getAsObject()->getObject("capabilities"))
467 O.map("trace", R.trace);
468 O.map("initializationOptions", R.initializationOptions);
469 return true;
470}
471
472llvm::json::Value toJSON(const WorkDoneProgressCreateParams &P) {
473 return llvm::json::Object{{"token", P.token}};
474}
475
476llvm::json::Value toJSON(const WorkDoneProgressBegin &P) {
477 llvm::json::Object Result{
478 {"kind", "begin"},
479 {"title", P.title},
480 };
481 if (P.cancellable)
482 Result["cancellable"] = true;
483 if (P.percentage)
484 Result["percentage"] = 0;
485
486 // FIXME: workaround for older gcc/clang
487 return Result;
488}
489
490llvm::json::Value toJSON(const WorkDoneProgressReport &P) {
491 llvm::json::Object Result{{"kind", "report"}};
492 if (P.cancellable)
493 Result["cancellable"] = *P.cancellable;
494 if (P.message)
495 Result["message"] = *P.message;
496 if (P.percentage)
497 Result["percentage"] = *P.percentage;
498 // FIXME: workaround for older gcc/clang
499 return Result;
500}
501
502llvm::json::Value toJSON(const WorkDoneProgressEnd &P) {
503 llvm::json::Object Result{{"kind", "end"}};
504 if (P.message)
505 Result["message"] = *P.message;
506 // FIXME: workaround for older gcc/clang
507 return Result;
508}
509
510llvm::json::Value toJSON(const MessageType &R) {
511 return static_cast<int64_t>(R);
512}
513
514llvm::json::Value toJSON(const ShowMessageParams &R) {
515 return llvm::json::Object{{"type", R.type}, {"message", R.message}};
516}
517
518bool fromJSON(const llvm::json::Value &Params, DidOpenTextDocumentParams &R,
519 llvm::json::Path P) {
520 llvm::json::ObjectMapper O(Params, P);
521 return O && O.map("textDocument", R.textDocument);
522}
523
524bool fromJSON(const llvm::json::Value &Params, DidCloseTextDocumentParams &R,
525 llvm::json::Path P) {
526 llvm::json::ObjectMapper O(Params, P);
527 return O && O.map("textDocument", R.textDocument);
528}
529
530bool fromJSON(const llvm::json::Value &Params, DidSaveTextDocumentParams &R,
531 llvm::json::Path P) {
532 llvm::json::ObjectMapper O(Params, P);
533 return O && O.map("textDocument", R.textDocument);
534}
535
536bool fromJSON(const llvm::json::Value &Params, DidChangeTextDocumentParams &R,
537 llvm::json::Path P) {
538 llvm::json::ObjectMapper O(Params, P);
539 return O && O.map("textDocument", R.textDocument) &&
540 O.map("contentChanges", R.contentChanges) &&
541 O.map("wantDiagnostics", R.wantDiagnostics) &&
542 mapOptOrNull(Params, "forceRebuild", R.forceRebuild, P);
543}
544
545bool fromJSON(const llvm::json::Value &E, FileChangeType &Out,
546 llvm::json::Path P) {
547 if (auto T = E.getAsInteger()) {
548 if (*T < static_cast<int>(FileChangeType::Created) ||
549 *T > static_cast<int>(FileChangeType::Deleted))
550 return false;
551 Out = static_cast<FileChangeType>(*T);
552 return true;
553 }
554 return false;
555}
556
557bool fromJSON(const llvm::json::Value &Params, FileEvent &R,
558 llvm::json::Path P) {
559 llvm::json::ObjectMapper O(Params, P);
560 return O && O.map("uri", R.uri) && O.map("type", R.type);
561}
562
563bool fromJSON(const llvm::json::Value &Params, DidChangeWatchedFilesParams &R,
564 llvm::json::Path P) {
565 llvm::json::ObjectMapper O(Params, P);
566 return O && O.map("changes", R.changes);
567}
568
569bool fromJSON(const llvm::json::Value &Params,
570 TextDocumentContentChangeEvent &R, llvm::json::Path P) {
571 llvm::json::ObjectMapper O(Params, P);
572 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
573 O.map("text", R.text);
574}
575
576bool fromJSON(const llvm::json::Value &Params, DocumentRangeFormattingParams &R,
577 llvm::json::Path P) {
578 llvm::json::ObjectMapper O(Params, P);
579 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
580}
581
582bool fromJSON(const llvm::json::Value &Params,
583 DocumentOnTypeFormattingParams &R, llvm::json::Path P) {
584 llvm::json::ObjectMapper O(Params, P);
585 return O && O.map("textDocument", R.textDocument) &&
586 O.map("position", R.position) && O.map("ch", R.ch);
587}
588
589bool fromJSON(const llvm::json::Value &Params, DocumentFormattingParams &R,
590 llvm::json::Path P) {
591 llvm::json::ObjectMapper O(Params, P);
592 return O && O.map("textDocument", R.textDocument);
593}
594
595bool fromJSON(const llvm::json::Value &Params, DocumentSymbolParams &R,
596 llvm::json::Path P) {
597 llvm::json::ObjectMapper O(Params, P);
598 return O && O.map("textDocument", R.textDocument);
599}
600
601llvm::json::Value toJSON(const DiagnosticRelatedInformation &DRI) {
602 return llvm::json::Object{
603 {"location", DRI.location},
604 {"message", DRI.message},
605 };
606}
607
608llvm::json::Value toJSON(DiagnosticTag Tag) { return static_cast<int>(Tag); }
609
610llvm::json::Value toJSON(const CodeDescription &D) {
611 return llvm::json::Object{{"href", D.href}};
612}
613
614llvm::json::Value toJSON(const Diagnostic &D) {
615 llvm::json::Object Diag{
616 {"range", D.range},
617 {"severity", D.severity},
618 {"message", D.message},
619 };
620 if (D.category)
621 Diag["category"] = *D.category;
622 if (D.codeActions)
623 Diag["codeActions"] = D.codeActions;
624 if (!D.code.empty())
625 Diag["code"] = D.code;
626 if (D.codeDescription)
627 Diag["codeDescription"] = *D.codeDescription;
628 if (!D.source.empty())
629 Diag["source"] = D.source;
630 if (D.relatedInformation)
631 Diag["relatedInformation"] = *D.relatedInformation;
632 if (!D.data.empty())
633 Diag["data"] = llvm::json::Object(D.data);
634 if (!D.tags.empty())
635 Diag["tags"] = llvm::json::Array{D.tags};
636 // FIXME: workaround for older gcc/clang
637 return Diag;
638}
639
640bool fromJSON(const llvm::json::Value &Params, Diagnostic &R,
641 llvm::json::Path P) {
642 llvm::json::ObjectMapper O(Params, P);
643 if (!O)
644 return false;
645 if (auto *Data = Params.getAsObject()->getObject("data"))
646 R.data = *Data;
647 return O.map("range", R.range) && O.map("message", R.message) &&
648 mapOptOrNull(Params, "severity", R.severity, P) &&
649 mapOptOrNull(Params, "category", R.category, P) &&
650 mapOptOrNull(Params, "code", R.code, P) &&
651 mapOptOrNull(Params, "source", R.source, P);
652}
653
654llvm::json::Value toJSON(const PublishDiagnosticsParams &PDP) {
655 llvm::json::Object Result{
656 {"uri", PDP.uri},
657 {"diagnostics", PDP.diagnostics},
658 };
659 if (PDP.version)
660 Result["version"] = PDP.version;
661 return Result;
662}
663
664bool fromJSON(const llvm::json::Value &Params, CodeActionContext &R,
665 llvm::json::Path P) {
666 llvm::json::ObjectMapper O(Params, P);
667 if (!O || !O.map("diagnostics", R.diagnostics))
668 return false;
669 O.map("only", R.only);
670 return true;
671}
672
673llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
674 OS << D.range << " [";
675 switch (D.severity) {
676 case 1:
677 OS << "error";
678 break;
679 case 2:
680 OS << "warning";
681 break;
682 case 3:
683 OS << "note";
684 break;
685 case 4:
686 OS << "remark";
687 break;
688 default:
689 OS << "diagnostic";
690 break;
691 }
692 return OS << '(' << D.severity << "): " << D.message << "]";
693}
694
695bool fromJSON(const llvm::json::Value &Params, CodeActionParams &R,
696 llvm::json::Path P) {
697 llvm::json::ObjectMapper O(Params, P);
698 return O && O.map("textDocument", R.textDocument) &&
699 O.map("range", R.range) && O.map("context", R.context);
700}
701
702bool fromJSON(const llvm::json::Value &Params, WorkspaceEdit &R,
703 llvm::json::Path P) {
704 llvm::json::ObjectMapper O(Params, P);
705 return O && O.map("changes", R.changes) &&
706 O.map("documentChanges", R.documentChanges) &&
707 O.mapOptional("changeAnnotations", R.changeAnnotations);
708}
709
710bool fromJSON(const llvm::json::Value &Params, ExecuteCommandParams &R,
711 llvm::json::Path P) {
712 llvm::json::ObjectMapper O(Params, P);
713 if (!O || !O.map("command", R.command))
714 return false;
715
716 const auto *Args = Params.getAsObject()->get("arguments");
717 if (!Args)
718 return true; // Missing args is ok, argument is null.
719 const auto *ArgsArray = Args->getAsArray();
720 if (!ArgsArray) {
721 P.field("arguments").report("expected array");
722 return false;
723 }
724 if (ArgsArray->size() > 1) {
725 P.field("arguments").report("Command should have 0 or 1 argument");
726 return false;
727 }
728 if (ArgsArray->size() == 1) {
729 R.argument = ArgsArray->front();
730 }
731 return true;
732}
733
734llvm::json::Value toJSON(const SymbolInformation &P) {
735 llvm::json::Object O{
736 {"name", P.name},
737 {"kind", static_cast<int>(P.kind)},
738 {"location", P.location},
739 {"containerName", P.containerName},
740 };
741 if (P.score)
742 O["score"] = *P.score;
743 return O;
744}
745
746llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
747 const SymbolInformation &SI) {
748 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
749 return O;
750}
751
752bool fromJSON(const llvm::json::Value &Params, WorkspaceSymbolParams &R,
753 llvm::json::Path P) {
754 llvm::json::ObjectMapper O(Params, P);
755 return O && O.map("query", R.query) &&
756 mapOptOrNull(Params, "limit", R.limit, P);
757}
758
759llvm::json::Value toJSON(const Command &C) {
760 auto Cmd = llvm::json::Object{{"title", C.title}, {"command", C.command}};
761 if (!C.argument.getAsNull())
762 Cmd["arguments"] = llvm::json::Array{C.argument};
763 return Cmd;
764}
765
766const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";
767const llvm::StringLiteral CodeAction::REFACTOR_KIND = "refactor";
768const llvm::StringLiteral CodeAction::INFO_KIND = "info";
769
770llvm::json::Value toJSON(const CodeAction &CA) {
771 auto CodeAction = llvm::json::Object{{"title", CA.title}};
772 if (CA.kind)
773 CodeAction["kind"] = *CA.kind;
774 if (CA.diagnostics)
775 CodeAction["diagnostics"] = llvm::json::Array(*CA.diagnostics);
776 if (CA.isPreferred)
777 CodeAction["isPreferred"] = true;
778 if (CA.edit)
779 CodeAction["edit"] = *CA.edit;
780 if (CA.command)
781 CodeAction["command"] = *CA.command;
782 return CodeAction;
783}
784
785llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S) {
786 return O << S.name << " - " << toJSON(S);
787}
788
789llvm::json::Value toJSON(const DocumentSymbol &S) {
790 llvm::json::Object Result{{"name", S.name},
791 {"kind", static_cast<int>(S.kind)},
792 {"range", S.range},
793 {"selectionRange", S.selectionRange}};
794
795 if (!S.detail.empty())
796 Result["detail"] = S.detail;
797 if (!S.children.empty())
798 Result["children"] = S.children;
799 if (S.deprecated)
800 Result["deprecated"] = true;
801 // FIXME: workaround for older gcc/clang
802 return Result;
803}
804
805llvm::json::Value toJSON(const WorkspaceEdit &WE) {
806 llvm::json::Object Result;
807 if (WE.changes) {
808 llvm::json::Object FileChanges;
809 for (auto &Change : *WE.changes)
810 FileChanges[Change.first] = llvm::json::Array(Change.second);
811 Result["changes"] = std::move(FileChanges);
812 }
813 if (WE.documentChanges)
814 Result["documentChanges"] = *WE.documentChanges;
815 if (!WE.changeAnnotations.empty()) {
816 llvm::json::Object ChangeAnnotations;
817 for (auto &Annotation : WE.changeAnnotations)
819 Result["changeAnnotations"] = std::move(ChangeAnnotations);
820 }
821 return Result;
822}
823
824bool fromJSON(const llvm::json::Value &Params, TweakArgs &A,
825 llvm::json::Path P) {
826 llvm::json::ObjectMapper O(Params, P);
827 return O && O.map("file", A.file) && O.map("selection", A.selection) &&
828 O.map("tweakID", A.tweakID);
829}
830
831llvm::json::Value toJSON(const TweakArgs &A) {
832 return llvm::json::Object{
833 {"tweakID", A.tweakID}, {"selection", A.selection}, {"file", A.file}};
834}
835
836llvm::json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
837 return llvm::json::Object{{"edit", Params.edit}};
838}
839
840bool fromJSON(const llvm::json::Value &Response, ApplyWorkspaceEditResponse &R,
841 llvm::json::Path P) {
842 llvm::json::ObjectMapper O(Response, P);
843 return O && O.map("applied", R.applied) &&
844 O.map("failureReason", R.failureReason);
845}
846
847bool fromJSON(const llvm::json::Value &Params, TextDocumentPositionParams &R,
848 llvm::json::Path P) {
849 llvm::json::ObjectMapper O(Params, P);
850 return O && O.map("textDocument", R.textDocument) &&
851 O.map("position", R.position);
852}
853
854bool fromJSON(const llvm::json::Value &Params, CompletionContext &R,
855 llvm::json::Path P) {
856 llvm::json::ObjectMapper O(Params, P);
857 int TriggerKind;
858 if (!O || !O.map("triggerKind", TriggerKind) ||
859 !mapOptOrNull(Params, "triggerCharacter", R.triggerCharacter, P))
860 return false;
862 return true;
863}
864
865bool fromJSON(const llvm::json::Value &Params, CompletionParams &R,
866 llvm::json::Path P) {
867 if (!fromJSON(Params, static_cast<TextDocumentPositionParams &>(R), P) ||
868 !mapOptOrNull(Params, "limit", R.limit, P))
869 return false;
870 if (auto *Context = Params.getAsObject()->get("context"))
871 return fromJSON(*Context, R.context, P.field("context"));
872 return true;
873}
874
875static llvm::StringRef toTextKind(MarkupKind Kind) {
876 switch (Kind) {
878 return "plaintext";
880 return "markdown";
881 }
882 llvm_unreachable("Invalid MarkupKind");
883}
884
885static MarkupKind fromTextKind(llvm::StringRef Kind) {
886 if (Kind == "plaintext")
888 if (Kind == "markdown")
890 llvm_unreachable("Invalid MarkupKind");
891}
892
893bool fromJSON(const llvm::json::Value &V, MarkupKind &K, llvm::json::Path P) {
894 auto Str = V.getAsString();
895 if (!Str) {
896 P.report("expected string");
897 return false;
898 }
899 if (*Str == "plaintext")
901 else if (*Str == "markdown")
903 else {
904 P.report("unknown markup kind");
905 return false;
906 }
907 return true;
908}
909
910llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) {
911 return OS << toTextKind(K);
912}
913
914llvm::json::Value toJSON(const MarkupContent &MC) {
915 if (MC.value.empty())
916 return nullptr;
917
918 return llvm::json::Object{
919 {"kind", toTextKind(MC.kind)},
920 {"value", MC.value},
921 };
922}
923
924bool fromJSON(const llvm::json::Value &Params, MarkupContent &R,
925 llvm::json::Path P) {
926 llvm::json::ObjectMapper O(Params, P);
927 std::string MarkupKind;
928 O.map("kind", MarkupKind);
929 R.kind = fromTextKind(MarkupKind);
930 return O.mapOptional("value", R.value);
931}
932
933llvm::json::Value toJSON(const Hover &H) {
934 llvm::json::Object Result{{"contents", toJSON(H.contents)}};
935
936 if (H.range)
937 Result["range"] = toJSON(*H.range);
938
939 return Result;
940}
941
942bool fromJSON(const llvm::json::Value &E, CompletionItemKind &Out,
943 llvm::json::Path P) {
944 if (auto T = E.getAsInteger()) {
945 if (*T < static_cast<int>(CompletionItemKind::Text) ||
946 *T > static_cast<int>(CompletionItemKind::TypeParameter))
947 return false;
948 Out = static_cast<CompletionItemKind>(*T);
949 return true;
950 }
951 return false;
952}
953
957 auto KindVal = static_cast<size_t>(Kind);
961 return Kind;
962
963 switch (Kind) {
964 // Provide some fall backs for common kinds that are close enough.
971 default:
973 }
974}
975
976bool fromJSON(const llvm::json::Value &E, CompletionItemKindBitset &Out,
977 llvm::json::Path P) {
978 if (auto *A = E.getAsArray()) {
979 for (size_t I = 0; I < A->size(); ++I) {
981 if (fromJSON((*A)[I], KindOut, P.index(I)))
982 Out.set(size_t(KindOut));
983 }
984 return true;
985 }
986 return false;
987}
988
989llvm::json::Value toJSON(const CompletionItem &CI) {
990 assert(!CI.label.empty() && "completion item label is required");
991 llvm::json::Object Result{{"label", CI.label}};
993 Result["kind"] = static_cast<int>(CI.kind);
994 if (!CI.detail.empty())
995 Result["detail"] = CI.detail;
996 if (CI.documentation)
997 Result["documentation"] = CI.documentation;
998 if (!CI.sortText.empty())
999 Result["sortText"] = CI.sortText;
1000 if (!CI.filterText.empty())
1001 Result["filterText"] = CI.filterText;
1002 if (!CI.insertText.empty())
1003 Result["insertText"] = CI.insertText;
1004 if (CI.insertTextFormat != InsertTextFormat::Missing)
1005 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
1006 if (CI.textEdit)
1007 Result["textEdit"] = *CI.textEdit;
1008 if (!CI.additionalTextEdits.empty())
1009 Result["additionalTextEdits"] = llvm::json::Array(CI.additionalTextEdits);
1010 if (CI.deprecated)
1011 Result["deprecated"] = CI.deprecated;
1012 Result["score"] = CI.score;
1013 Result["data"] = CI.data;
1014 return Result;
1015}
1016
1017bool fromJSON(const llvm::json::Value &Params, CompletionItem &R,
1018 llvm::json::Path P) {
1019 llvm::json::ObjectMapper O(Params, P);
1020 int Kind;
1021 if (!O.mapOptional("kind", Kind))
1022 return false;
1023 R.kind = static_cast<CompletionItemKind>(Kind);
1024
1025 if (!O.mapOptional("insertTextFormat", Kind))
1026 return false;
1027 R.insertTextFormat = static_cast<InsertTextFormat>(Kind);
1028 return O //
1029 && O.map("label", R.label) //
1030 && O.mapOptional("detail", R.detail) //
1031 && O.mapOptional("documentation", R.documentation) //
1032 && O.mapOptional("sortText", R.sortText) //
1033 && O.mapOptional("filterText", R.filterText) //
1034 && O.mapOptional("insertText", R.insertText) //
1035 && O.mapOptional("textEdit", R.textEdit) //
1036 && O.mapOptional("additionalTextEdits", R.additionalTextEdits) //
1037 && O.mapOptional("data", R.data) //
1038 ;
1039}
1040
1041llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) {
1042 O << I.label << " - " << toJSON(I);
1043 return O;
1044}
1045
1047 return (L.sortText.empty() ? L.label : L.sortText) <
1048 (R.sortText.empty() ? R.label : R.sortText);
1049}
1050
1051llvm::json::Value toJSON(const CompletionList &L) {
1052 return llvm::json::Object{
1053 {"isIncomplete", L.isIncomplete},
1054 {"items", llvm::json::Array(L.items)},
1055 };
1056}
1057
1058llvm::json::Value toJSON(const ParameterInformation &PI) {
1059 assert((PI.labelOffsets || !PI.labelString.empty()) &&
1060 "parameter information label is required");
1061 llvm::json::Object Result;
1062 if (PI.labelOffsets)
1063 Result["label"] =
1064 llvm::json::Array({PI.labelOffsets->first, PI.labelOffsets->second});
1065 else
1066 Result["label"] = PI.labelString;
1067 if (!PI.documentation.empty())
1068 Result["documentation"] = PI.documentation;
1069 return Result;
1070}
1071
1072llvm::json::Value toJSON(const SignatureInformation &SI) {
1073 assert(!SI.label.empty() && "signature information label is required");
1074 llvm::json::Object Result{
1075 {"label", SI.label},
1076 {"parameters", llvm::json::Array(SI.parameters)},
1077 };
1078 if (!SI.documentation.value.empty())
1079 Result["documentation"] = SI.documentation;
1080 return Result;
1081}
1082
1083llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1084 const SignatureInformation &I) {
1085 O << I.label << " - " << toJSON(I);
1086 return O;
1087}
1088
1089llvm::json::Value toJSON(const SignatureHelp &SH) {
1090 assert(SH.activeSignature >= 0 &&
1091 "Unexpected negative value for number of active signatures.");
1092 assert(SH.activeParameter >= 0 &&
1093 "Unexpected negative value for active parameter index");
1094 return llvm::json::Object{
1095 {"activeSignature", SH.activeSignature},
1096 {"activeParameter", SH.activeParameter},
1097 {"signatures", llvm::json::Array(SH.signatures)},
1098 };
1099}
1100
1101bool fromJSON(const llvm::json::Value &Params, RenameParams &R,
1102 llvm::json::Path P) {
1103 llvm::json::ObjectMapper O(Params, P);
1104 return O && O.map("textDocument", R.textDocument) &&
1105 O.map("position", R.position) && O.map("newName", R.newName);
1106}
1107
1108llvm::json::Value toJSON(const DocumentHighlight &DH) {
1109 return llvm::json::Object{
1110 {"range", toJSON(DH.range)},
1111 {"kind", static_cast<int>(DH.kind)},
1112 };
1113}
1114
1115llvm::json::Value toJSON(const FileStatus &FStatus) {
1116 return llvm::json::Object{
1117 {"uri", FStatus.uri},
1118 {"state", FStatus.state},
1119 };
1120}
1121
1122constexpr unsigned SemanticTokenEncodingSize = 5;
1123static llvm::json::Value encodeTokens(llvm::ArrayRef<SemanticToken> Toks) {
1124 llvm::json::Array Result;
1125 Result.reserve(SemanticTokenEncodingSize * Toks.size());
1126 for (const auto &Tok : Toks) {
1127 Result.push_back(Tok.deltaLine);
1128 Result.push_back(Tok.deltaStart);
1129 Result.push_back(Tok.length);
1130 Result.push_back(Tok.tokenType);
1131 Result.push_back(Tok.tokenModifiers);
1132 }
1133 assert(Result.size() == SemanticTokenEncodingSize * Toks.size());
1134 return Result;
1135}
1136
1137bool operator==(const SemanticToken &L, const SemanticToken &R) {
1138 return std::tie(L.deltaLine, L.deltaStart, L.length, L.tokenType,
1139 L.tokenModifiers) == std::tie(R.deltaLine, R.deltaStart,
1140 R.length, R.tokenType,
1141 R.tokenModifiers);
1142}
1143
1144llvm::json::Value toJSON(const SemanticTokens &Tokens) {
1145 return llvm::json::Object{{"resultId", Tokens.resultId},
1146 {"data", encodeTokens(Tokens.tokens)}};
1147}
1148
1149llvm::json::Value toJSON(const SemanticTokensEdit &Edit) {
1150 return llvm::json::Object{
1151 {"start", SemanticTokenEncodingSize * Edit.startToken},
1152 {"deleteCount", SemanticTokenEncodingSize * Edit.deleteTokens},
1153 {"data", encodeTokens(Edit.tokens)}};
1154}
1155
1156llvm::json::Value toJSON(const SemanticTokensOrDelta &TE) {
1157 llvm::json::Object Result{{"resultId", TE.resultId}};
1158 if (TE.edits)
1159 Result["edits"] = *TE.edits;
1160 if (TE.tokens)
1161 Result["data"] = encodeTokens(*TE.tokens);
1162 return Result;
1163}
1164
1165bool fromJSON(const llvm::json::Value &Params, SemanticTokensParams &R,
1166 llvm::json::Path P) {
1167 llvm::json::ObjectMapper O(Params, P);
1168 return O && O.map("textDocument", R.textDocument);
1169}
1170
1171bool fromJSON(const llvm::json::Value &Params, SemanticTokensDeltaParams &R,
1172 llvm::json::Path P) {
1173 llvm::json::ObjectMapper O(Params, P);
1174 return O && O.map("textDocument", R.textDocument) &&
1175 O.map("previousResultId", R.previousResultId);
1176}
1177
1178llvm::json::Value toJSON(const InactiveRegionsParams &InactiveRegions) {
1179 return llvm::json::Object{
1180 {"textDocument", InactiveRegions.TextDocument},
1181 {"regions", std::move(InactiveRegions.InactiveRegions)}};
1182}
1183
1184llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1185 const DocumentHighlight &V) {
1186 O << V.range;
1187 if (V.kind == DocumentHighlightKind::Read)
1188 O << "(r)";
1189 if (V.kind == DocumentHighlightKind::Write)
1190 O << "(w)";
1191 return O;
1192}
1193
1194bool fromJSON(const llvm::json::Value &Params,
1195 DidChangeConfigurationParams &CCP, llvm::json::Path P) {
1196 llvm::json::ObjectMapper O(Params, P);
1197 return O && O.map("settings", CCP.settings);
1198}
1199
1200bool fromJSON(const llvm::json::Value &Params, ClangdCompileCommand &CDbUpdate,
1201 llvm::json::Path P) {
1202 llvm::json::ObjectMapper O(Params, P);
1203 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&
1204 O.map("compilationCommand", CDbUpdate.compilationCommand);
1205}
1206
1207bool fromJSON(const llvm::json::Value &Params, ConfigurationSettings &S,
1208 llvm::json::Path P) {
1209 llvm::json::ObjectMapper O(Params, P);
1210 if (!O)
1211 return true; // 'any' type in LSP.
1212 return mapOptOrNull(Params, "compilationDatabaseChanges",
1213 S.compilationDatabaseChanges, P);
1214}
1215
1216bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts,
1217 llvm::json::Path P) {
1218 llvm::json::ObjectMapper O(Params, P);
1219 if (!O)
1220 return true; // 'any' type in LSP.
1221
1222 return fromJSON(Params, Opts.ConfigSettings, P) &&
1223 O.map("compilationDatabasePath", Opts.compilationDatabasePath) &&
1224 mapOptOrNull(Params, "fallbackFlags", Opts.fallbackFlags, P) &&
1225 mapOptOrNull(Params, "clangdFileStatus", Opts.FileStatus, P);
1226}
1227
1228bool fromJSON(const llvm::json::Value &E, TypeHierarchyDirection &Out,
1229 llvm::json::Path P) {
1230 auto T = E.getAsInteger();
1231 if (!T)
1232 return false;
1233 if (*T < static_cast<int>(TypeHierarchyDirection::Children) ||
1234 *T > static_cast<int>(TypeHierarchyDirection::Both))
1235 return false;
1236 Out = static_cast<TypeHierarchyDirection>(*T);
1237 return true;
1238}
1239
1240bool fromJSON(const llvm::json::Value &Params, TypeHierarchyPrepareParams &R,
1241 llvm::json::Path P) {
1242 llvm::json::ObjectMapper O(Params, P);
1243 return O && O.map("textDocument", R.textDocument) &&
1244 O.map("position", R.position) &&
1245 mapOptOrNull(Params, "resolve", R.resolve, P) &&
1246 mapOptOrNull(Params, "direction", R.direction, P);
1247}
1248
1249llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1250 const TypeHierarchyItem &I) {
1251 return O << I.name << " - " << toJSON(I);
1252}
1253
1254llvm::json::Value toJSON(const TypeHierarchyItem::ResolveParams &RP) {
1255 llvm::json::Object Result{};
1256 if (RP.parents)
1257 Result["parents"] = RP.parents;
1258 return Result;
1259}
1260bool fromJSON(const llvm::json::Value &Params,
1261 TypeHierarchyItem::ResolveParams &RP, llvm::json::Path P) {
1262 llvm::json::ObjectMapper O(Params, P);
1263 return O && mapOptOrNull(Params, "parents", RP.parents, P);
1264}
1265
1266llvm::json::Value toJSON(const TypeHierarchyItem &I) {
1267 llvm::json::Object Result{
1268 {"name", I.name}, {"kind", static_cast<int>(I.kind)},
1269 {"range", I.range}, {"selectionRange", I.selectionRange},
1270 {"uri", I.uri}, {"data", I.data},
1271 };
1272
1273 if (I.detail)
1274 Result["detail"] = I.detail;
1275 return Result;
1276}
1277
1278bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I,
1279 llvm::json::Path P) {
1280 llvm::json::ObjectMapper O(Params, P);
1281
1282 // Required fields.
1283 return O && O.map("name", I.name) && O.map("kind", I.kind) &&
1284 O.map("uri", I.uri) && O.map("range", I.range) &&
1285 O.map("selectionRange", I.selectionRange) &&
1286 mapOptOrNull(Params, "detail", I.detail, P) &&
1287 mapOptOrNull(Params, "deprecated", I.deprecated, P) &&
1288 mapOptOrNull(Params, "parents", I.parents, P) &&
1289 mapOptOrNull(Params, "children", I.children, P) &&
1290 mapOptOrNull(Params, "data", I.data, P);
1291}
1292
1293bool fromJSON(const llvm::json::Value &Params,
1294 ResolveTypeHierarchyItemParams &R, llvm::json::Path P) {
1295 llvm::json::ObjectMapper O(Params, P);
1296 return O && O.map("item", R.item) &&
1297 mapOptOrNull(Params, "resolve", R.resolve, P) &&
1298 mapOptOrNull(Params, "direction", R.direction, P);
1299}
1300
1301bool fromJSON(const llvm::json::Value &Params, ReferenceContext &R,
1302 llvm::json::Path P) {
1303 llvm::json::ObjectMapper O(Params, P);
1304 return O && O.mapOptional("includeDeclaration", R.includeDeclaration);
1305}
1306
1307bool fromJSON(const llvm::json::Value &Params, ReferenceParams &R,
1308 llvm::json::Path P) {
1310 llvm::json::ObjectMapper O(Params, P);
1311 return fromJSON(Params, Base, P) && O && O.mapOptional("context", R.context);
1312}
1313
1314llvm::json::Value toJSON(SymbolTag Tag) {
1315 return llvm::json::Value{static_cast<int>(Tag)};
1316}
1317
1318llvm::json::Value toJSON(const CallHierarchyItem &I) {
1319 llvm::json::Object Result{{"name", I.name},
1320 {"kind", static_cast<int>(I.kind)},
1321 {"range", I.range},
1322 {"selectionRange", I.selectionRange},
1323 {"uri", I.uri}};
1324 if (!I.tags.empty())
1325 Result["tags"] = I.tags;
1326 if (!I.detail.empty())
1327 Result["detail"] = I.detail;
1328 if (!I.data.empty())
1329 Result["data"] = I.data;
1330 return Result;
1331}
1332
1333bool fromJSON(const llvm::json::Value &Params, CallHierarchyItem &I,
1334 llvm::json::Path P) {
1335 llvm::json::ObjectMapper O(Params, P);
1336
1337 // Populate the required fields only. We don't care about the
1338 // optional fields `Tags` and `Detail` for the purpose of
1339 // client --> server communication.
1340 return O && O.map("name", I.name) && O.map("kind", I.kind) &&
1341 O.map("uri", I.uri) && O.map("range", I.range) &&
1342 O.map("selectionRange", I.selectionRange) &&
1343 mapOptOrNull(Params, "data", I.data, P);
1344}
1345
1346bool fromJSON(const llvm::json::Value &Params,
1347 CallHierarchyIncomingCallsParams &C, llvm::json::Path P) {
1348 llvm::json::ObjectMapper O(Params, P);
1349 return O.map("item", C.item);
1350}
1351
1352llvm::json::Value toJSON(const CallHierarchyIncomingCall &C) {
1353 return llvm::json::Object{{"from", C.from}, {"fromRanges", C.fromRanges}};
1354}
1355
1356bool fromJSON(const llvm::json::Value &Params,
1357 CallHierarchyOutgoingCallsParams &C, llvm::json::Path P) {
1358 llvm::json::ObjectMapper O(Params, P);
1359 return O.map("item", C.item);
1360}
1361
1362llvm::json::Value toJSON(const CallHierarchyOutgoingCall &C) {
1363 return llvm::json::Object{{"to", C.to}, {"fromRanges", C.fromRanges}};
1364}
1365
1366bool fromJSON(const llvm::json::Value &Params, InlayHintsParams &R,
1367 llvm::json::Path P) {
1368 llvm::json::ObjectMapper O(Params, P);
1369 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
1370}
1371
1372llvm::json::Value toJSON(const InlayHintKind &Kind) {
1373 switch (Kind) {
1375 return 1;
1377 return 2;
1378 case InlayHintKind::Designator: // This is an extension, don't serialize.
1379 return nullptr;
1380 }
1381 llvm_unreachable("Unknown clang.clangd.InlayHintKind");
1382}
1383
1384llvm::json::Value toJSON(const InlayHint &H) {
1385 llvm::json::Object Result{{"position", H.position},
1386 {"label", H.label},
1387 {"paddingLeft", H.paddingLeft},
1388 {"paddingRight", H.paddingRight}};
1389 auto K = toJSON(H.kind);
1390 if (!K.getAsNull())
1391 Result["kind"] = std::move(K);
1392 return Result;
1393}
1394bool operator==(const InlayHint &A, const InlayHint &B) {
1395 return std::tie(A.position, A.range, A.kind, A.label) ==
1396 std::tie(B.position, B.range, B.kind, B.label);
1397}
1398bool operator<(const InlayHint &A, const InlayHint &B) {
1399 return std::tie(A.position, A.range, A.kind, A.label) <
1400 std::tie(B.position, B.range, B.kind, B.label);
1401}
1402
1403llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) {
1404 auto ToString = [](InlayHintKind K) {
1405 switch (K) {
1407 return "parameter";
1409 return "type";
1411 return "designator";
1412 }
1413 llvm_unreachable("Unknown clang.clangd.InlayHintKind");
1414 };
1415 return OS << ToString(Kind);
1416}
1417
1418static const char *toString(OffsetEncoding OE) {
1419 switch (OE) {
1421 return "utf-8";
1423 return "utf-16";
1425 return "utf-32";
1427 return "unknown";
1428 }
1429 llvm_unreachable("Unknown clang.clangd.OffsetEncoding");
1430}
1431llvm::json::Value toJSON(const OffsetEncoding &OE) { return toString(OE); }
1432bool fromJSON(const llvm::json::Value &V, OffsetEncoding &OE,
1433 llvm::json::Path P) {
1434 auto Str = V.getAsString();
1435 if (!Str)
1436 return false;
1437 OE = llvm::StringSwitch<OffsetEncoding>(*Str)
1438 .Case("utf-8", OffsetEncoding::UTF8)
1439 .Case("utf-16", OffsetEncoding::UTF16)
1440 .Case("utf-32", OffsetEncoding::UTF32)
1442 return true;
1443}
1444llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OffsetEncoding Enc) {
1445 return OS << toString(Enc);
1446}
1447
1448bool fromJSON(const llvm::json::Value &Params, SelectionRangeParams &S,
1449 llvm::json::Path P) {
1450 llvm::json::ObjectMapper O(Params, P);
1451 return O && O.map("textDocument", S.textDocument) &&
1452 O.map("positions", S.positions);
1453}
1454
1455llvm::json::Value toJSON(const SelectionRange &Out) {
1456 if (Out.parent) {
1457 return llvm::json::Object{{"range", Out.range},
1458 {"parent", toJSON(*Out.parent)}};
1459 }
1460 return llvm::json::Object{{"range", Out.range}};
1461}
1462
1463bool fromJSON(const llvm::json::Value &Params, DocumentLinkParams &R,
1464 llvm::json::Path P) {
1465 llvm::json::ObjectMapper O(Params, P);
1466 return O && O.map("textDocument", R.textDocument);
1467}
1468
1469llvm::json::Value toJSON(const DocumentLink &DocumentLink) {
1470 return llvm::json::Object{
1471 {"range", DocumentLink.range},
1472 {"target", DocumentLink.target},
1473 };
1474}
1475
1476bool fromJSON(const llvm::json::Value &Params, FoldingRangeParams &R,
1477 llvm::json::Path P) {
1478 llvm::json::ObjectMapper O(Params, P);
1479 return O && O.map("textDocument", R.textDocument);
1480}
1481
1482const llvm::StringLiteral FoldingRange::REGION_KIND = "region";
1483const llvm::StringLiteral FoldingRange::COMMENT_KIND = "comment";
1484const llvm::StringLiteral FoldingRange::IMPORT_KIND = "import";
1485
1486llvm::json::Value toJSON(const FoldingRange &Range) {
1487 llvm::json::Object Result{
1488 {"startLine", Range.startLine},
1489 {"endLine", Range.endLine},
1490 };
1491 if (Range.startCharacter)
1492 Result["startCharacter"] = Range.startCharacter;
1493 if (Range.endCharacter)
1494 Result["endCharacter"] = Range.endCharacter;
1495 if (!Range.kind.empty())
1496 Result["kind"] = Range.kind;
1497 return Result;
1498}
1499
1500bool fromJSON(const llvm::json::Value &Params, ASTParams &R,
1501 llvm::json::Path P) {
1502 llvm::json::ObjectMapper O(Params, P);
1503 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
1504}
1505
1506llvm::json::Value toJSON(const ASTNode &N) {
1507 llvm::json::Object Result{
1508 {"role", N.role},
1509 {"kind", N.kind},
1510 };
1511 if (!N.children.empty())
1512 Result["children"] = N.children;
1513 if (!N.detail.empty())
1514 Result["detail"] = N.detail;
1515 if (!N.arcana.empty())
1516 Result["arcana"] = N.arcana;
1517 if (N.range)
1518 Result["range"] = *N.range;
1519 return Result;
1520}
1521
1522llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const ASTNode &Root) {
1523 std::function<void(const ASTNode &, unsigned)> Print = [&](const ASTNode &N,
1524 unsigned Level) {
1525 OS.indent(2 * Level) << N.role << ": " << N.kind;
1526 if (!N.detail.empty())
1527 OS << " - " << N.detail;
1528 OS << "\n";
1529 for (const ASTNode &C : N.children)
1530 Print(C, Level + 1);
1531 };
1532 Print(Root, 0);
1533 return OS;
1534}
1535
1536llvm::json::Value toJSON(const ConfigurationItem &N) {
1537 llvm::json::Object R;
1538 if (N.scopeUri)
1539 R["scopeUri"] = N.scopeUri;
1540 if (N.section)
1541 R["section"] = N.section;
1542 return R;
1543}
1544
1545llvm::json::Value toJSON(const ConfigurationParams &N) {
1546 return llvm::json::Object{{"items", N.items}};
1547}
1548
1549} // namespace lspserver
static llvm::Expected< std::string > resolve(const URI &U, llvm::StringRef HintPath="")
Definition URI.cpp:242
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Definition URI.cpp:174
static llvm::Expected< std::string > resolvePath(llvm::StringRef AbsPath, llvm::StringRef HintPath="")
Definition URI.cpp:250
Whether current platform treats paths case insensitively.
Definition Connection.h:11
std::bitset< SymbolKindMax+1 > SymbolKindBitset
@ Created
The file got created.
@ Deleted
The file got deleted.
@ Info
An information message.
bool fromJSON(const llvm::json::Value &, URIForFile &, llvm::json::Path)
std::bitset< CompletionItemKindMax+1 > CompletionItemKindBitset
void elog(const char *Fmt, Ts &&...Vals)
Definition Logger.h:52
llvm::json::Value toJSON(const URIForFile &U)
Serialize/deserialize URIForFile to/from a string URI.
llvm::raw_ostream & operator<<(llvm::raw_ostream &, const Position &)
CompletionItemKind
The kind of a completion entry.
CompletionItemKind adjustKindToCapability(CompletionItemKind Kind, CompletionItemKindBitset &SupportedCompletionItemKinds)
bool operator==(const TextEdit &L, const TextEdit &R)
constexpr unsigned SemanticTokenEncodingSize
bool operator<(const CompletionItem &, const CompletionItem &)
TextDocumentIdentifier textDocument
The text document.
Represents an incoming call, e.g. a caller of a method or constructor.
The parameter of a callHierarchy/incomingCalls request.
The parameter of a callHierarchy/outgoingCalls request.
bool ChangeAnnotation
The client supports change annotations on text edits,.
bool DocumentChanges
The client supports versioned document changes for WorkspaceEdit.
std::optional< SymbolKindBitset > WorkspaceSymbolKinds
std::optional< CompletionItemKindBitset > CompletionItemKinds
std::optional< std::vector< OffsetEncoding > > offsetEncoding
Supported encodings for LSP character offsets. (clangd extension).
Range range
The range for which the command was invoked.
TextDocumentIdentifier textDocument
The document in which the command was invoked.
CodeActionContext context
Context carrying additional information.
std::string title
A short, human-readable, title for this code action.
static const llvm::StringLiteral REFACTOR_KIND
static const llvm::StringLiteral INFO_KIND
std::optional< WorkspaceEdit > edit
The workspace edit this code action performs.
static const llvm::StringLiteral QUICKFIX_KIND
Structure to capture a description for an error code.
std::string href
An URI to open with more information about the diagnostic error.
CompletionTriggerKind triggerKind
How the completion was triggered.
std::optional< MarkupContent > documentation
A human-readable string that represents a doc-comment.
Represents a collection of completion items to be presented in the editor.
std::optional< std::vector< CodeAction > > codeActions
llvm::SmallVector< DiagnosticTag, 1 > tags
Additional metadata about the diagnostic.
Range range
The range at which the message applies.
std::string message
The diagnostic's message.
std::optional< std::vector< DiagnosticRelatedInformation > > relatedInformation
std::optional< CodeDescription > codeDescription
An optional property to describe the error code.
std::string code
The diagnostic's code. Can be omitted.
std::vector< TextDocumentContentChangeEvent > contentChanges
The actual content changes.
std::vector< FileEvent > changes
The actual file events.
TextDocumentIdentifier textDocument
The document that was closed.
TextDocumentItem textDocument
The document that was opened.
TextDocumentIdentifier textDocument
The document that was saved.
TextDocumentIdentifier textDocument
The document to format.
Parameters for the document link request.
TextDocumentIdentifier textDocument
The document to provide document links for.
TextDocumentIdentifier textDocument
The document to format.
Position position
The position at which this request was sent.
std::string ch
The character that has been typed.
TextDocumentIdentifier textDocument
The document to format.
std::string command
The identifier of the actual command handler.
FileChangeType type
The change type.
Stores information about a region of code that can be folded.
static const llvm::StringLiteral IMPORT_KIND
static const llvm::StringLiteral COMMENT_KIND
static const llvm::StringLiteral REGION_KIND
TextDocumentIdentifier TextDocument
The textdocument these inactive regions belong to.
std::vector< Range > InactiveRegions
The inactive regions that should be sent.
llvm::json::Object rawCapabilities
The same data as capabilities, but not parsed (to expose to modules).
InitializationOptions initializationOptions
User-provided initialization options.
std::optional< TraceLevel > trace
The initial trace setting. If omitted trace is disabled ('off').
ClientCapabilities capabilities
The capabilities provided by the client (editor or tool)
A parameter literal used in inlay hint requests.
TextDocumentIdentifier textDocument
The text document.
URIForFile uri
The text document's URI.
A single parameter of a particular signature.
int line
Line position in a document (zero-based).
Position start
The range's start position.
Position end
The range's end position.
bool includeDeclaration
Include the declaration of the current symbol.
std::string newName
The new name of the symbol.
Position position
The position at which this request was sent.
TextDocumentIdentifier textDocument
The document that was opened.
Parameters for the typeHierarchy/resolve request.
TypeHierarchyDirection direction
The direction of the hierarchy levels to resolve.
int resolve
The hierarchy levels to resolve. 0 indicates no level.
std::unique_ptr< SelectionRange > parent
unsigned length
the length of the token. A token cannot be multiline
unsigned tokenType
will be looked up in SemanticTokensLegend.tokenTypes
unsigned deltaLine
token line number, relative to the previous token
unsigned tokenModifiers
each set bit will be looked up in SemanticTokensLegend.tokenModifiers
TextDocumentIdentifier textDocument
The text document.
Describes a replacement of a contiguous range of semanticTokens.
Body of textDocument/semanticTokens/full request.
TextDocumentIdentifier textDocument
The text document.
Represents the signature of a callable.
Represents the signature of something callable.
std::string containerName
The name of the symbol containing this symbol.
Location location
The location of this symbol.
std::string text
The new text of the range/document.
std::optional< Range > range
The range of the document that changed.
std::optional< int > rangeLength
The length of the range that got replaced.
VersionedTextDocumentIdentifier textDocument
The text document to change.
std::string languageId
The text document's language identifier.
std::string text
The content of the opened text document.
Position position
The position inside the text document.
TextDocumentIdentifier textDocument
The text document.
ChangeAnnotationIdentifier annotationId
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
static llvm::Expected< URIForFile > fromURI(const URI &U, llvm::StringRef HintPath)
llvm::json::Value token
The token to be used to report progress.
Signals the end of progress reporting.
Reporting progress is done using the following payload.
std::optional< std::map< std::string, std::vector< TextEdit > > > changes
Holds changes to existing resources.
std::map< std::string, ChangeAnnotation > changeAnnotations
std::optional< std::vector< TextDocumentEdit > > documentChanges
The parameters of a Workspace Symbol Request.