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::INFO_KIND = "info";
770
771llvm::json::Value toJSON(const CodeAction &CA) {
772 auto CodeAction = llvm::json::Object{{"title", CA.title}};
773 if (CA.kind)
774 CodeAction["kind"] = *CA.kind;
775 if (CA.diagnostics)
776 CodeAction["diagnostics"] = llvm::json::Array(*CA.diagnostics);
777 if (CA.isPreferred)
778 CodeAction["isPreferred"] = true;
779 if (CA.edit)
780 CodeAction["edit"] = *CA.edit;
781 if (CA.command)
782 CodeAction["command"] = *CA.command;
783 return CodeAction;
784}
785
786llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S) {
787 return O << S.name << " - " << toJSON(S);
788}
789
790llvm::json::Value toJSON(const DocumentSymbol &S) {
791 llvm::json::Object Result{{"name", S.name},
792 {"kind", static_cast<int>(S.kind)},
793 {"range", S.range},
794 {"selectionRange", S.selectionRange}};
795
796 if (!S.detail.empty())
797 Result["detail"] = S.detail;
798 if (!S.children.empty())
799 Result["children"] = S.children;
800 if (S.deprecated)
801 Result["deprecated"] = true;
802 // FIXME: workaround for older gcc/clang
803 return Result;
804}
805
806llvm::json::Value toJSON(const WorkspaceEdit &WE) {
807 llvm::json::Object Result;
808 if (WE.changes) {
809 llvm::json::Object FileChanges;
810 for (auto &Change : *WE.changes)
811 FileChanges[Change.first] = llvm::json::Array(Change.second);
812 Result["changes"] = std::move(FileChanges);
813 }
814 if (WE.documentChanges)
815 Result["documentChanges"] = *WE.documentChanges;
816 if (!WE.changeAnnotations.empty()) {
817 llvm::json::Object ChangeAnnotations;
818 for (auto &Annotation : WE.changeAnnotations)
819 ChangeAnnotations[Annotation.first] = Annotation.second;
820 Result["changeAnnotations"] = std::move(ChangeAnnotations);
821 }
822 return Result;
823}
824
825bool fromJSON(const llvm::json::Value &Params, TweakArgs &A,
826 llvm::json::Path P) {
827 llvm::json::ObjectMapper O(Params, P);
828 return O && O.map("file", A.file) && O.map("selection", A.selection) &&
829 O.map("tweakID", A.tweakID);
830}
831
832llvm::json::Value toJSON(const TweakArgs &A) {
833 return llvm::json::Object{
834 {"tweakID", A.tweakID}, {"selection", A.selection}, {"file", A.file}};
835}
836
837llvm::json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
838 return llvm::json::Object{{"edit", Params.edit}};
839}
840
841bool fromJSON(const llvm::json::Value &Response, ApplyWorkspaceEditResponse &R,
842 llvm::json::Path P) {
843 llvm::json::ObjectMapper O(Response, P);
844 return O && O.map("applied", R.applied) &&
845 O.map("failureReason", R.failureReason);
846}
847
848bool fromJSON(const llvm::json::Value &Params, TextDocumentPositionParams &R,
849 llvm::json::Path P) {
850 llvm::json::ObjectMapper O(Params, P);
851 return O && O.map("textDocument", R.textDocument) &&
852 O.map("position", R.position);
853}
854
855bool fromJSON(const llvm::json::Value &Params, CompletionContext &R,
856 llvm::json::Path P) {
857 llvm::json::ObjectMapper O(Params, P);
858 int TriggerKind;
859 if (!O || !O.map("triggerKind", TriggerKind) ||
860 !mapOptOrNull(Params, "triggerCharacter", R.triggerCharacter, P))
861 return false;
862 R.triggerKind = static_cast<CompletionTriggerKind>(TriggerKind);
863 return true;
864}
865
866bool fromJSON(const llvm::json::Value &Params, CompletionParams &R,
867 llvm::json::Path P) {
868 if (!fromJSON(Params, static_cast<TextDocumentPositionParams &>(R), P) ||
869 !mapOptOrNull(Params, "limit", R.limit, P))
870 return false;
871 if (auto *Context = Params.getAsObject()->get("context"))
872 return fromJSON(*Context, R.context, P.field("context"));
873 return true;
874}
875
876static llvm::StringRef toTextKind(MarkupKind Kind) {
877 switch (Kind) {
879 return "plaintext";
881 return "markdown";
882 }
883 llvm_unreachable("Invalid MarkupKind");
884}
885
886static MarkupKind fromTextKind(llvm::StringRef Kind) {
887 if (Kind == "plaintext")
889 if (Kind == "markdown")
891 llvm_unreachable("Invalid MarkupKind");
892}
893
894bool fromJSON(const llvm::json::Value &V, MarkupKind &K, llvm::json::Path P) {
895 auto Str = V.getAsString();
896 if (!Str) {
897 P.report("expected string");
898 return false;
899 }
900 if (*Str == "plaintext")
902 else if (*Str == "markdown")
904 else {
905 P.report("unknown markup kind");
906 return false;
907 }
908 return true;
909}
910
911llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) {
912 return OS << toTextKind(K);
913}
914
915llvm::json::Value toJSON(const MarkupContent &MC) {
916 if (MC.value.empty())
917 return nullptr;
918
919 return llvm::json::Object{
920 {"kind", toTextKind(MC.kind)},
921 {"value", MC.value},
922 };
923}
924
925bool fromJSON(const llvm::json::Value &Params, MarkupContent &R,
926 llvm::json::Path P) {
927 llvm::json::ObjectMapper O(Params, P);
928 std::string MarkupKind;
929 O.map("kind", MarkupKind);
930 R.kind = fromTextKind(MarkupKind);
931 return O.mapOptional("value", R.value);
932}
933
934llvm::json::Value toJSON(const Hover &H) {
935 llvm::json::Object Result{{"contents", toJSON(H.contents)}};
936
937 if (H.range)
938 Result["range"] = toJSON(*H.range);
939
940 return Result;
941}
942
943bool fromJSON(const llvm::json::Value &E, CompletionItemKind &Out,
944 llvm::json::Path P) {
945 if (auto T = E.getAsInteger()) {
946 if (*T < static_cast<int>(CompletionItemKind::Text) ||
947 *T > static_cast<int>(CompletionItemKind::TypeParameter))
948 return false;
949 Out = static_cast<CompletionItemKind>(*T);
950 return true;
951 }
952 return false;
953}
954
957 CompletionItemKindBitset &SupportedCompletionItemKinds) {
958 auto KindVal = static_cast<size_t>(Kind);
959 if (KindVal >= CompletionItemKindMin &&
960 KindVal <= SupportedCompletionItemKinds.size() &&
961 SupportedCompletionItemKinds[KindVal])
962 return Kind;
963
964 switch (Kind) {
965 // Provide some fall backs for common kinds that are close enough.
972 default:
974 }
975}
976
977bool fromJSON(const llvm::json::Value &E, CompletionItemKindBitset &Out,
978 llvm::json::Path P) {
979 if (auto *A = E.getAsArray()) {
980 for (size_t I = 0; I < A->size(); ++I) {
981 CompletionItemKind KindOut;
982 if (fromJSON((*A)[I], KindOut, P.index(I)))
983 Out.set(size_t(KindOut));
984 }
985 return true;
986 }
987 return false;
988}
989
990llvm::json::Value toJSON(const CompletionItem &CI) {
991 assert(!CI.label.empty() && "completion item label is required");
992 llvm::json::Object Result{{"label", CI.label}};
994 Result["kind"] = static_cast<int>(CI.kind);
995 if (!CI.detail.empty())
996 Result["detail"] = CI.detail;
997 if (CI.documentation)
998 Result["documentation"] = CI.documentation;
999 if (!CI.sortText.empty())
1000 Result["sortText"] = CI.sortText;
1001 if (!CI.filterText.empty())
1002 Result["filterText"] = CI.filterText;
1003 if (!CI.insertText.empty())
1004 Result["insertText"] = CI.insertText;
1006 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
1007 if (CI.textEdit)
1008 Result["textEdit"] = *CI.textEdit;
1009 if (!CI.additionalTextEdits.empty())
1010 Result["additionalTextEdits"] = llvm::json::Array(CI.additionalTextEdits);
1011 if (CI.deprecated)
1012 Result["deprecated"] = CI.deprecated;
1013 Result["score"] = CI.score;
1014 Result["data"] = CI.data;
1015 return Result;
1016}
1017
1018bool fromJSON(const llvm::json::Value &Params, CompletionItem &R,
1019 llvm::json::Path P) {
1020 llvm::json::ObjectMapper O(Params, P);
1021 int Kind;
1022 if (!O.mapOptional("kind", Kind))
1023 return false;
1024 R.kind = static_cast<CompletionItemKind>(Kind);
1025
1026 if (!O.mapOptional("insertTextFormat", Kind))
1027 return false;
1028 R.insertTextFormat = static_cast<InsertTextFormat>(Kind);
1029 return O //
1030 && O.map("label", R.label) //
1031 && O.mapOptional("detail", R.detail) //
1032 && O.mapOptional("documentation", R.documentation) //
1033 && O.mapOptional("sortText", R.sortText) //
1034 && O.mapOptional("filterText", R.filterText) //
1035 && O.mapOptional("insertText", R.insertText) //
1036 && O.mapOptional("textEdit", R.textEdit) //
1037 && O.mapOptional("additionalTextEdits", R.additionalTextEdits) //
1038 && O.mapOptional("data", R.data) //
1039 ;
1040}
1041
1042llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) {
1043 O << I.label << " - " << toJSON(I);
1044 return O;
1045}
1046
1047bool operator<(const CompletionItem &L, const CompletionItem &R) {
1048 return (L.sortText.empty() ? L.label : L.sortText) <
1049 (R.sortText.empty() ? R.label : R.sortText);
1050}
1051
1052llvm::json::Value toJSON(const CompletionList &L) {
1053 return llvm::json::Object{
1054 {"isIncomplete", L.isIncomplete},
1055 {"items", llvm::json::Array(L.items)},
1056 };
1057}
1058
1059llvm::json::Value toJSON(const ParameterInformation &PI) {
1060 assert((PI.labelOffsets || !PI.labelString.empty()) &&
1061 "parameter information label is required");
1062 llvm::json::Object Result;
1063 if (PI.labelOffsets)
1064 Result["label"] =
1065 llvm::json::Array({PI.labelOffsets->first, PI.labelOffsets->second});
1066 else
1067 Result["label"] = PI.labelString;
1068 if (!PI.documentation.empty())
1069 Result["documentation"] = PI.documentation;
1070 return Result;
1071}
1072
1073llvm::json::Value toJSON(const SignatureInformation &SI) {
1074 assert(!SI.label.empty() && "signature information label is required");
1075 llvm::json::Object Result{
1076 {"label", SI.label},
1077 {"parameters", llvm::json::Array(SI.parameters)},
1078 };
1079 if (!SI.documentation.value.empty())
1080 Result["documentation"] = SI.documentation;
1081 return Result;
1082}
1083
1084llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1085 const SignatureInformation &I) {
1086 O << I.label << " - " << toJSON(I);
1087 return O;
1088}
1089
1090llvm::json::Value toJSON(const SignatureHelp &SH) {
1091 assert(SH.activeSignature >= 0 &&
1092 "Unexpected negative value for number of active signatures.");
1093 assert(SH.activeParameter >= 0 &&
1094 "Unexpected negative value for active parameter index");
1095 return llvm::json::Object{
1096 {"activeSignature", SH.activeSignature},
1097 {"activeParameter", SH.activeParameter},
1098 {"signatures", llvm::json::Array(SH.signatures)},
1099 };
1100}
1101
1102bool fromJSON(const llvm::json::Value &Params, RenameParams &R,
1103 llvm::json::Path P) {
1104 llvm::json::ObjectMapper O(Params, P);
1105 return O && O.map("textDocument", R.textDocument) &&
1106 O.map("position", R.position) && O.map("newName", R.newName);
1107}
1108
1109llvm::json::Value toJSON(const DocumentHighlight &DH) {
1110 return llvm::json::Object{
1111 {"range", toJSON(DH.range)},
1112 {"kind", static_cast<int>(DH.kind)},
1113 };
1114}
1115
1116llvm::json::Value toJSON(const FileStatus &FStatus) {
1117 return llvm::json::Object{
1118 {"uri", FStatus.uri},
1119 {"state", FStatus.state},
1120 };
1121}
1122
1123constexpr unsigned SemanticTokenEncodingSize = 5;
1124static llvm::json::Value encodeTokens(llvm::ArrayRef<SemanticToken> Toks) {
1125 llvm::json::Array Result;
1126 Result.reserve(SemanticTokenEncodingSize * Toks.size());
1127 for (const auto &Tok : Toks) {
1128 Result.push_back(Tok.deltaLine);
1129 Result.push_back(Tok.deltaStart);
1130 Result.push_back(Tok.length);
1131 Result.push_back(Tok.tokenType);
1132 Result.push_back(Tok.tokenModifiers);
1133 }
1134 assert(Result.size() == SemanticTokenEncodingSize * Toks.size());
1135 return Result;
1136}
1137
1138bool operator==(const SemanticToken &L, const SemanticToken &R) {
1139 return std::tie(L.deltaLine, L.deltaStart, L.length, L.tokenType,
1140 L.tokenModifiers) == std::tie(R.deltaLine, R.deltaStart,
1141 R.length, R.tokenType,
1142 R.tokenModifiers);
1143}
1144
1145llvm::json::Value toJSON(const SemanticTokens &Tokens) {
1146 return llvm::json::Object{{"resultId", Tokens.resultId},
1147 {"data", encodeTokens(Tokens.tokens)}};
1148}
1149
1150llvm::json::Value toJSON(const SemanticTokensEdit &Edit) {
1151 return llvm::json::Object{
1152 {"start", SemanticTokenEncodingSize * Edit.startToken},
1153 {"deleteCount", SemanticTokenEncodingSize * Edit.deleteTokens},
1154 {"data", encodeTokens(Edit.tokens)}};
1155}
1156
1157llvm::json::Value toJSON(const SemanticTokensOrDelta &TE) {
1158 llvm::json::Object Result{{"resultId", TE.resultId}};
1159 if (TE.edits)
1160 Result["edits"] = *TE.edits;
1161 if (TE.tokens)
1162 Result["data"] = encodeTokens(*TE.tokens);
1163 return Result;
1164}
1165
1166bool fromJSON(const llvm::json::Value &Params, SemanticTokensParams &R,
1167 llvm::json::Path P) {
1168 llvm::json::ObjectMapper O(Params, P);
1169 return O && O.map("textDocument", R.textDocument);
1170}
1171
1172bool fromJSON(const llvm::json::Value &Params, SemanticTokensDeltaParams &R,
1173 llvm::json::Path P) {
1174 llvm::json::ObjectMapper O(Params, P);
1175 return O && O.map("textDocument", R.textDocument) &&
1176 O.map("previousResultId", R.previousResultId);
1177}
1178
1179llvm::json::Value toJSON(const InactiveRegionsParams &InactiveRegions) {
1180 return llvm::json::Object{
1181 {"textDocument", InactiveRegions.TextDocument},
1182 {"regions", std::move(InactiveRegions.InactiveRegions)}};
1183}
1184
1185llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1186 const DocumentHighlight &V) {
1187 O << V.range;
1189 O << "(r)";
1191 O << "(w)";
1192 return O;
1193}
1194
1195bool fromJSON(const llvm::json::Value &Params,
1196 DidChangeConfigurationParams &CCP, llvm::json::Path P) {
1197 llvm::json::ObjectMapper O(Params, P);
1198 return O && O.map("settings", CCP.settings);
1199}
1200
1201bool fromJSON(const llvm::json::Value &Params, ClangdCompileCommand &CDbUpdate,
1202 llvm::json::Path P) {
1203 llvm::json::ObjectMapper O(Params, P);
1204 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&
1205 O.map("compilationCommand", CDbUpdate.compilationCommand);
1206}
1207
1208bool fromJSON(const llvm::json::Value &Params, ConfigurationSettings &S,
1209 llvm::json::Path P) {
1210 llvm::json::ObjectMapper O(Params, P);
1211 if (!O)
1212 return true; // 'any' type in LSP.
1213 return mapOptOrNull(Params, "compilationDatabaseChanges",
1215}
1216
1217bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts,
1218 llvm::json::Path P) {
1219 llvm::json::ObjectMapper O(Params, P);
1220 if (!O)
1221 return true; // 'any' type in LSP.
1222
1223 return fromJSON(Params, Opts.ConfigSettings, P) &&
1224 O.map("compilationDatabasePath", Opts.compilationDatabasePath) &&
1225 mapOptOrNull(Params, "fallbackFlags", Opts.fallbackFlags, P) &&
1226 mapOptOrNull(Params, "clangdFileStatus", Opts.FileStatus, P);
1227}
1228
1229bool fromJSON(const llvm::json::Value &E, TypeHierarchyDirection &Out,
1230 llvm::json::Path P) {
1231 auto T = E.getAsInteger();
1232 if (!T)
1233 return false;
1234 if (*T < static_cast<int>(TypeHierarchyDirection::Children) ||
1235 *T > static_cast<int>(TypeHierarchyDirection::Both))
1236 return false;
1237 Out = static_cast<TypeHierarchyDirection>(*T);
1238 return true;
1239}
1240
1241bool fromJSON(const llvm::json::Value &Params, TypeHierarchyPrepareParams &R,
1242 llvm::json::Path P) {
1243 llvm::json::ObjectMapper O(Params, P);
1244 return O && O.map("textDocument", R.textDocument) &&
1245 O.map("position", R.position) &&
1246 mapOptOrNull(Params, "resolve", R.resolve, P) &&
1247 mapOptOrNull(Params, "direction", R.direction, P);
1248}
1249
1250llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1251 const TypeHierarchyItem &I) {
1252 return O << I.name << " - " << toJSON(I);
1253}
1254
1255llvm::json::Value toJSON(const TypeHierarchyItem::ResolveParams &RP) {
1256 llvm::json::Object Result{};
1257 if (RP.parents)
1258 Result["parents"] = RP.parents;
1259 return Result;
1260}
1261bool fromJSON(const llvm::json::Value &Params,
1262 TypeHierarchyItem::ResolveParams &RP, llvm::json::Path P) {
1263 llvm::json::ObjectMapper O(Params, P);
1264 return O && mapOptOrNull(Params, "parents", RP.parents, P);
1265}
1266
1267llvm::json::Value toJSON(const TypeHierarchyItem &I) {
1268 llvm::json::Object Result{
1269 {"name", I.name}, {"kind", static_cast<int>(I.kind)},
1270 {"range", I.range}, {"selectionRange", I.selectionRange},
1271 {"uri", I.uri}, {"data", I.data},
1272 };
1273
1274 if (I.detail)
1275 Result["detail"] = I.detail;
1276 return Result;
1277}
1278
1279bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I,
1280 llvm::json::Path P) {
1281 llvm::json::ObjectMapper O(Params, P);
1282
1283 // Required fields.
1284 return O && O.map("name", I.name) && O.map("kind", I.kind) &&
1285 O.map("uri", I.uri) && O.map("range", I.range) &&
1286 O.map("selectionRange", I.selectionRange) &&
1287 mapOptOrNull(Params, "detail", I.detail, P) &&
1288 mapOptOrNull(Params, "deprecated", I.deprecated, P) &&
1289 mapOptOrNull(Params, "parents", I.parents, P) &&
1290 mapOptOrNull(Params, "children", I.children, P) &&
1291 mapOptOrNull(Params, "data", I.data, P);
1292}
1293
1294bool fromJSON(const llvm::json::Value &Params,
1295 ResolveTypeHierarchyItemParams &R, llvm::json::Path P) {
1296 llvm::json::ObjectMapper O(Params, P);
1297 return O && O.map("item", R.item) &&
1298 mapOptOrNull(Params, "resolve", R.resolve, P) &&
1299 mapOptOrNull(Params, "direction", R.direction, P);
1300}
1301
1302bool fromJSON(const llvm::json::Value &Params, ReferenceContext &R,
1303 llvm::json::Path P) {
1304 llvm::json::ObjectMapper O(Params, P);
1305 return O && O.mapOptional("includeDeclaration", R.includeDeclaration);
1306}
1307
1308bool fromJSON(const llvm::json::Value &Params, ReferenceParams &R,
1309 llvm::json::Path P) {
1311 llvm::json::ObjectMapper O(Params, P);
1312 return fromJSON(Params, Base, P) && O && O.mapOptional("context", R.context);
1313}
1314
1315llvm::json::Value toJSON(SymbolTag Tag) {
1316 return llvm::json::Value{static_cast<int>(Tag)};
1317}
1318
1319llvm::json::Value toJSON(const CallHierarchyItem &I) {
1320 llvm::json::Object Result{{"name", I.name},
1321 {"kind", static_cast<int>(I.kind)},
1322 {"range", I.range},
1323 {"selectionRange", I.selectionRange},
1324 {"uri", I.uri}};
1325 if (!I.tags.empty())
1326 Result["tags"] = I.tags;
1327 if (!I.detail.empty())
1328 Result["detail"] = I.detail;
1329 if (!I.data.empty())
1330 Result["data"] = I.data;
1331 return Result;
1332}
1333
1334bool fromJSON(const llvm::json::Value &Params, CallHierarchyItem &I,
1335 llvm::json::Path P) {
1336 llvm::json::ObjectMapper O(Params, P);
1337
1338 // Populate the required fields only. We don't care about the
1339 // optional fields `Tags` and `Detail` for the purpose of
1340 // client --> server communication.
1341 return O && O.map("name", I.name) && O.map("kind", I.kind) &&
1342 O.map("uri", I.uri) && O.map("range", I.range) &&
1343 O.map("selectionRange", I.selectionRange) &&
1344 mapOptOrNull(Params, "data", I.data, P);
1345}
1346
1347bool fromJSON(const llvm::json::Value &Params,
1348 CallHierarchyIncomingCallsParams &C, llvm::json::Path P) {
1349 llvm::json::ObjectMapper O(Params, P);
1350 return O.map("item", C.item);
1351}
1352
1353llvm::json::Value toJSON(const CallHierarchyIncomingCall &C) {
1354 return llvm::json::Object{{"from", C.from}, {"fromRanges", C.fromRanges}};
1355}
1356
1357bool fromJSON(const llvm::json::Value &Params,
1358 CallHierarchyOutgoingCallsParams &C, llvm::json::Path P) {
1359 llvm::json::ObjectMapper O(Params, P);
1360 return O.map("item", C.item);
1361}
1362
1363llvm::json::Value toJSON(const CallHierarchyOutgoingCall &C) {
1364 return llvm::json::Object{{"to", C.to}, {"fromRanges", C.fromRanges}};
1365}
1366
1367bool fromJSON(const llvm::json::Value &Params, InlayHintsParams &R,
1368 llvm::json::Path P) {
1369 llvm::json::ObjectMapper O(Params, P);
1370 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
1371}
1372
1373llvm::json::Value toJSON(const InlayHintKind &Kind) {
1374 switch (Kind) {
1376 return 1;
1378 return 2;
1379 case InlayHintKind::Designator: // This is an extension, don't serialize.
1380 return nullptr;
1381 }
1382 llvm_unreachable("Unknown clang.clangd.InlayHintKind");
1383}
1384
1385llvm::json::Value toJSON(const InlayHint &H) {
1386 llvm::json::Object Result{{"position", H.position},
1387 {"label", H.label},
1388 {"paddingLeft", H.paddingLeft},
1389 {"paddingRight", H.paddingRight}};
1390 auto K = toJSON(H.kind);
1391 if (!K.getAsNull())
1392 Result["kind"] = std::move(K);
1393 return Result;
1394}
1395bool operator==(const InlayHint &A, const InlayHint &B) {
1396 return std::tie(A.position, A.range, A.kind, A.label) ==
1397 std::tie(B.position, B.range, B.kind, B.label);
1398}
1399bool operator<(const InlayHint &A, const InlayHint &B) {
1400 return std::tie(A.position, A.range, A.kind, A.label) <
1401 std::tie(B.position, B.range, B.kind, B.label);
1402}
1403
1404llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) {
1405 auto ToString = [](InlayHintKind K) {
1406 switch (K) {
1408 return "parameter";
1410 return "type";
1412 return "designator";
1413 }
1414 llvm_unreachable("Unknown clang.clangd.InlayHintKind");
1415 };
1416 return OS << ToString(Kind);
1417}
1418
1419static const char *toString(OffsetEncoding OE) {
1420 switch (OE) {
1422 return "utf-8";
1424 return "utf-16";
1426 return "utf-32";
1428 return "unknown";
1429 }
1430 llvm_unreachable("Unknown clang.clangd.OffsetEncoding");
1431}
1432llvm::json::Value toJSON(const OffsetEncoding &OE) { return toString(OE); }
1433bool fromJSON(const llvm::json::Value &V, OffsetEncoding &OE,
1434 llvm::json::Path P) {
1435 auto Str = V.getAsString();
1436 if (!Str)
1437 return false;
1438 OE = llvm::StringSwitch<OffsetEncoding>(*Str)
1439 .Case("utf-8", OffsetEncoding::UTF8)
1440 .Case("utf-16", OffsetEncoding::UTF16)
1441 .Case("utf-32", OffsetEncoding::UTF32)
1443 return true;
1444}
1445llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OffsetEncoding Enc) {
1446 return OS << toString(Enc);
1447}
1448
1449bool fromJSON(const llvm::json::Value &Params, SelectionRangeParams &S,
1450 llvm::json::Path P) {
1451 llvm::json::ObjectMapper O(Params, P);
1452 return O && O.map("textDocument", S.textDocument) &&
1453 O.map("positions", S.positions);
1454}
1455
1456llvm::json::Value toJSON(const SelectionRange &Out) {
1457 if (Out.parent) {
1458 return llvm::json::Object{{"range", Out.range},
1459 {"parent", toJSON(*Out.parent)}};
1460 }
1461 return llvm::json::Object{{"range", Out.range}};
1462}
1463
1464bool fromJSON(const llvm::json::Value &Params, DocumentLinkParams &R,
1465 llvm::json::Path P) {
1466 llvm::json::ObjectMapper O(Params, P);
1467 return O && O.map("textDocument", R.textDocument);
1468}
1469
1470llvm::json::Value toJSON(const DocumentLink &DocumentLink) {
1471 return llvm::json::Object{
1472 {"range", DocumentLink.range},
1473 {"target", DocumentLink.target},
1474 };
1475}
1476
1477bool fromJSON(const llvm::json::Value &Params, FoldingRangeParams &R,
1478 llvm::json::Path P) {
1479 llvm::json::ObjectMapper O(Params, P);
1480 return O && O.map("textDocument", R.textDocument);
1481}
1482
1483const llvm::StringLiteral FoldingRange::REGION_KIND = "region";
1484const llvm::StringLiteral FoldingRange::COMMENT_KIND = "comment";
1485const llvm::StringLiteral FoldingRange::IMPORT_KIND = "import";
1486
1487llvm::json::Value toJSON(const FoldingRange &Range) {
1488 llvm::json::Object Result{
1489 {"startLine", Range.startLine},
1490 {"endLine", Range.endLine},
1491 };
1492 if (Range.startCharacter)
1493 Result["startCharacter"] = Range.startCharacter;
1494 if (Range.endCharacter)
1495 Result["endCharacter"] = Range.endCharacter;
1496 if (!Range.kind.empty())
1497 Result["kind"] = Range.kind;
1498 return Result;
1499}
1500
1501bool fromJSON(const llvm::json::Value &Params, ASTParams &R,
1502 llvm::json::Path P) {
1503 llvm::json::ObjectMapper O(Params, P);
1504 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
1505}
1506
1507llvm::json::Value toJSON(const ASTNode &N) {
1508 llvm::json::Object Result{
1509 {"role", N.role},
1510 {"kind", N.kind},
1511 };
1512 if (!N.children.empty())
1513 Result["children"] = N.children;
1514 if (!N.detail.empty())
1515 Result["detail"] = N.detail;
1516 if (!N.arcana.empty())
1517 Result["arcana"] = N.arcana;
1518 if (N.range)
1519 Result["range"] = *N.range;
1520 return Result;
1521}
1522
1523llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const ASTNode &Root) {
1524 std::function<void(const ASTNode &, unsigned)> Print = [&](const ASTNode &N,
1525 unsigned Level) {
1526 OS.indent(2 * Level) << N.role << ": " << N.kind;
1527 if (!N.detail.empty())
1528 OS << " - " << N.detail;
1529 OS << "\n";
1530 for (const ASTNode &C : N.children)
1531 Print(C, Level + 1);
1532 };
1533 Print(Root, 0);
1534 return OS;
1535}
1536
1537llvm::json::Value toJSON(const ConfigurationItem &N) {
1538 llvm::json::Object R;
1539 if (N.scopeUri)
1540 R["scopeUri"] = N.scopeUri;
1541 if (N.section)
1542 R["section"] = N.section;
1543 return R;
1544}
1545
1546llvm::json::Value toJSON(const ConfigurationParams &N) {
1547 return llvm::json::Object{{"items", N.items}};
1548}
1549
1550} // 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 &)
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 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.
std::vector< SemanticToken > tokens
The actual tokens.
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.