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
235//===----------------------------------------------------------------------===//
236// Resource Operations (LSP 3.13+)
237//===----------------------------------------------------------------------===//
238
239llvm::json::Value toJSON(const CreateFileOptions &P) {
240 llvm::json::Object Result;
241 if (P.overwrite)
242 Result["overwrite"] = *P.overwrite;
243 if (P.ignoreIfExists)
244 Result["ignoreIfExists"] = *P.ignoreIfExists;
245 return Result;
246}
247
248llvm::json::Value toJSON(const CreateFile &P) {
249 llvm::json::Object Result{
250 {"kind", "create"},
251 {"uri", P.uri},
252 };
253 if (P.options)
254 Result["options"] = *P.options;
255 if (P.annotationId)
256 Result["annotationId"] = *P.annotationId;
257 return Result;
258}
259
260llvm::json::Value toJSON(const RenameFileOptions &P) {
261 llvm::json::Object Result;
262 if (P.overwrite)
263 Result["overwrite"] = *P.overwrite;
264 if (P.ignoreIfExists)
265 Result["ignoreIfExists"] = *P.ignoreIfExists;
266 return Result;
267}
268
269llvm::json::Value toJSON(const RenameFile &P) {
270 llvm::json::Object Result{
271 {"kind", "rename"},
272 {"oldUri", P.oldUri},
273 {"newUri", P.newUri},
274 };
275 if (P.options)
276 Result["options"] = *P.options;
277 if (P.annotationId)
278 Result["annotationId"] = *P.annotationId;
279 return Result;
280}
281
282llvm::json::Value toJSON(const DeleteFileOptions &P) {
283 llvm::json::Object Result;
284 if (P.recursive)
285 Result["recursive"] = *P.recursive;
286 if (P.ignoreIfNotExists)
287 Result["ignoreIfNotExists"] = *P.ignoreIfNotExists;
288 return Result;
289}
290
291llvm::json::Value toJSON(const DeleteFile &P) {
292 llvm::json::Object Result{
293 {"kind", "delete"},
294 {"uri", P.uri},
295 };
296 if (P.options)
297 Result["options"] = *P.options;
298 if (P.annotationId)
299 Result["annotationId"] = *P.annotationId;
300 return Result;
301}
302
303llvm::json::Value toJSON(const DocumentChange &DC) {
304 return std::visit(
305 [](const auto &Change) -> llvm::json::Value { return toJSON(Change); },
306 DC);
307}
308
309bool fromJSON(const llvm::json::Value &Params, DocumentChange &DC,
310 llvm::json::Path P) {
311 // DocumentChange is a variant: TextDocumentEdit | CreateFile | RenameFile |
312 // DeleteFile Resource operations have a "kind" field; TextDocumentEdit does
313 // not.
314 const auto *O = Params.getAsObject();
315 if (!O)
316 return false;
317
318 // Check for "kind" field to distinguish resource operations
319 if (auto Kind = O->getString("kind")) {
320 if (*Kind == "create") {
321 CreateFile CF;
322 if (!fromJSON(Params, CF.uri, P.field("uri")))
323 return false;
324 // Options are optional, parse if present
325 if (const auto *OptsObj = O->getObject("options")) {
327 if (auto Overwrite = OptsObj->getBoolean("overwrite"))
328 CF.options->overwrite = *Overwrite;
329 if (auto IgnoreIfExists = OptsObj->getBoolean("ignoreIfExists"))
330 CF.options->ignoreIfExists = *IgnoreIfExists;
331 }
332 if (auto AnnotationId = O->getString("annotationId"))
333 CF.annotationId = AnnotationId->str();
334 DC = std::move(CF);
335 return true;
336 }
337 if (*Kind == "rename") {
338 RenameFile RF;
339 if (!fromJSON(Params, RF.oldUri, P.field("oldUri")) ||
340 !fromJSON(Params, RF.newUri, P.field("newUri")))
341 return false;
342 if (const auto *OptsObj = O->getObject("options")) {
344 if (auto Overwrite = OptsObj->getBoolean("overwrite"))
345 RF.options->overwrite = *Overwrite;
346 if (auto IgnoreIfExists = OptsObj->getBoolean("ignoreIfExists"))
347 RF.options->ignoreIfExists = *IgnoreIfExists;
348 }
349 if (auto AnnotationId = O->getString("annotationId"))
350 RF.annotationId = AnnotationId->str();
351 DC = std::move(RF);
352 return true;
353 }
354 if (*Kind == "delete") {
355 DeleteFile DF;
356 if (!fromJSON(Params, DF.uri, P.field("uri")))
357 return false;
358 if (const auto *OptsObj = O->getObject("options")) {
360 if (auto Recursive = OptsObj->getBoolean("recursive"))
361 DF.options->recursive = *Recursive;
362 if (auto IgnoreIfNotExists = OptsObj->getBoolean("ignoreIfNotExists"))
363 DF.options->ignoreIfNotExists = *IgnoreIfNotExists;
364 }
365 if (auto AnnotationId = O->getString("annotationId"))
366 DF.annotationId = AnnotationId->str();
367 DC = std::move(DF);
368 return true;
369 }
370 P.report("unknown document change kind");
371 return false;
372 }
373
374 // No "kind" field - must be TextDocumentEdit
376 if (!fromJSON(Params, TDE, P))
377 return false;
378 DC = std::move(TDE);
379 return true;
380}
381
382llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {
383 OS << TE.range << " => \"";
384 llvm::printEscapedString(TE.newText, OS);
385 return OS << '"';
386}
387
388bool fromJSON(const llvm::json::Value &E, TraceLevel &Out, llvm::json::Path P) {
389 if (auto S = E.getAsString()) {
390 if (*S == "off") {
391 Out = TraceLevel::Off;
392 return true;
393 }
394 if (*S == "messages") {
396 return true;
397 }
398 if (*S == "verbose") {
400 return true;
401 }
402 }
403 return false;
404}
405
406bool fromJSON(const llvm::json::Value &E, SymbolKind &Out, llvm::json::Path P) {
407 if (auto T = E.getAsInteger()) {
408 if (*T < static_cast<int>(SymbolKind::File) ||
409 *T > static_cast<int>(SymbolKind::TypeParameter))
410 return false;
411 Out = static_cast<SymbolKind>(*T);
412 return true;
413 }
414 return false;
415}
416
417bool fromJSON(const llvm::json::Value &E, SymbolKindBitset &Out,
418 llvm::json::Path P) {
419 if (auto *A = E.getAsArray()) {
420 for (size_t I = 0; I < A->size(); ++I) {
421 SymbolKind KindOut;
422 if (fromJSON((*A)[I], KindOut, P.index(I)))
423 Out.set(size_t(KindOut));
424 }
425 return true;
426 }
427 return false;
428}
429
431 SymbolKindBitset &SupportedSymbolKinds) {
432 auto KindVal = static_cast<size_t>(Kind);
433 if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() &&
434 SupportedSymbolKinds[KindVal])
435 return Kind;
436
437 switch (Kind) {
438 // Provide some fall backs for common kinds that are close enough.
440 return SymbolKind::Class;
442 return SymbolKind::Enum;
443 default:
444 return SymbolKind::String;
445 }
446}
447
448bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R,
449 llvm::json::Path P) {
450 const llvm::json::Object *O = Params.getAsObject();
451 if (!O) {
452 P.report("expected object");
453 return false;
454 }
455 if (auto *TextDocument = O->getObject("textDocument")) {
456 if (auto *SemanticHighlighting =
457 TextDocument->getObject("semanticHighlightingCapabilities")) {
458 if (auto SemanticHighlightingSupport =
459 SemanticHighlighting->getBoolean("semanticHighlighting"))
460 R.TheiaSemanticHighlighting = *SemanticHighlightingSupport;
461 }
462 if (auto *InactiveRegions =
463 TextDocument->getObject("inactiveRegionsCapabilities")) {
464 if (auto InactiveRegionsSupport =
465 InactiveRegions->getBoolean("inactiveRegions")) {
466 R.InactiveRegions = *InactiveRegionsSupport;
467 }
468 }
469 if (TextDocument->getObject("semanticTokens"))
470 R.SemanticTokens = true;
471 if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) {
472 if (auto CategorySupport = Diagnostics->getBoolean("categorySupport"))
473 R.DiagnosticCategory = *CategorySupport;
474 if (auto CodeActions = Diagnostics->getBoolean("codeActionsInline"))
475 R.DiagnosticFixes = *CodeActions;
476 if (auto RelatedInfo = Diagnostics->getBoolean("relatedInformation"))
477 R.DiagnosticRelatedInformation = *RelatedInfo;
478 }
479 if (auto *References = TextDocument->getObject("references"))
480 if (auto ContainerSupport = References->getBoolean("container"))
481 R.ReferenceContainer = *ContainerSupport;
482 if (auto *Completion = TextDocument->getObject("completion")) {
483 if (auto *Item = Completion->getObject("completionItem")) {
484 if (auto SnippetSupport = Item->getBoolean("snippetSupport"))
485 R.CompletionSnippets = *SnippetSupport;
486 if (const auto *DocumentationFormat =
487 Item->getArray("documentationFormat")) {
488 for (const auto &Format : *DocumentationFormat) {
489 if (fromJSON(Format, R.CompletionDocumentationFormat, P))
490 break;
491 }
492 }
493 }
494 if (auto *ItemKind = Completion->getObject("completionItemKind")) {
495 if (auto *ValueSet = ItemKind->get("valueSet")) {
496 R.CompletionItemKinds.emplace();
497 if (!fromJSON(*ValueSet, *R.CompletionItemKinds,
498 P.field("textDocument")
499 .field("completion")
500 .field("completionItemKind")
501 .field("valueSet")))
502 return false;
503 }
504 }
505 if (auto EditsNearCursor = Completion->getBoolean("editsNearCursor"))
506 R.CompletionFixes = *EditsNearCursor;
507 }
508 if (auto *CodeAction = TextDocument->getObject("codeAction")) {
509 if (CodeAction->getObject("codeActionLiteralSupport"))
510 R.CodeActionStructure = true;
511 }
512 if (auto *DocumentSymbol = TextDocument->getObject("documentSymbol")) {
513 if (auto HierarchicalSupport =
514 DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
515 R.HierarchicalDocumentSymbol = *HierarchicalSupport;
516 }
517 if (auto *Hover = TextDocument->getObject("hover")) {
518 if (auto *ContentFormat = Hover->getArray("contentFormat")) {
519 for (const auto &Format : *ContentFormat) {
520 if (fromJSON(Format, R.HoverContentFormat, P))
521 break;
522 }
523 }
524 }
525 if (auto *Help = TextDocument->getObject("signatureHelp")) {
526 R.HasSignatureHelp = true;
527 if (auto *Info = Help->getObject("signatureInformation")) {
528 if (auto *Parameter = Info->getObject("parameterInformation")) {
529 if (auto OffsetSupport = Parameter->getBoolean("labelOffsetSupport"))
530 R.OffsetsInSignatureHelp = *OffsetSupport;
531 }
532 if (const auto *DocumentationFormat =
533 Info->getArray("documentationFormat")) {
534 for (const auto &Format : *DocumentationFormat) {
536 break;
537 }
538 }
539 }
540 }
541 if (auto *Folding = TextDocument->getObject("foldingRange")) {
542 if (auto LineFolding = Folding->getBoolean("lineFoldingOnly"))
543 R.LineFoldingOnly = *LineFolding;
544 }
545 if (auto *Rename = TextDocument->getObject("rename")) {
546 if (auto RenameSupport = Rename->getBoolean("prepareSupport"))
547 R.RenamePrepareSupport = *RenameSupport;
548 }
549 }
550 if (auto *Workspace = O->getObject("workspace")) {
551 if (auto *Symbol = Workspace->getObject("symbol")) {
552 if (auto *SymbolKind = Symbol->getObject("symbolKind")) {
553 if (auto *ValueSet = SymbolKind->get("valueSet")) {
554 R.WorkspaceSymbolKinds.emplace();
555 if (!fromJSON(*ValueSet, *R.WorkspaceSymbolKinds,
556 P.field("workspace")
557 .field("symbol")
558 .field("symbolKind")
559 .field("valueSet")))
560 return false;
561 }
562 }
563 }
564
565 if (auto WorkspaceConfiguration = Workspace->getBoolean("configuration")) {
566 R.WorkspaceConfiguration = *WorkspaceConfiguration;
567 }
568
569 if (auto *SemanticTokens = Workspace->getObject("semanticTokens")) {
570 if (auto RefreshSupport = SemanticTokens->getBoolean("refreshSupport"))
571 R.SemanticTokenRefreshSupport = *RefreshSupport;
572 }
573 if (auto *WorkspaceEdit = Workspace->getObject("workspaceEdit")) {
574 if (auto DocumentChanges = WorkspaceEdit->getBoolean("documentChanges"))
575 R.DocumentChanges = *DocumentChanges;
576 if (WorkspaceEdit->getObject("changeAnnotationSupport")) {
577 R.ChangeAnnotation = true;
578 }
579 }
580 }
581 if (auto *Window = O->getObject("window")) {
582 if (auto WorkDoneProgress = Window->getBoolean("workDoneProgress"))
583 R.WorkDoneProgress = *WorkDoneProgress;
584 if (auto Implicit = Window->getBoolean("implicitWorkDoneProgressCreate"))
585 R.ImplicitProgressCreation = *Implicit;
586 }
587 if (auto *General = O->getObject("general")) {
588 if (auto *StaleRequestSupport = General->getObject("staleRequestSupport")) {
589 if (auto Cancel = StaleRequestSupport->getBoolean("cancel"))
590 R.CancelsStaleRequests = *Cancel;
591 }
592 }
593 if (auto *OffsetEncoding = O->get("offsetEncoding")) {
594 R.offsetEncoding.emplace();
596 P.field("offsetEncoding")))
597 return false;
598 }
599 return true;
600}
601
602bool fromJSON(const llvm::json::Value &Params, InitializeParams &R,
603 llvm::json::Path P) {
604 llvm::json::ObjectMapper O(Params, P);
605 if (!O)
606 return false;
607 // We deliberately don't fail if we can't parse individual fields.
608 // Failing to handle a slightly malformed initialize would be a disaster.
609 O.map("processId", R.processId);
610 O.map("rootUri", R.rootUri);
611 O.map("rootPath", R.rootPath);
612 O.map("capabilities", R.capabilities);
613 if (auto *RawCaps = Params.getAsObject()->getObject("capabilities"))
614 R.rawCapabilities = *RawCaps;
615 O.map("trace", R.trace);
616 O.map("initializationOptions", R.initializationOptions);
617 return true;
618}
619
620llvm::json::Value toJSON(const WorkDoneProgressCreateParams &P) {
621 return llvm::json::Object{{"token", P.token}};
622}
623
624llvm::json::Value toJSON(const WorkDoneProgressBegin &P) {
625 llvm::json::Object Result{
626 {"kind", "begin"},
627 {"title", P.title},
628 };
629 if (P.cancellable)
630 Result["cancellable"] = true;
631 if (P.percentage)
632 Result["percentage"] = 0;
633
634 // FIXME: workaround for older gcc/clang
635 return Result;
636}
637
638llvm::json::Value toJSON(const WorkDoneProgressReport &P) {
639 llvm::json::Object Result{{"kind", "report"}};
640 if (P.cancellable)
641 Result["cancellable"] = *P.cancellable;
642 if (P.message)
643 Result["message"] = *P.message;
644 if (P.percentage)
645 Result["percentage"] = *P.percentage;
646 // FIXME: workaround for older gcc/clang
647 return Result;
648}
649
650llvm::json::Value toJSON(const WorkDoneProgressEnd &P) {
651 llvm::json::Object Result{{"kind", "end"}};
652 if (P.message)
653 Result["message"] = *P.message;
654 // FIXME: workaround for older gcc/clang
655 return Result;
656}
657
658llvm::json::Value toJSON(const MessageType &R) {
659 return static_cast<int64_t>(R);
660}
661
662llvm::json::Value toJSON(const ShowMessageParams &R) {
663 return llvm::json::Object{{"type", R.type}, {"message", R.message}};
664}
665
666bool fromJSON(const llvm::json::Value &Params, DidOpenTextDocumentParams &R,
667 llvm::json::Path P) {
668 llvm::json::ObjectMapper O(Params, P);
669 return O && O.map("textDocument", R.textDocument);
670}
671
672bool fromJSON(const llvm::json::Value &Params, DidCloseTextDocumentParams &R,
673 llvm::json::Path P) {
674 llvm::json::ObjectMapper O(Params, P);
675 return O && O.map("textDocument", R.textDocument);
676}
677
678bool fromJSON(const llvm::json::Value &Params, DidSaveTextDocumentParams &R,
679 llvm::json::Path P) {
680 llvm::json::ObjectMapper O(Params, P);
681 return O && O.map("textDocument", R.textDocument);
682}
683
684bool fromJSON(const llvm::json::Value &Params, DidChangeTextDocumentParams &R,
685 llvm::json::Path P) {
686 llvm::json::ObjectMapper O(Params, P);
687 return O && O.map("textDocument", R.textDocument) &&
688 O.map("contentChanges", R.contentChanges) &&
689 O.map("wantDiagnostics", R.wantDiagnostics) &&
690 mapOptOrNull(Params, "forceRebuild", R.forceRebuild, P);
691}
692
693bool fromJSON(const llvm::json::Value &E, FileChangeType &Out,
694 llvm::json::Path P) {
695 if (auto T = E.getAsInteger()) {
696 if (*T < static_cast<int>(FileChangeType::Created) ||
697 *T > static_cast<int>(FileChangeType::Deleted))
698 return false;
699 Out = static_cast<FileChangeType>(*T);
700 return true;
701 }
702 return false;
703}
704
705bool fromJSON(const llvm::json::Value &Params, FileEvent &R,
706 llvm::json::Path P) {
707 llvm::json::ObjectMapper O(Params, P);
708 return O && O.map("uri", R.uri) && O.map("type", R.type);
709}
710
711bool fromJSON(const llvm::json::Value &Params, DidChangeWatchedFilesParams &R,
712 llvm::json::Path P) {
713 llvm::json::ObjectMapper O(Params, P);
714 return O && O.map("changes", R.changes);
715}
716
717bool fromJSON(const llvm::json::Value &Params,
718 TextDocumentContentChangeEvent &R, llvm::json::Path P) {
719 llvm::json::ObjectMapper O(Params, P);
720 return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
721 O.map("text", R.text);
722}
723
724bool fromJSON(const llvm::json::Value &Params, DocumentRangeFormattingParams &R,
725 llvm::json::Path P) {
726 llvm::json::ObjectMapper O(Params, P);
727 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
728}
729
730bool fromJSON(const llvm::json::Value &Params,
731 DocumentOnTypeFormattingParams &R, llvm::json::Path P) {
732 llvm::json::ObjectMapper O(Params, P);
733 return O && O.map("textDocument", R.textDocument) &&
734 O.map("position", R.position) && O.map("ch", R.ch);
735}
736
737bool fromJSON(const llvm::json::Value &Params, DocumentFormattingParams &R,
738 llvm::json::Path P) {
739 llvm::json::ObjectMapper O(Params, P);
740 return O && O.map("textDocument", R.textDocument);
741}
742
743bool fromJSON(const llvm::json::Value &Params, DocumentSymbolParams &R,
744 llvm::json::Path P) {
745 llvm::json::ObjectMapper O(Params, P);
746 return O && O.map("textDocument", R.textDocument);
747}
748
749llvm::json::Value toJSON(const DiagnosticRelatedInformation &DRI) {
750 return llvm::json::Object{
751 {"location", DRI.location},
752 {"message", DRI.message},
753 };
754}
755
756llvm::json::Value toJSON(DiagnosticTag Tag) { return static_cast<int>(Tag); }
757
758llvm::json::Value toJSON(const CodeDescription &D) {
759 return llvm::json::Object{{"href", D.href}};
760}
761
762llvm::json::Value toJSON(const Diagnostic &D) {
763 llvm::json::Object Diag{
764 {"range", D.range},
765 {"severity", D.severity},
766 {"message", D.message},
767 };
768 if (D.category)
769 Diag["category"] = *D.category;
770 if (D.codeActions)
771 Diag["codeActions"] = D.codeActions;
772 if (!D.code.empty())
773 Diag["code"] = D.code;
774 if (D.codeDescription)
775 Diag["codeDescription"] = *D.codeDescription;
776 if (!D.source.empty())
777 Diag["source"] = D.source;
778 if (D.relatedInformation)
779 Diag["relatedInformation"] = *D.relatedInformation;
780 if (!D.data.empty())
781 Diag["data"] = llvm::json::Object(D.data);
782 if (!D.tags.empty())
783 Diag["tags"] = llvm::json::Array{D.tags};
784 // FIXME: workaround for older gcc/clang
785 return Diag;
786}
787
788bool fromJSON(const llvm::json::Value &Params, Diagnostic &R,
789 llvm::json::Path P) {
790 llvm::json::ObjectMapper O(Params, P);
791 if (!O)
792 return false;
793 if (auto *Data = Params.getAsObject()->getObject("data"))
794 R.data = *Data;
795 return O.map("range", R.range) && O.map("message", R.message) &&
796 mapOptOrNull(Params, "severity", R.severity, P) &&
797 mapOptOrNull(Params, "category", R.category, P) &&
798 mapOptOrNull(Params, "code", R.code, P) &&
799 mapOptOrNull(Params, "source", R.source, P);
800}
801
802llvm::json::Value toJSON(const PublishDiagnosticsParams &PDP) {
803 llvm::json::Object Result{
804 {"uri", PDP.uri},
805 {"diagnostics", PDP.diagnostics},
806 };
807 if (PDP.version)
808 Result["version"] = PDP.version;
809 return Result;
810}
811
812bool fromJSON(const llvm::json::Value &Params, CodeActionContext &R,
813 llvm::json::Path P) {
814 llvm::json::ObjectMapper O(Params, P);
815 if (!O || !O.map("diagnostics", R.diagnostics))
816 return false;
817 O.map("only", R.only);
818 return true;
819}
820
821llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
822 OS << D.range << " [";
823 switch (D.severity) {
824 case 1:
825 OS << "error";
826 break;
827 case 2:
828 OS << "warning";
829 break;
830 case 3:
831 OS << "note";
832 break;
833 case 4:
834 OS << "remark";
835 break;
836 default:
837 OS << "diagnostic";
838 break;
839 }
840 return OS << '(' << D.severity << "): " << D.message << "]";
841}
842
843bool fromJSON(const llvm::json::Value &Params, CodeActionParams &R,
844 llvm::json::Path P) {
845 llvm::json::ObjectMapper O(Params, P);
846 return O && O.map("textDocument", R.textDocument) &&
847 O.map("range", R.range) && O.map("context", R.context);
848}
849
850bool fromJSON(const llvm::json::Value &Params, WorkspaceEdit &R,
851 llvm::json::Path P) {
852 llvm::json::ObjectMapper O(Params, P);
853 return O && O.map("changes", R.changes) &&
854 O.map("documentChanges", R.documentChanges) &&
855 O.mapOptional("changeAnnotations", R.changeAnnotations);
856}
857
858bool fromJSON(const llvm::json::Value &Params, ExecuteCommandParams &R,
859 llvm::json::Path P) {
860 llvm::json::ObjectMapper O(Params, P);
861 if (!O || !O.map("command", R.command))
862 return false;
863
864 const auto *Args = Params.getAsObject()->get("arguments");
865 if (!Args)
866 return true; // Missing args is ok, argument is null.
867 const auto *ArgsArray = Args->getAsArray();
868 if (!ArgsArray) {
869 P.field("arguments").report("expected array");
870 return false;
871 }
872 if (ArgsArray->size() > 1) {
873 P.field("arguments").report("Command should have 0 or 1 argument");
874 return false;
875 }
876 if (ArgsArray->size() == 1) {
877 R.argument = ArgsArray->front();
878 }
879 return true;
880}
881
882llvm::json::Value toJSON(const SymbolInformation &P) {
883 llvm::json::Object O{
884 {"name", P.name},
885 {"kind", static_cast<int>(P.kind)},
886 {"location", P.location},
887 {"containerName", P.containerName},
888 };
889 if (P.score)
890 O["score"] = *P.score;
891 return O;
892}
893
894llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
895 const SymbolInformation &SI) {
896 O << SI.containerName << "::" << SI.name << " - " << toJSON(SI);
897 return O;
898}
899
900bool fromJSON(const llvm::json::Value &Params, WorkspaceSymbolParams &R,
901 llvm::json::Path P) {
902 llvm::json::ObjectMapper O(Params, P);
903 return O && O.map("query", R.query) &&
904 mapOptOrNull(Params, "limit", R.limit, P);
905}
906
907llvm::json::Value toJSON(const Command &C) {
908 auto Cmd = llvm::json::Object{{"title", C.title}, {"command", C.command}};
909 if (!C.argument.getAsNull())
910 Cmd["arguments"] = llvm::json::Array{C.argument};
911 return Cmd;
912}
913
914const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";
915const llvm::StringLiteral CodeAction::REFACTOR_KIND = "refactor";
916const llvm::StringLiteral CodeAction::REFACTOR_REWRITE_KIND =
917 "refactor.rewrite";
918const llvm::StringLiteral CodeAction::INFO_KIND = "info";
919
920llvm::json::Value toJSON(const CodeAction &CA) {
921 auto CodeAction = llvm::json::Object{{"title", CA.title}};
922 if (CA.kind)
923 CodeAction["kind"] = *CA.kind;
924 if (CA.diagnostics)
925 CodeAction["diagnostics"] = llvm::json::Array(*CA.diagnostics);
926 if (CA.isPreferred)
927 CodeAction["isPreferred"] = true;
928 if (CA.edit)
929 CodeAction["edit"] = *CA.edit;
930 if (CA.command)
931 CodeAction["command"] = *CA.command;
932 if (CA.data)
933 CodeAction["data"] = *CA.data;
934 return CodeAction;
935}
936
937bool fromJSON(const llvm::json::Value &Params, CodeAction &CA,
938 llvm::json::Path P) {
939 llvm::json::ObjectMapper O(Params, P);
940 if (!O || !O.map("title", CA.title))
941 return false;
942 O.map("kind", CA.kind);
943 O.map("diagnostics", CA.diagnostics);
944 O.map("isPreferred", CA.isPreferred);
945 O.map("edit", CA.edit);
946 O.map("command", CA.command);
947 // Handle data field - it's an arbitrary JSON value
948 if (const auto *Obj = Params.getAsObject()) {
949 if (const auto *Data = Obj->get("data"))
950 CA.data = *Data;
951 }
952 return true;
953}
954
955llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S) {
956 return O << S.name << " - " << toJSON(S);
957}
958
959llvm::json::Value toJSON(const DocumentSymbol &S) {
960 llvm::json::Object Result{{"name", S.name},
961 {"kind", static_cast<int>(S.kind)},
962 {"range", S.range},
963 {"selectionRange", S.selectionRange}};
964
965 if (!S.detail.empty())
966 Result["detail"] = S.detail;
967 if (!S.children.empty())
968 Result["children"] = S.children;
969 if (S.deprecated)
970 Result["deprecated"] = true;
971 // FIXME: workaround for older gcc/clang
972 return Result;
973}
974
975llvm::json::Value toJSON(const WorkspaceEdit &WE) {
976 llvm::json::Object Result;
977 if (WE.changes) {
978 llvm::json::Object FileChanges;
979 for (auto &Change : *WE.changes)
980 FileChanges[Change.first] = llvm::json::Array(Change.second);
981 Result["changes"] = std::move(FileChanges);
982 }
983 if (WE.documentChanges)
984 Result["documentChanges"] = *WE.documentChanges;
985 if (!WE.changeAnnotations.empty()) {
986 llvm::json::Object ChangeAnnotations;
987 for (auto &Annotation : WE.changeAnnotations)
988 ChangeAnnotations[Annotation.first] = Annotation.second;
989 Result["changeAnnotations"] = std::move(ChangeAnnotations);
990 }
991 return Result;
992}
993
994bool fromJSON(const llvm::json::Value &Params, TweakArgs &A,
995 llvm::json::Path P) {
996 llvm::json::ObjectMapper O(Params, P);
997 return O && O.map("file", A.file) && O.map("selection", A.selection) &&
998 O.map("tweakID", A.tweakID);
999}
1000
1001llvm::json::Value toJSON(const TweakArgs &A) {
1002 return llvm::json::Object{
1003 {"tweakID", A.tweakID}, {"selection", A.selection}, {"file", A.file}};
1004}
1005
1006llvm::json::Value toJSON(const ApplyWorkspaceEditParams &Params) {
1007 return llvm::json::Object{{"edit", Params.edit}};
1008}
1009
1010bool fromJSON(const llvm::json::Value &Response, ApplyWorkspaceEditResponse &R,
1011 llvm::json::Path P) {
1012 llvm::json::ObjectMapper O(Response, P);
1013 return O && O.map("applied", R.applied) &&
1014 O.map("failureReason", R.failureReason);
1015}
1016
1017llvm::json::Value toJSON(const ShowDocumentParams &Params) {
1018 llvm::json::Object Result;
1019 // Use externalUri if set (for https:// etc), otherwise use uri (for file://)
1020 if (Params.externalUri)
1021 Result["uri"] = *Params.externalUri;
1022 else
1023 Result["uri"] = Params.uri;
1024 if (Params.external)
1025 Result["external"] = *Params.external;
1026 if (Params.takeFocus)
1027 Result["takeFocus"] = *Params.takeFocus;
1028 if (Params.selection)
1029 Result["selection"] = *Params.selection;
1030 return Result;
1031}
1032
1033bool fromJSON(const llvm::json::Value &Response, ShowDocumentResult &R,
1034 llvm::json::Path P) {
1035 llvm::json::ObjectMapper O(Response, P);
1036 return O && O.map("success", R.success);
1037}
1038
1039bool fromJSON(const llvm::json::Value &Params, TextDocumentPositionParams &R,
1040 llvm::json::Path P) {
1041 llvm::json::ObjectMapper O(Params, P);
1042 return O && O.map("textDocument", R.textDocument) &&
1043 O.map("position", R.position);
1044}
1045
1046bool fromJSON(const llvm::json::Value &Params, CompletionContext &R,
1047 llvm::json::Path P) {
1048 llvm::json::ObjectMapper O(Params, P);
1049 int TriggerKind;
1050 if (!O || !O.map("triggerKind", TriggerKind) ||
1051 !mapOptOrNull(Params, "triggerCharacter", R.triggerCharacter, P))
1052 return false;
1053 R.triggerKind = static_cast<CompletionTriggerKind>(TriggerKind);
1054 return true;
1055}
1056
1057bool fromJSON(const llvm::json::Value &Params, CompletionParams &R,
1058 llvm::json::Path P) {
1059 if (!fromJSON(Params, static_cast<TextDocumentPositionParams &>(R), P) ||
1060 !mapOptOrNull(Params, "limit", R.limit, P))
1061 return false;
1062 if (auto *Context = Params.getAsObject()->get("context"))
1063 return fromJSON(*Context, R.context, P.field("context"));
1064 return true;
1065}
1066
1067static llvm::StringRef toTextKind(MarkupKind Kind) {
1068 switch (Kind) {
1070 return "plaintext";
1072 return "markdown";
1073 }
1074 llvm_unreachable("Invalid MarkupKind");
1075}
1076
1077static MarkupKind fromTextKind(llvm::StringRef Kind) {
1078 if (Kind == "plaintext")
1079 return MarkupKind::PlainText;
1080 if (Kind == "markdown")
1081 return MarkupKind::Markdown;
1082 llvm_unreachable("Invalid MarkupKind");
1083}
1084
1085bool fromJSON(const llvm::json::Value &V, MarkupKind &K, llvm::json::Path P) {
1086 auto Str = V.getAsString();
1087 if (!Str) {
1088 P.report("expected string");
1089 return false;
1090 }
1091 if (*Str == "plaintext")
1093 else if (*Str == "markdown")
1095 else {
1096 P.report("unknown markup kind");
1097 return false;
1098 }
1099 return true;
1100}
1101
1102llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) {
1103 return OS << toTextKind(K);
1104}
1105
1106llvm::json::Value toJSON(const MarkupContent &MC) {
1107 if (MC.value.empty())
1108 return nullptr;
1109
1110 return llvm::json::Object{
1111 {"kind", toTextKind(MC.kind)},
1112 {"value", MC.value},
1113 };
1114}
1115
1116bool fromJSON(const llvm::json::Value &Params, MarkupContent &R,
1117 llvm::json::Path P) {
1118 llvm::json::ObjectMapper O(Params, P);
1119 std::string MarkupKind;
1120 O.map("kind", MarkupKind);
1121 R.kind = fromTextKind(MarkupKind);
1122 return O.mapOptional("value", R.value);
1123}
1124
1125llvm::json::Value toJSON(const Hover &H) {
1126 llvm::json::Object Result{{"contents", toJSON(H.contents)}};
1127
1128 if (H.range)
1129 Result["range"] = toJSON(*H.range);
1130
1131 return Result;
1132}
1133
1134bool fromJSON(const llvm::json::Value &E, CompletionItemKind &Out,
1135 llvm::json::Path P) {
1136 if (auto T = E.getAsInteger()) {
1137 if (*T < static_cast<int>(CompletionItemKind::Text) ||
1138 *T > static_cast<int>(CompletionItemKind::TypeParameter))
1139 return false;
1140 Out = static_cast<CompletionItemKind>(*T);
1141 return true;
1142 }
1143 return false;
1144}
1145
1148 CompletionItemKindBitset &SupportedCompletionItemKinds) {
1149 auto KindVal = static_cast<size_t>(Kind);
1150 if (KindVal >= CompletionItemKindMin &&
1151 KindVal <= SupportedCompletionItemKinds.size() &&
1152 SupportedCompletionItemKinds[KindVal])
1153 return Kind;
1154
1155 switch (Kind) {
1156 // Provide some fall backs for common kinds that are close enough.
1163 default:
1165 }
1166}
1167
1168bool fromJSON(const llvm::json::Value &E, CompletionItemKindBitset &Out,
1169 llvm::json::Path P) {
1170 if (auto *A = E.getAsArray()) {
1171 for (size_t I = 0; I < A->size(); ++I) {
1172 CompletionItemKind KindOut;
1173 if (fromJSON((*A)[I], KindOut, P.index(I)))
1174 Out.set(size_t(KindOut));
1175 }
1176 return true;
1177 }
1178 return false;
1179}
1180
1181llvm::json::Value toJSON(const CompletionItem &CI) {
1182 assert(!CI.label.empty() && "completion item label is required");
1183 llvm::json::Object Result{{"label", CI.label}};
1185 Result["kind"] = static_cast<int>(CI.kind);
1186 if (!CI.detail.empty())
1187 Result["detail"] = CI.detail;
1188 if (CI.documentation)
1189 Result["documentation"] = CI.documentation;
1190 if (!CI.sortText.empty())
1191 Result["sortText"] = CI.sortText;
1192 if (!CI.filterText.empty())
1193 Result["filterText"] = CI.filterText;
1194 if (!CI.insertText.empty())
1195 Result["insertText"] = CI.insertText;
1197 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
1198 if (CI.textEdit)
1199 Result["textEdit"] = *CI.textEdit;
1200 if (!CI.additionalTextEdits.empty())
1201 Result["additionalTextEdits"] = llvm::json::Array(CI.additionalTextEdits);
1202 if (CI.deprecated)
1203 Result["deprecated"] = CI.deprecated;
1204 Result["score"] = CI.score;
1205 Result["data"] = CI.data;
1206 return Result;
1207}
1208
1209bool fromJSON(const llvm::json::Value &Params, CompletionItem &R,
1210 llvm::json::Path P) {
1211 llvm::json::ObjectMapper O(Params, P);
1212 int Kind;
1213 if (!O.mapOptional("kind", Kind))
1214 return false;
1215 R.kind = static_cast<CompletionItemKind>(Kind);
1216
1217 if (!O.mapOptional("insertTextFormat", Kind))
1218 return false;
1219 R.insertTextFormat = static_cast<InsertTextFormat>(Kind);
1220 return O //
1221 && O.map("label", R.label) //
1222 && O.mapOptional("detail", R.detail) //
1223 && O.mapOptional("documentation", R.documentation) //
1224 && O.mapOptional("sortText", R.sortText) //
1225 && O.mapOptional("filterText", R.filterText) //
1226 && O.mapOptional("insertText", R.insertText) //
1227 && O.mapOptional("textEdit", R.textEdit) //
1228 && O.mapOptional("additionalTextEdits", R.additionalTextEdits) //
1229 && O.mapOptional("data", R.data) //
1230 ;
1231}
1232
1233llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) {
1234 O << I.label << " - " << toJSON(I);
1235 return O;
1236}
1237
1238bool operator<(const CompletionItem &L, const CompletionItem &R) {
1239 return (L.sortText.empty() ? L.label : L.sortText) <
1240 (R.sortText.empty() ? R.label : R.sortText);
1241}
1242
1243llvm::json::Value toJSON(const CompletionList &L) {
1244 return llvm::json::Object{
1245 {"isIncomplete", L.isIncomplete},
1246 {"items", llvm::json::Array(L.items)},
1247 };
1248}
1249
1250llvm::json::Value toJSON(const ParameterInformation &PI) {
1251 assert((PI.labelOffsets || !PI.labelString.empty()) &&
1252 "parameter information label is required");
1253 llvm::json::Object Result;
1254 if (PI.labelOffsets)
1255 Result["label"] =
1256 llvm::json::Array({PI.labelOffsets->first, PI.labelOffsets->second});
1257 else
1258 Result["label"] = PI.labelString;
1259 if (!PI.documentation.empty())
1260 Result["documentation"] = PI.documentation;
1261 return Result;
1262}
1263
1264llvm::json::Value toJSON(const SignatureInformation &SI) {
1265 assert(!SI.label.empty() && "signature information label is required");
1266 llvm::json::Object Result{
1267 {"label", SI.label},
1268 {"parameters", llvm::json::Array(SI.parameters)},
1269 };
1270 if (!SI.documentation.value.empty())
1271 Result["documentation"] = SI.documentation;
1272 return Result;
1273}
1274
1275llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1276 const SignatureInformation &I) {
1277 O << I.label << " - " << toJSON(I);
1278 return O;
1279}
1280
1281llvm::json::Value toJSON(const SignatureHelp &SH) {
1282 assert(SH.activeSignature >= 0 &&
1283 "Unexpected negative value for number of active signatures.");
1284 assert(SH.activeParameter >= 0 &&
1285 "Unexpected negative value for active parameter index");
1286 return llvm::json::Object{
1287 {"activeSignature", SH.activeSignature},
1288 {"activeParameter", SH.activeParameter},
1289 {"signatures", llvm::json::Array(SH.signatures)},
1290 };
1291}
1292
1293bool fromJSON(const llvm::json::Value &Params, RenameParams &R,
1294 llvm::json::Path P) {
1295 llvm::json::ObjectMapper O(Params, P);
1296 return O && O.map("textDocument", R.textDocument) &&
1297 O.map("position", R.position) && O.map("newName", R.newName);
1298}
1299
1300llvm::json::Value toJSON(const DocumentHighlight &DH) {
1301 return llvm::json::Object{
1302 {"range", toJSON(DH.range)},
1303 {"kind", static_cast<int>(DH.kind)},
1304 };
1305}
1306
1307llvm::json::Value toJSON(const FileStatus &FStatus) {
1308 return llvm::json::Object{
1309 {"uri", FStatus.uri},
1310 {"state", FStatus.state},
1311 };
1312}
1313
1314constexpr unsigned SemanticTokenEncodingSize = 5;
1315static llvm::json::Value encodeTokens(llvm::ArrayRef<SemanticToken> Toks) {
1316 llvm::json::Array Result;
1317 Result.reserve(SemanticTokenEncodingSize * Toks.size());
1318 for (const auto &Tok : Toks) {
1319 Result.push_back(Tok.deltaLine);
1320 Result.push_back(Tok.deltaStart);
1321 Result.push_back(Tok.length);
1322 Result.push_back(Tok.tokenType);
1323 Result.push_back(Tok.tokenModifiers);
1324 }
1325 assert(Result.size() == SemanticTokenEncodingSize * Toks.size());
1326 return Result;
1327}
1328
1329bool operator==(const SemanticToken &L, const SemanticToken &R) {
1330 return std::tie(L.deltaLine, L.deltaStart, L.length, L.tokenType,
1331 L.tokenModifiers) == std::tie(R.deltaLine, R.deltaStart,
1332 R.length, R.tokenType,
1333 R.tokenModifiers);
1334}
1335
1336llvm::json::Value toJSON(const SemanticTokens &Tokens) {
1337 return llvm::json::Object{{"resultId", Tokens.resultId},
1338 {"data", encodeTokens(Tokens.tokens)}};
1339}
1340
1341llvm::json::Value toJSON(const SemanticTokensEdit &Edit) {
1342 return llvm::json::Object{
1343 {"start", SemanticTokenEncodingSize * Edit.startToken},
1344 {"deleteCount", SemanticTokenEncodingSize * Edit.deleteTokens},
1345 {"data", encodeTokens(Edit.tokens)}};
1346}
1347
1348llvm::json::Value toJSON(const SemanticTokensOrDelta &TE) {
1349 llvm::json::Object Result{{"resultId", TE.resultId}};
1350 if (TE.edits)
1351 Result["edits"] = *TE.edits;
1352 if (TE.tokens)
1353 Result["data"] = encodeTokens(*TE.tokens);
1354 return Result;
1355}
1356
1357bool fromJSON(const llvm::json::Value &Params, SemanticTokensParams &R,
1358 llvm::json::Path P) {
1359 llvm::json::ObjectMapper O(Params, P);
1360 return O && O.map("textDocument", R.textDocument);
1361}
1362
1363bool fromJSON(const llvm::json::Value &Params, SemanticTokensDeltaParams &R,
1364 llvm::json::Path P) {
1365 llvm::json::ObjectMapper O(Params, P);
1366 return O && O.map("textDocument", R.textDocument) &&
1367 O.map("previousResultId", R.previousResultId);
1368}
1369
1370llvm::json::Value toJSON(const InactiveRegionsParams &InactiveRegions) {
1371 return llvm::json::Object{
1372 {"textDocument", InactiveRegions.TextDocument},
1373 {"regions", std::move(InactiveRegions.InactiveRegions)}};
1374}
1375
1376llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1377 const DocumentHighlight &V) {
1378 O << V.range;
1380 O << "(r)";
1382 O << "(w)";
1383 return O;
1384}
1385
1386bool fromJSON(const llvm::json::Value &Params,
1387 DidChangeConfigurationParams &CCP, llvm::json::Path P) {
1388 llvm::json::ObjectMapper O(Params, P);
1389 return O && O.map("settings", CCP.settings);
1390}
1391
1392bool fromJSON(const llvm::json::Value &Params, ClangdCompileCommand &CDbUpdate,
1393 llvm::json::Path P) {
1394 llvm::json::ObjectMapper O(Params, P);
1395 return O && O.map("workingDirectory", CDbUpdate.workingDirectory) &&
1396 O.map("compilationCommand", CDbUpdate.compilationCommand);
1397}
1398
1399bool fromJSON(const llvm::json::Value &Params, ConfigurationSettings &S,
1400 llvm::json::Path P) {
1401 llvm::json::ObjectMapper O(Params, P);
1402 if (!O)
1403 return true; // 'any' type in LSP.
1404 return mapOptOrNull(Params, "compilationDatabaseChanges",
1406}
1407
1408bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts,
1409 llvm::json::Path P) {
1410 llvm::json::ObjectMapper O(Params, P);
1411 if (!O)
1412 return true; // 'any' type in LSP.
1413
1414 return fromJSON(Params, Opts.ConfigSettings, P) &&
1415 O.map("compilationDatabasePath", Opts.compilationDatabasePath) &&
1416 mapOptOrNull(Params, "fallbackFlags", Opts.fallbackFlags, P) &&
1417 mapOptOrNull(Params, "clangdFileStatus", Opts.FileStatus, P);
1418}
1419
1420bool fromJSON(const llvm::json::Value &E, TypeHierarchyDirection &Out,
1421 llvm::json::Path P) {
1422 auto T = E.getAsInteger();
1423 if (!T)
1424 return false;
1425 if (*T < static_cast<int>(TypeHierarchyDirection::Children) ||
1426 *T > static_cast<int>(TypeHierarchyDirection::Both))
1427 return false;
1428 Out = static_cast<TypeHierarchyDirection>(*T);
1429 return true;
1430}
1431
1432bool fromJSON(const llvm::json::Value &Params, TypeHierarchyPrepareParams &R,
1433 llvm::json::Path P) {
1434 llvm::json::ObjectMapper O(Params, P);
1435 return O && O.map("textDocument", R.textDocument) &&
1436 O.map("position", R.position) &&
1437 mapOptOrNull(Params, "resolve", R.resolve, P) &&
1438 mapOptOrNull(Params, "direction", R.direction, P);
1439}
1440
1441llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
1442 const TypeHierarchyItem &I) {
1443 return O << I.name << " - " << toJSON(I);
1444}
1445
1446llvm::json::Value toJSON(const TypeHierarchyItem::ResolveParams &RP) {
1447 llvm::json::Object Result{};
1448 if (RP.parents)
1449 Result["parents"] = RP.parents;
1450 return Result;
1451}
1452bool fromJSON(const llvm::json::Value &Params,
1453 TypeHierarchyItem::ResolveParams &RP, llvm::json::Path P) {
1454 llvm::json::ObjectMapper O(Params, P);
1455 return O && mapOptOrNull(Params, "parents", RP.parents, P);
1456}
1457
1458llvm::json::Value toJSON(const TypeHierarchyItem &I) {
1459 llvm::json::Object Result{
1460 {"name", I.name}, {"kind", static_cast<int>(I.kind)},
1461 {"range", I.range}, {"selectionRange", I.selectionRange},
1462 {"uri", I.uri}, {"data", I.data},
1463 };
1464
1465 if (I.detail)
1466 Result["detail"] = I.detail;
1467 return Result;
1468}
1469
1470bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I,
1471 llvm::json::Path P) {
1472 llvm::json::ObjectMapper O(Params, P);
1473
1474 // Required fields.
1475 return O && O.map("name", I.name) && O.map("kind", I.kind) &&
1476 O.map("uri", I.uri) && O.map("range", I.range) &&
1477 O.map("selectionRange", I.selectionRange) &&
1478 mapOptOrNull(Params, "detail", I.detail, P) &&
1479 mapOptOrNull(Params, "deprecated", I.deprecated, P) &&
1480 mapOptOrNull(Params, "parents", I.parents, P) &&
1481 mapOptOrNull(Params, "children", I.children, P) &&
1482 mapOptOrNull(Params, "data", I.data, P);
1483}
1484
1485bool fromJSON(const llvm::json::Value &Params,
1486 ResolveTypeHierarchyItemParams &R, llvm::json::Path P) {
1487 llvm::json::ObjectMapper O(Params, P);
1488 return O && O.map("item", R.item) &&
1489 mapOptOrNull(Params, "resolve", R.resolve, P) &&
1490 mapOptOrNull(Params, "direction", R.direction, P);
1491}
1492
1493bool fromJSON(const llvm::json::Value &Params, ReferenceContext &R,
1494 llvm::json::Path P) {
1495 llvm::json::ObjectMapper O(Params, P);
1496 return O && O.mapOptional("includeDeclaration", R.includeDeclaration);
1497}
1498
1499bool fromJSON(const llvm::json::Value &Params, ReferenceParams &R,
1500 llvm::json::Path P) {
1502 llvm::json::ObjectMapper O(Params, P);
1503 return fromJSON(Params, Base, P) && O && O.mapOptional("context", R.context);
1504}
1505
1506llvm::json::Value toJSON(SymbolTag Tag) {
1507 return llvm::json::Value{static_cast<int>(Tag)};
1508}
1509
1510llvm::json::Value toJSON(const CallHierarchyItem &I) {
1511 llvm::json::Object Result{{"name", I.name},
1512 {"kind", static_cast<int>(I.kind)},
1513 {"range", I.range},
1514 {"selectionRange", I.selectionRange},
1515 {"uri", I.uri}};
1516 if (!I.tags.empty())
1517 Result["tags"] = I.tags;
1518 if (!I.detail.empty())
1519 Result["detail"] = I.detail;
1520 if (!I.data.empty())
1521 Result["data"] = I.data;
1522 return Result;
1523}
1524
1525bool fromJSON(const llvm::json::Value &Params, CallHierarchyItem &I,
1526 llvm::json::Path P) {
1527 llvm::json::ObjectMapper O(Params, P);
1528
1529 // Populate the required fields only. We don't care about the
1530 // optional fields `Tags` and `Detail` for the purpose of
1531 // client --> server communication.
1532 return O && O.map("name", I.name) && O.map("kind", I.kind) &&
1533 O.map("uri", I.uri) && O.map("range", I.range) &&
1534 O.map("selectionRange", I.selectionRange) &&
1535 mapOptOrNull(Params, "data", I.data, P);
1536}
1537
1538bool fromJSON(const llvm::json::Value &Params,
1539 CallHierarchyIncomingCallsParams &C, llvm::json::Path P) {
1540 llvm::json::ObjectMapper O(Params, P);
1541 return O.map("item", C.item);
1542}
1543
1544llvm::json::Value toJSON(const CallHierarchyIncomingCall &C) {
1545 return llvm::json::Object{{"from", C.from}, {"fromRanges", C.fromRanges}};
1546}
1547
1548bool fromJSON(const llvm::json::Value &Params,
1549 CallHierarchyOutgoingCallsParams &C, llvm::json::Path P) {
1550 llvm::json::ObjectMapper O(Params, P);
1551 return O.map("item", C.item);
1552}
1553
1554llvm::json::Value toJSON(const CallHierarchyOutgoingCall &C) {
1555 return llvm::json::Object{{"to", C.to}, {"fromRanges", C.fromRanges}};
1556}
1557
1558bool fromJSON(const llvm::json::Value &Params, InlayHintsParams &R,
1559 llvm::json::Path P) {
1560 llvm::json::ObjectMapper O(Params, P);
1561 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
1562}
1563
1564llvm::json::Value toJSON(const InlayHintKind &Kind) {
1565 switch (Kind) {
1567 return 1;
1569 return 2;
1570 case InlayHintKind::Designator: // This is an extension, don't serialize.
1571 return nullptr;
1572 }
1573 llvm_unreachable("Unknown clang.clangd.InlayHintKind");
1574}
1575
1576llvm::json::Value toJSON(const InlayHint &H) {
1577 llvm::json::Object Result{{"position", H.position},
1578 {"label", H.label},
1579 {"paddingLeft", H.paddingLeft},
1580 {"paddingRight", H.paddingRight}};
1581 auto K = toJSON(H.kind);
1582 if (!K.getAsNull())
1583 Result["kind"] = std::move(K);
1584 return Result;
1585}
1586bool operator==(const InlayHint &A, const InlayHint &B) {
1587 return std::tie(A.position, A.range, A.kind, A.label) ==
1588 std::tie(B.position, B.range, B.kind, B.label);
1589}
1590bool operator<(const InlayHint &A, const InlayHint &B) {
1591 return std::tie(A.position, A.range, A.kind, A.label) <
1592 std::tie(B.position, B.range, B.kind, B.label);
1593}
1594
1595llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) {
1596 auto ToString = [](InlayHintKind K) {
1597 switch (K) {
1599 return "parameter";
1601 return "type";
1603 return "designator";
1604 }
1605 llvm_unreachable("Unknown clang.clangd.InlayHintKind");
1606 };
1607 return OS << ToString(Kind);
1608}
1609
1610static const char *toString(OffsetEncoding OE) {
1611 switch (OE) {
1613 return "utf-8";
1615 return "utf-16";
1617 return "utf-32";
1619 return "unknown";
1620 }
1621 llvm_unreachable("Unknown clang.clangd.OffsetEncoding");
1622}
1623llvm::json::Value toJSON(const OffsetEncoding &OE) { return toString(OE); }
1624bool fromJSON(const llvm::json::Value &V, OffsetEncoding &OE,
1625 llvm::json::Path P) {
1626 auto Str = V.getAsString();
1627 if (!Str)
1628 return false;
1629 OE = llvm::StringSwitch<OffsetEncoding>(*Str)
1630 .Case("utf-8", OffsetEncoding::UTF8)
1631 .Case("utf-16", OffsetEncoding::UTF16)
1632 .Case("utf-32", OffsetEncoding::UTF32)
1634 return true;
1635}
1636llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OffsetEncoding Enc) {
1637 return OS << toString(Enc);
1638}
1639
1640bool fromJSON(const llvm::json::Value &Params, SelectionRangeParams &S,
1641 llvm::json::Path P) {
1642 llvm::json::ObjectMapper O(Params, P);
1643 return O && O.map("textDocument", S.textDocument) &&
1644 O.map("positions", S.positions);
1645}
1646
1647llvm::json::Value toJSON(const SelectionRange &Out) {
1648 if (Out.parent) {
1649 return llvm::json::Object{{"range", Out.range},
1650 {"parent", toJSON(*Out.parent)}};
1651 }
1652 return llvm::json::Object{{"range", Out.range}};
1653}
1654
1655bool fromJSON(const llvm::json::Value &Params, DocumentLinkParams &R,
1656 llvm::json::Path P) {
1657 llvm::json::ObjectMapper O(Params, P);
1658 return O && O.map("textDocument", R.textDocument);
1659}
1660
1661llvm::json::Value toJSON(const DocumentLink &DocumentLink) {
1662 return llvm::json::Object{
1663 {"range", DocumentLink.range},
1664 {"target", DocumentLink.target},
1665 };
1666}
1667
1668bool fromJSON(const llvm::json::Value &Params, FoldingRangeParams &R,
1669 llvm::json::Path P) {
1670 llvm::json::ObjectMapper O(Params, P);
1671 return O && O.map("textDocument", R.textDocument);
1672}
1673
1674const llvm::StringLiteral FoldingRange::REGION_KIND = "region";
1675const llvm::StringLiteral FoldingRange::COMMENT_KIND = "comment";
1676const llvm::StringLiteral FoldingRange::IMPORT_KIND = "import";
1677
1678llvm::json::Value toJSON(const FoldingRange &Range) {
1679 llvm::json::Object Result{
1680 {"startLine", Range.startLine},
1681 {"endLine", Range.endLine},
1682 };
1683 if (Range.startCharacter)
1684 Result["startCharacter"] = Range.startCharacter;
1685 if (Range.endCharacter)
1686 Result["endCharacter"] = Range.endCharacter;
1687 if (!Range.kind.empty())
1688 Result["kind"] = Range.kind;
1689 return Result;
1690}
1691
1692bool fromJSON(const llvm::json::Value &Params, ASTParams &R,
1693 llvm::json::Path P) {
1694 llvm::json::ObjectMapper O(Params, P);
1695 return O && O.map("textDocument", R.textDocument) && O.map("range", R.range);
1696}
1697
1698llvm::json::Value toJSON(const ASTNode &N) {
1699 llvm::json::Object Result{
1700 {"role", N.role},
1701 {"kind", N.kind},
1702 };
1703 if (!N.children.empty())
1704 Result["children"] = N.children;
1705 if (!N.detail.empty())
1706 Result["detail"] = N.detail;
1707 if (!N.arcana.empty())
1708 Result["arcana"] = N.arcana;
1709 if (N.range)
1710 Result["range"] = *N.range;
1711 return Result;
1712}
1713
1714llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const ASTNode &Root) {
1715 std::function<void(const ASTNode &, unsigned)> Print = [&](const ASTNode &N,
1716 unsigned Level) {
1717 OS.indent(2 * Level) << N.role << ": " << N.kind;
1718 if (!N.detail.empty())
1719 OS << " - " << N.detail;
1720 OS << "\n";
1721 for (const ASTNode &C : N.children)
1722 Print(C, Level + 1);
1723 };
1724 Print(Root, 0);
1725 return OS;
1726}
1727
1728llvm::json::Value toJSON(const ConfigurationItem &N) {
1729 llvm::json::Object R;
1730 if (N.scopeUri)
1731 R["scopeUri"] = N.scopeUri;
1732 if (N.section)
1733 R["section"] = N.section;
1734 return R;
1735}
1736
1737llvm::json::Value toJSON(const ConfigurationParams &N) {
1738 return llvm::json::Object{{"items", N.items}};
1739}
1740
1741} // 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::variant< TextDocumentEdit, CreateFile, RenameFile, DeleteFile > DocumentChange
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
std::optional< llvm::json::Value > data
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::optional< bool > overwrite
Overwrite existing file. Overwrite wins over ignoreIfExists.
std::optional< bool > ignoreIfExists
Ignore if exists.
std::optional< CreateFileOptions > options
Additional options.
std::optional< std::string > annotationId
An optional annotation identifier.
URIForFile uri
The resource to create.
std::optional< bool > ignoreIfNotExists
Ignore the operation if the file doesn't exist.
std::optional< bool > recursive
Delete the content recursively if a folder is denoted.
std::optional< DeleteFileOptions > options
Delete options.
std::optional< std::string > annotationId
An optional annotation identifier.
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::optional< bool > overwrite
Overwrite target if existing. Overwrite wins over ignoreIfExists.
std::optional< bool > ignoreIfExists
Ignores if target exists.
std::optional< RenameFileOptions > options
Rename options.
std::optional< std::string > annotationId
An optional annotation identifier.
URIForFile oldUri
The old (existing) location.
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.
URIForFile uri
The document URI to show (for file:// URIs).
bool success
A boolean indicating if the show was successful.
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< DocumentChange > > documentChanges
The parameters of a Workspace Symbol Request.