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