LLVM 22.0.0git
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
15#include "llvm/ADT/StringSet.h"
17#include "llvm/Support/JSON.h"
19#include "llvm/Support/Path.h"
21
22using namespace llvm;
23using namespace llvm::lsp;
24
25// Helper that doesn't treat `null` and absent fields as failures.
26template <typename T>
27static bool mapOptOrNull(const llvm::json::Value &Params,
28 llvm::StringLiteral Prop, T &Out,
29 llvm::json::Path Path) {
30 const llvm::json::Object *O = Params.getAsObject();
31 assert(O);
32
33 // Field is missing or null.
34 auto *V = O->get(Prop);
35 if (!V || V->getAsNull())
36 return true;
37 return fromJSON(*V, Out, Path.field(Prop));
38}
39
40//===----------------------------------------------------------------------===//
41// LSPError
42//===----------------------------------------------------------------------===//
43
44char LSPError::ID;
45
46//===----------------------------------------------------------------------===//
47// URIForFile
48//===----------------------------------------------------------------------===//
49
50static bool isWindowsPath(StringRef Path) {
51 return Path.size() > 1 && llvm::isAlpha(Path[0]) && Path[1] == ':';
52}
53
54static bool isNetworkPath(StringRef Path) {
55 return Path.size() > 2 && Path[0] == Path[1] &&
57}
58
59static bool shouldEscapeInURI(unsigned char C) {
60 // Unreserved characters.
61 if ((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') ||
62 (C >= '0' && C <= '9'))
63 return false;
64
65 switch (C) {
66 case '-':
67 case '_':
68 case '.':
69 case '~':
70 // '/' is only reserved when parsing.
71 case '/':
72 // ':' is only reserved for relative URI paths, which we doesn't produce.
73 case ':':
74 return false;
75 }
76 return true;
77}
78
79/// Encodes a string according to percent-encoding.
80/// - Unreserved characters are not escaped.
81/// - Reserved characters always escaped with exceptions like '/'.
82/// - All other characters are escaped.
83static void percentEncode(StringRef Content, std::string &Out) {
84 for (unsigned char C : Content) {
85 if (shouldEscapeInURI(C)) {
86 Out.push_back('%');
87 Out.push_back(llvm::hexdigit(C / 16));
88 Out.push_back(llvm::hexdigit(C % 16));
89 } else {
90 Out.push_back(C);
91 }
92 }
93}
94
95/// Decodes a string according to percent-encoding.
96static std::string percentDecode(StringRef Content) {
97 std::string Result;
98 for (auto I = Content.begin(), E = Content.end(); I != E; ++I) {
99 if (*I != '%') {
100 Result += *I;
101 continue;
102 }
103 if (*I == '%' && I + 2 < Content.end() && llvm::isHexDigit(*(I + 1)) &&
104 llvm::isHexDigit(*(I + 2))) {
105 Result.push_back(llvm::hexFromNibbles(*(I + 1), *(I + 2)));
106 I += 2;
107 } else {
108 Result.push_back(*I);
109 }
110 }
111 return Result;
112}
113
114/// Return the set containing the supported URI schemes.
116 static StringSet<> Schemes({"file", "test"});
117 return Schemes;
118}
119
120/// Returns true if the given scheme is structurally valid, i.e. it does not
121/// contain any invalid scheme characters. This does not check that the scheme
122/// is actually supported.
124 if (Scheme.empty())
125 return false;
126 if (!llvm::isAlpha(Scheme[0]))
127 return false;
128 return llvm::all_of(llvm::drop_begin(Scheme), [](char C) {
129 return llvm::isAlnum(C) || C == '+' || C == '.' || C == '-';
130 });
131}
132
134 StringRef Scheme) {
135 std::string Body;
136 StringRef Authority;
137 StringRef Root = llvm::sys::path::root_name(AbsolutePath);
138 if (isNetworkPath(Root)) {
139 // Windows UNC paths e.g. \\server\share => file://server/share
140 Authority = Root.drop_front(2);
141 AbsolutePath.consume_front(Root);
142 } else if (isWindowsPath(Root)) {
143 // Windows paths e.g. X:\path => file:///X:/path
144 Body = "/";
145 }
146 Body += llvm::sys::path::convert_to_slash(AbsolutePath);
147
148 std::string Uri = Scheme.str() + ":";
149 if (Authority.empty() && Body.empty())
150 return Uri;
151
152 // If authority if empty, we only print body if it starts with "/"; otherwise,
153 // the URI is invalid.
154 if (!Authority.empty() || StringRef(Body).starts_with("/")) {
155 Uri.append("//");
156 percentEncode(Authority, Uri);
157 }
158 percentEncode(Body, Uri);
159 return Uri;
160}
161
163 StringRef Body) {
164 if (!Body.starts_with("/"))
167 "File scheme: expect body to be an absolute path starting "
168 "with '/': " +
169 Body);
170 SmallString<128> Path;
171 if (!Authority.empty()) {
172 // Windows UNC paths e.g. file://server/share => \\server\share
173 ("//" + Authority).toVector(Path);
174 } else if (isWindowsPath(Body.substr(1))) {
175 // Windows paths e.g. file:///X:/path => X:\path
176 Body.consume_front("/");
177 }
178 Path.append(Body);
180 return std::string(Path);
181}
182
184 StringRef Uri = OrigUri;
185
186 // Decode the scheme of the URI.
187 size_t Pos = Uri.find(':');
188 if (Pos == StringRef::npos)
190 "Scheme must be provided in URI: " +
191 OrigUri);
192 StringRef SchemeStr = Uri.substr(0, Pos);
193 std::string UriScheme = percentDecode(SchemeStr);
194 if (!isStructurallyValidScheme(UriScheme))
196 "Invalid scheme: " + SchemeStr +
197 " (decoded: " + UriScheme + ")");
198 Uri = Uri.substr(Pos + 1);
199
200 // Decode the authority of the URI.
201 std::string UriAuthority;
202 if (Uri.consume_front("//")) {
203 Pos = Uri.find('/');
204 UriAuthority = percentDecode(Uri.substr(0, Pos));
205 Uri = Uri.substr(Pos);
206 }
207
208 // Decode the body of the URI.
209 std::string UriBody = percentDecode(Uri);
210
211 // Compute the absolute path for this uri.
212 if (!getSupportedSchemes().contains(UriScheme)) {
214 "unsupported URI scheme `" + UriScheme +
215 "' for workspace files");
216 }
217 return getAbsolutePath(UriAuthority, UriBody);
218}
219
222 if (!FilePath)
223 return FilePath.takeError();
224 return URIForFile(std::move(*FilePath), Uri.str());
225}
226
228 StringRef Scheme) {
230 uriFromAbsolutePath(AbsoluteFilepath, Scheme);
231 if (!Uri)
232 return Uri.takeError();
233 return fromURI(*Uri);
234}
235
236StringRef URIForFile::scheme() const { return uri().split(':').first; }
237
241
243 llvm::json::Path Path) {
244 if (std::optional<StringRef> Str = Value.getAsString()) {
246 if (!ExpectedUri) {
247 Path.report("unresolvable URI");
248 consumeError(ExpectedUri.takeError());
249 return false;
250 }
251 Result = std::move(*ExpectedUri);
252 return true;
253 }
254 return false;
255}
256
260
262 return Os << Value.uri();
263}
264
265//===----------------------------------------------------------------------===//
266// ClientCapabilities
267//===----------------------------------------------------------------------===//
268
270 ClientCapabilities &Result, llvm::json::Path Path) {
271 const llvm::json::Object *O = Value.getAsObject();
272 if (!O) {
273 Path.report("expected object");
274 return false;
275 }
276 if (const llvm::json::Object *TextDocument = O->getObject("textDocument")) {
278 TextDocument->getObject("documentSymbol")) {
279 if (std::optional<bool> HierarchicalSupport =
280 DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
281 Result.hierarchicalDocumentSymbol = *HierarchicalSupport;
282 }
283 if (auto *CodeAction = TextDocument->getObject("codeAction")) {
284 if (CodeAction->getObject("codeActionLiteralSupport"))
285 Result.codeActionStructure = true;
286 }
287 }
288 if (auto *Window = O->getObject("window")) {
289 if (std::optional<bool> WorkDoneProgressSupport =
290 Window->getBoolean("workDoneProgress"))
291 Result.workDoneProgress = *WorkDoneProgressSupport;
292 }
293 return true;
294}
295
296//===----------------------------------------------------------------------===//
297// ClientInfo
298//===----------------------------------------------------------------------===//
299
301 llvm::json::Path Path) {
303 if (!O || !O.map("name", Result.name))
304 return false;
305
306 // Don't fail if we can't parse version.
307 O.map("version", Result.version);
308 return true;
309}
310
311//===----------------------------------------------------------------------===//
312// InitializeParams
313//===----------------------------------------------------------------------===//
314
316 llvm::json::Path Path) {
317 if (std::optional<StringRef> Str = Value.getAsString()) {
318 if (*Str == "off") {
319 Result = TraceLevel::Off;
320 return true;
321 }
322 if (*Str == "messages") {
323 Result = TraceLevel::Messages;
324 return true;
325 }
326 if (*Str == "verbose") {
327 Result = TraceLevel::Verbose;
328 return true;
329 }
330 }
331 return false;
332}
333
335 InitializeParams &Result, llvm::json::Path Path) {
337 if (!O)
338 return false;
339 // We deliberately don't fail if we can't parse individual fields.
340 O.map("capabilities", Result.capabilities);
341 O.map("trace", Result.trace);
342 mapOptOrNull(Value, "clientInfo", Result.clientInfo, Path);
343
344 return true;
345}
346
347//===----------------------------------------------------------------------===//
348// TextDocumentItem
349//===----------------------------------------------------------------------===//
350
352 TextDocumentItem &Result, llvm::json::Path Path) {
354 return O && O.map("uri", Result.uri) &&
355 O.map("languageId", Result.languageId) && O.map("text", Result.text) &&
356 O.map("version", Result.version);
357}
358
359//===----------------------------------------------------------------------===//
360// TextDocumentIdentifier
361//===----------------------------------------------------------------------===//
362
366
369 llvm::json::Path Path) {
371 return O && O.map("uri", Result.uri);
372}
373
374//===----------------------------------------------------------------------===//
375// VersionedTextDocumentIdentifier
376//===----------------------------------------------------------------------===//
377
380 return llvm::json::Object{
381 {"uri", Value.uri},
382 {"version", Value.version},
383 };
384}
385
388 llvm::json::Path Path) {
390 return O && O.map("uri", Result.uri) && O.map("version", Result.version);
391}
392
393//===----------------------------------------------------------------------===//
394// Position
395//===----------------------------------------------------------------------===//
396
398 llvm::json::Path Path) {
400 return O && O.map("line", Result.line) &&
401 O.map("character", Result.character);
402}
403
405 return llvm::json::Object{
406 {"line", Value.line},
407 {"character", Value.character},
408 };
409}
410
412 return Os << Value.line << ':' << Value.character;
413}
414
415//===----------------------------------------------------------------------===//
416// Range
417//===----------------------------------------------------------------------===//
418
420 llvm::json::Path Path) {
422 return O && O.map("start", Result.start) && O.map("end", Result.end);
423}
424
426 return llvm::json::Object{
427 {"start", Value.start},
428 {"end", Value.end},
429 };
430}
431
433 return Os << Value.start << '-' << Value.end;
434}
435
436//===----------------------------------------------------------------------===//
437// Location
438//===----------------------------------------------------------------------===//
439
441 llvm::json::Path Path) {
443 return O && O.map("uri", Result.uri) && O.map("range", Result.range);
444}
445
447 return llvm::json::Object{
448 {"uri", Value.uri},
449 {"range", Value.range},
450 };
451}
452
454 return Os << Value.range << '@' << Value.uri;
455}
456
457//===----------------------------------------------------------------------===//
458// TextDocumentPositionParams
459//===----------------------------------------------------------------------===//
460
463 llvm::json::Path Path) {
465 return O && O.map("textDocument", Result.textDocument) &&
466 O.map("position", Result.position);
467}
468
469//===----------------------------------------------------------------------===//
470// ReferenceParams
471//===----------------------------------------------------------------------===//
472
474 ReferenceContext &Result, llvm::json::Path Path) {
476 return O && O.mapOptional("includeDeclaration", Result.includeDeclaration);
477}
478
480 ReferenceParams &Result, llvm::json::Path Path) {
483 return fromJSON(Value, Base, Path) && O &&
484 O.mapOptional("context", Result.context);
485}
486
487//===----------------------------------------------------------------------===//
488// DidOpenTextDocumentParams
489//===----------------------------------------------------------------------===//
490
493 llvm::json::Path Path) {
495 return O && O.map("textDocument", Result.textDocument);
496}
497
498//===----------------------------------------------------------------------===//
499// DidCloseTextDocumentParams
500//===----------------------------------------------------------------------===//
501
504 llvm::json::Path Path) {
506 return O && O.map("textDocument", Result.textDocument);
507}
508
509//===----------------------------------------------------------------------===//
510// DidChangeTextDocumentParams
511//===----------------------------------------------------------------------===//
512
514TextDocumentContentChangeEvent::applyTo(std::string &Contents) const {
515 // If there is no range, the full document changed.
516 if (!range) {
517 Contents = text;
518 return success();
519 }
520
521 // Try to map the replacement range to the content.
522 llvm::SourceMgr TmpScrMgr;
524 SMLoc());
525 SMRange RangeLoc = range->getAsSMRange(TmpScrMgr);
526 if (!RangeLoc.isValid())
527 return failure();
528
529 Contents.replace(RangeLoc.Start.getPointer() - Contents.data(),
530 RangeLoc.End.getPointer() - RangeLoc.Start.getPointer(),
531 text);
532 return success();
533}
534
536 ArrayRef<TextDocumentContentChangeEvent> Changes, std::string &Contents) {
537 for (const auto &Change : Changes)
538 if (failed(Change.applyTo(Contents)))
539 return failure();
540 return success();
541}
542
545 llvm::json::Path Path) {
547 return O && O.map("range", Result.range) &&
548 O.map("rangeLength", Result.rangeLength) && O.map("text", Result.text);
549}
550
553 llvm::json::Path Path) {
555 return O && O.map("textDocument", Result.textDocument) &&
556 O.map("contentChanges", Result.contentChanges);
557}
558
559//===----------------------------------------------------------------------===//
560// MarkupContent
561//===----------------------------------------------------------------------===//
562
564 switch (Kind) {
566 return "plaintext";
568 return "markdown";
569 }
570 llvm_unreachable("Invalid MarkupKind");
571}
572
574 return Os << toTextKind(Kind);
575}
576
578 if (Mc.value.empty())
579 return nullptr;
580
581 return llvm::json::Object{
582 {"kind", toTextKind(Mc.kind)},
583 {"value", Mc.value},
584 };
585}
586
587//===----------------------------------------------------------------------===//
588// Hover
589//===----------------------------------------------------------------------===//
590
592 llvm::json::Object Result{{"contents", toJSON(Hover.contents)}};
593 if (Hover.range)
594 Result["range"] = toJSON(*Hover.range);
595 return std::move(Result);
596}
597
598//===----------------------------------------------------------------------===//
599// DocumentSymbol
600//===----------------------------------------------------------------------===//
601
603 llvm::json::Object Result{{"name", Symbol.name},
604 {"kind", static_cast<int>(Symbol.kind)},
605 {"range", Symbol.range},
606 {"selectionRange", Symbol.selectionRange}};
607
608 if (!Symbol.detail.empty())
609 Result["detail"] = Symbol.detail;
610 if (!Symbol.children.empty())
611 Result["children"] = Symbol.children;
612 return std::move(Result);
613}
614
615//===----------------------------------------------------------------------===//
616// DocumentSymbolParams
617//===----------------------------------------------------------------------===//
618
622 return O && O.map("textDocument", Result.textDocument);
623}
624
625//===----------------------------------------------------------------------===//
626// DiagnosticRelatedInformation
627//===----------------------------------------------------------------------===//
628
631 llvm::json::Path Path) {
633 return O && O.map("location", Result.location) &&
634 O.map("message", Result.message);
635}
636
638 return llvm::json::Object{
639 {"location", Info.location},
640 {"message", Info.message},
641 };
642}
643
644//===----------------------------------------------------------------------===//
645// Diagnostic
646//===----------------------------------------------------------------------===//
647
649 return static_cast<int>(Tag);
650}
651
653 llvm::json::Path Path) {
654 if (std::optional<int64_t> I = Value.getAsInteger()) {
655 Result = (DiagnosticTag)*I;
656 return true;
657 }
658
659 return false;
660}
661
663 llvm::json::Object Result{
664 {"range", Diag.range},
665 {"severity", (int)Diag.severity},
666 {"message", Diag.message},
667 };
668 if (Diag.category)
669 Result["category"] = *Diag.category;
670 if (!Diag.source.empty())
671 Result["source"] = Diag.source;
672 if (Diag.relatedInformation)
673 Result["relatedInformation"] = *Diag.relatedInformation;
674 if (!Diag.tags.empty())
675 Result["tags"] = Diag.tags;
676 return std::move(Result);
677}
678
680 llvm::json::Path Path) {
682 if (!O)
683 return false;
684 int Severity = 0;
685 if (!mapOptOrNull(Value, "severity", Severity, Path))
686 return false;
687 Result.severity = (DiagnosticSeverity)Severity;
688
689 return O.map("range", Result.range) && O.map("message", Result.message) &&
690 mapOptOrNull(Value, "category", Result.category, Path) &&
691 mapOptOrNull(Value, "source", Result.source, Path) &&
692 mapOptOrNull(Value, "relatedInformation", Result.relatedInformation,
693 Path) &&
694 mapOptOrNull(Value, "tags", Result.tags, Path);
695}
696
697//===----------------------------------------------------------------------===//
698// PublishDiagnosticsParams
699//===----------------------------------------------------------------------===//
700
702 return llvm::json::Object{
703 {"uri", Params.uri},
704 {"diagnostics", Params.diagnostics},
705 {"version", Params.version},
706 };
707}
708
709//===----------------------------------------------------------------------===//
710// TextEdit
711//===----------------------------------------------------------------------===//
712
714 llvm::json::Path Path) {
716 return O && O.map("range", Result.range) && O.map("newText", Result.newText);
717}
718
720 return llvm::json::Object{
721 {"range", Value.range},
722 {"newText", Value.newText},
723 };
724}
725
727 Os << Value.range << " => \"";
728 llvm::printEscapedString(Value.newText, Os);
729 return Os << '"';
730}
731
732//===----------------------------------------------------------------------===//
733// CompletionItemKind
734//===----------------------------------------------------------------------===//
735
737 CompletionItemKind &Result, llvm::json::Path Path) {
738 if (std::optional<int64_t> IntValue = Value.getAsInteger()) {
739 if (*IntValue < static_cast<int>(CompletionItemKind::Text) ||
740 *IntValue > static_cast<int>(CompletionItemKind::TypeParameter))
741 return false;
742 Result = static_cast<CompletionItemKind>(*IntValue);
743 return true;
744 }
745 return false;
746}
747
750 CompletionItemKindBitset &SupportedCompletionItemKinds) {
751 size_t KindVal = static_cast<size_t>(Kind);
752 if (KindVal >= kCompletionItemKindMin &&
753 KindVal <= SupportedCompletionItemKinds.size() &&
754 SupportedCompletionItemKinds[KindVal])
755 return Kind;
756
757 // Provide some fall backs for common kinds that are close enough.
758 switch (Kind) {
765 default:
767 }
768}
769
772 llvm::json::Path Path) {
773 if (const llvm::json::Array *ArrayValue = Value.getAsArray()) {
774 for (size_t I = 0, E = ArrayValue->size(); I < E; ++I) {
775 CompletionItemKind KindOut;
776 if (fromJSON((*ArrayValue)[I], KindOut, Path.index(I)))
777 Result.set(size_t(KindOut));
778 }
779 return true;
780 }
781 return false;
782}
783
784//===----------------------------------------------------------------------===//
785// CompletionItem
786//===----------------------------------------------------------------------===//
787
789 assert(!Value.label.empty() && "completion item label is required");
790 llvm::json::Object Result{{"label", Value.label}};
792 Result["kind"] = static_cast<int>(Value.kind);
793 if (!Value.detail.empty())
794 Result["detail"] = Value.detail;
795 if (Value.documentation)
796 Result["documentation"] = Value.documentation;
797 if (!Value.sortText.empty())
798 Result["sortText"] = Value.sortText;
799 if (!Value.filterText.empty())
800 Result["filterText"] = Value.filterText;
801 if (!Value.insertText.empty())
802 Result["insertText"] = Value.insertText;
803 if (Value.insertTextFormat != InsertTextFormat::Missing)
804 Result["insertTextFormat"] = static_cast<int>(Value.insertTextFormat);
805 if (Value.textEdit)
806 Result["textEdit"] = *Value.textEdit;
807 if (!Value.additionalTextEdits.empty()) {
808 Result["additionalTextEdits"] =
809 llvm::json::Array(Value.additionalTextEdits);
810 }
811 if (Value.deprecated)
812 Result["deprecated"] = Value.deprecated;
813 return std::move(Result);
814}
815
817 const CompletionItem &Value) {
818 return Os << Value.label << " - " << toJSON(Value);
819}
820
822 const CompletionItem &Rhs) {
823 return (Lhs.sortText.empty() ? Lhs.label : Lhs.sortText) <
824 (Rhs.sortText.empty() ? Rhs.label : Rhs.sortText);
825}
826
827//===----------------------------------------------------------------------===//
828// CompletionList
829//===----------------------------------------------------------------------===//
830
832 return llvm::json::Object{
833 {"isIncomplete", Value.isIncomplete},
834 {"items", llvm::json::Array(Value.items)},
835 };
836}
837
838//===----------------------------------------------------------------------===//
839// CompletionContext
840//===----------------------------------------------------------------------===//
841
843 CompletionContext &Result, llvm::json::Path Path) {
845 int TriggerKind;
846 if (!O || !O.map("triggerKind", TriggerKind) ||
847 !mapOptOrNull(Value, "triggerCharacter", Result.triggerCharacter, Path))
848 return false;
849 Result.triggerKind = static_cast<CompletionTriggerKind>(TriggerKind);
850 return true;
851}
852
853//===----------------------------------------------------------------------===//
854// CompletionParams
855//===----------------------------------------------------------------------===//
856
858 CompletionParams &Result, llvm::json::Path Path) {
859 if (!fromJSON(Value, static_cast<TextDocumentPositionParams &>(Result), Path))
860 return false;
861 if (const llvm::json::Value *Context = Value.getAsObject()->get("context"))
862 return fromJSON(*Context, Result.context, Path.field("context"));
863 return true;
864}
865
866//===----------------------------------------------------------------------===//
867// ParameterInformation
868//===----------------------------------------------------------------------===//
869
871 assert((Value.labelOffsets || !Value.labelString.empty()) &&
872 "parameter information label is required");
873 llvm::json::Object Result;
874 if (Value.labelOffsets)
875 Result["label"] = llvm::json::Array(
876 {Value.labelOffsets->first, Value.labelOffsets->second});
877 else
878 Result["label"] = Value.labelString;
879 if (!Value.documentation.empty())
880 Result["documentation"] = Value.documentation;
881 return std::move(Result);
882}
883
884//===----------------------------------------------------------------------===//
885// SignatureInformation
886//===----------------------------------------------------------------------===//
887
889 assert(!Value.label.empty() && "signature information label is required");
890 llvm::json::Object Result{
891 {"label", Value.label},
892 {"parameters", llvm::json::Array(Value.parameters)},
893 };
894 if (!Value.documentation.empty())
895 Result["documentation"] = Value.documentation;
896 return std::move(Result);
897}
898
901 return Os << Value.label << " - " << toJSON(Value);
902}
903
904//===----------------------------------------------------------------------===//
905// SignatureHelp
906//===----------------------------------------------------------------------===//
907
909 assert(Value.activeSignature >= 0 &&
910 "Unexpected negative value for number of active signatures.");
911 assert(Value.activeParameter >= 0 &&
912 "Unexpected negative value for active parameter index");
913 return llvm::json::Object{
914 {"activeSignature", Value.activeSignature},
915 {"activeParameter", Value.activeParameter},
916 {"signatures", llvm::json::Array(Value.signatures)},
917 };
918}
919
920//===----------------------------------------------------------------------===//
921// DocumentLinkParams
922//===----------------------------------------------------------------------===//
923
925 DocumentLinkParams &Result, llvm::json::Path Path) {
927 return O && O.map("textDocument", Result.textDocument);
928}
929
930//===----------------------------------------------------------------------===//
931// DocumentLink
932//===----------------------------------------------------------------------===//
933
935 return llvm::json::Object{
936 {"range", Value.range},
937 {"target", Value.target},
938 };
939}
940
941//===----------------------------------------------------------------------===//
942// InlayHintsParams
943//===----------------------------------------------------------------------===//
944
946 InlayHintsParams &Result, llvm::json::Path Path) {
948 return O && O.map("textDocument", Result.textDocument) &&
949 O.map("range", Result.range);
950}
951
952//===----------------------------------------------------------------------===//
953// InlayHint
954//===----------------------------------------------------------------------===//
955
957 return llvm::json::Object{{"position", Value.position},
958 {"kind", (int)Value.kind},
959 {"label", Value.label},
960 {"paddingLeft", Value.paddingLeft},
961 {"paddingRight", Value.paddingRight}};
962}
963bool llvm::lsp::operator==(const InlayHint &Lhs, const InlayHint &Rhs) {
964 return std::tie(Lhs.position, Lhs.kind, Lhs.label) ==
965 std::tie(Rhs.position, Rhs.kind, Rhs.label);
966}
967bool llvm::lsp::operator<(const InlayHint &Lhs, const InlayHint &Rhs) {
968 return std::tie(Lhs.position, Lhs.kind, Lhs.label) <
969 std::tie(Rhs.position, Rhs.kind, Rhs.label);
970}
971
974 switch (Value) {
976 return Os << "parameter";
978 return Os << "type";
979 }
980 llvm_unreachable("Unknown InlayHintKind");
981}
982
983//===----------------------------------------------------------------------===//
984// CodeActionContext
985//===----------------------------------------------------------------------===//
986
988 CodeActionContext &Result, llvm::json::Path Path) {
990 if (!O || !O.map("diagnostics", Result.diagnostics))
991 return false;
992 O.map("only", Result.only);
993 return true;
994}
995
996//===----------------------------------------------------------------------===//
997// CodeActionParams
998//===----------------------------------------------------------------------===//
999
1001 CodeActionParams &Result, llvm::json::Path Path) {
1003 return O && O.map("textDocument", Result.textDocument) &&
1004 O.map("range", Result.range) && O.map("context", Result.context);
1005}
1006
1007//===----------------------------------------------------------------------===//
1008// WorkspaceEdit
1009//===----------------------------------------------------------------------===//
1010
1012 llvm::json::Path Path) {
1014 return O && O.map("changes", Result.changes);
1015}
1016
1018 llvm::json::Object FileChanges;
1019 for (auto &Change : Value.changes)
1020 FileChanges[Change.first] = llvm::json::Array(Change.second);
1021 return llvm::json::Object{{"changes", std::move(FileChanges)}};
1022}
1023
1024//===----------------------------------------------------------------------===//
1025// CodeAction
1026//===----------------------------------------------------------------------===//
1027
1031
1033 llvm::json::Object CodeAction{{"title", Value.title}};
1034 if (Value.kind)
1035 CodeAction["kind"] = *Value.kind;
1036 if (Value.diagnostics)
1037 CodeAction["diagnostics"] = llvm::json::Array(*Value.diagnostics);
1038 if (Value.isPreferred)
1039 CodeAction["isPreferred"] = true;
1040 if (Value.edit)
1041 CodeAction["edit"] = *Value.edit;
1042 return std::move(CodeAction);
1043}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file supports working with JSON data.
#define I(x, y, z)
Definition MD5.cpp:58
#define T
static bool isWindowsPath(StringRef Path)
Definition Protocol.cpp:50
static void percentEncode(StringRef Content, std::string &Out)
Encodes a string according to percent-encoding.
Definition Protocol.cpp:83
static std::string percentDecode(StringRef Content)
Decodes a string according to percent-encoding.
Definition Protocol.cpp:96
static bool isNetworkPath(StringRef Path)
Definition Protocol.cpp:54
static llvm::Expected< std::string > parseFilePathFromURI(StringRef OrigUri)
Definition Protocol.cpp:183
static bool isStructurallyValidScheme(StringRef Scheme)
Returns true if the given scheme is structurally valid, i.e.
Definition Protocol.cpp:123
static bool shouldEscapeInURI(unsigned char C)
Definition Protocol.cpp:59
static llvm::Expected< std::string > uriFromAbsolutePath(StringRef AbsolutePath, StringRef Scheme)
Definition Protocol.cpp:133
static StringSet & getSupportedSchemes()
Return the set containing the supported URI schemes.
Definition Protocol.cpp:115
static bool mapOptOrNull(const llvm::json::Value &Params, llvm::StringLiteral Prop, T &Out, llvm::json::Path Path)
Definition Protocol.cpp:27
static llvm::Expected< std::string > getAbsolutePath(StringRef Authority, StringRef Body)
Definition Protocol.cpp:162
static llvm::StringRef toTextKind(MarkupKind Kind)
Definition Protocol.cpp:563
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:480
This file contains some functions that are useful when dealing with strings.
StringSet - A set-like wrapper for the StringMap.
DEMANGLE_NAMESPACE_BEGIN bool starts_with(std::string_view self, char C) noexcept
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:41
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
Represents a location in source code.
Definition SMLoc.h:23
constexpr const char * getPointer() const
Definition SMLoc.h:34
Represents a range in source code.
Definition SMLoc.h:48
bool isValid() const
Definition SMLoc.h:59
SMLoc Start
Definition SMLoc.h:50
SMLoc End
Definition SMLoc.h:50
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling.
Definition SourceMgr.h:32
unsigned AddNewSourceBuffer(std::unique_ptr< MemoryBuffer > F, SMLoc IncludeLoc)
Add a new source buffer to this source manager.
Definition SourceMgr.h:145
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition StringRef.h:862
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:710
std::string str() const
str - Get the contents as an std::string.
Definition StringRef.h:233
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition StringRef.h:581
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:269
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:151
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition StringRef.h:619
iterator begin() const
Definition StringRef.h:120
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition StringRef.h:645
iterator end() const
Definition StringRef.h:122
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition StringRef.h:301
static constexpr size_t npos
Definition StringRef.h:57
StringSet - A wrapper for StringMap that provides set-like functionality.
Definition StringSet.h:25
std::pair< typename Base::iterator, bool > insert(StringRef key)
Definition StringSet.h:39
An Array is a JSON array, which contains heterogeneous JSON values.
Definition JSON.h:166
Helper for mapping JSON objects onto protocol structs.
Definition JSON.h:861
An Object is a JSON object, which maps strings to heterogenous JSON values.
Definition JSON.h:98
A "cursor" marking a position within a Value.
Definition JSON.h:666
A Value is an JSON value of unknown type.
Definition JSON.h:290
const json::Object * getAsObject() const
Definition JSON.h:464
static char ID
Definition Protocol.h:83
URI in "file" scheme for a file.
Definition Protocol.h:101
static void registerSupportedScheme(StringRef scheme)
Register a supported URI scheme.
Definition Protocol.cpp:238
static llvm::Expected< URIForFile > fromFile(StringRef absoluteFilepath, StringRef scheme="file")
Try to build a URIForFile from the given absolute file path and optional scheme.
Definition Protocol.cpp:227
static llvm::Expected< URIForFile > fromURI(StringRef uri)
Try to build a URIForFile from the given URI string.
Definition Protocol.cpp:220
StringRef scheme() const
Return the scheme of the uri.
Definition Protocol.cpp:236
StringRef uri() const
Returns the original uri of the file.
Definition Protocol.h:117
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
constexpr auto kCompletionItemKindMin
Definition Protocol.h:809
MarkupKind
Describes the content type that a client supports in various result literals like Hover.
Definition Protocol.h:529
llvm::json::Value toJSON(const URIForFile &value)
Add support for JSON serialization.
Definition Protocol.cpp:257
CompletionTriggerKind
Definition Protocol.h:923
bool operator<(const CompletionItem &lhs, const CompletionItem &rhs)
Definition Protocol.cpp:821
bool operator==(const TextEdit &lhs, const TextEdit &rhs)
Definition Protocol.h:764
raw_ostream & operator<<(raw_ostream &os, const URIForFile &value)
Definition Protocol.cpp:261
CompletionItemKind adjustKindToCapability(CompletionItemKind kind, CompletionItemKindBitset &supportedCompletionItemKinds)
Definition Protocol.cpp:748
InlayHintKind
Inlay hint kinds.
Definition Protocol.h:1092
@ Parameter
An inlay hint that is for a parameter.
Definition Protocol.h:1105
@ Type
An inlay hint that for a type annotation.
Definition Protocol.h:1098
DiagnosticSeverity
Definition Protocol.h:677
std::bitset< kCompletionItemKindMax+1 > CompletionItemKindBitset
Definition Protocol.h:813
CompletionItemKind
The kind of a completion entry.
Definition Protocol.h:778
bool fromJSON(const llvm::json::Value &value, URIForFile &result, llvm::json::Path path)
Definition Protocol.cpp:242
LLVM_ABI std::string convert_to_slash(StringRef path, Style style=Style::native)
Replaces backslashes with slashes if Windows.
Definition Path.cpp:568
LLVM_ABI StringRef root_name(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get root name.
Definition Path.cpp:373
LLVM_ABI bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
Definition Path.cpp:601
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:310
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1707
bool failed(LogicalResult Result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:98
LogicalResult failure(bool IsFailure=true)
Utility function to generate a LogicalResult.
LLVM_ABI void printEscapedString(StringRef Name, raw_ostream &Out)
Print each character of the specified string, escaping it if it is not printable or if it is an escap...
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1305
bool isAlpha(char C)
Checks if character C is a valid letter as classified by "C" locale.
uint8_t hexFromNibbles(char MSB, char LSB)
Return the binary representation of the two provided values, MSB and LSB, that make up the nibbles of...
char hexdigit(unsigned X, bool LowerCase=false)
hexdigit - Return the hexadecimal character for the given number X (which should be less than 16).
bool isAlnum(char C)
Checks whether character C is either a decimal digit or an uppercase or lowercase letter as classifie...
bool isHexDigit(char C)
Checks if character C is a hexadecimal numeric character.
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1083
This class represents an efficient way to signal success or failure.
A code action represents a change that can be performed in code, e.g.
Definition Protocol.h:1219
static const llvm::StringLiteral kRefactor
Definition Protocol.h:1227
static const llvm::StringLiteral kInfo
Definition Protocol.h:1228
static const llvm::StringLiteral kQuickFix
Definition Protocol.h:1226
std::string label
The label of this completion item.
Definition Protocol.h:852
std::string sortText
A string that should be used when comparing this item with other items.
Definition Protocol.h:867
Represents a collection of completion items to be presented in the editor.
Definition Protocol.h:907
Represents a related message and source code location for a diagnostic.
Definition Protocol.h:657
std::vector< DiagnosticTag > tags
Additional metadata about the diagnostic.
Definition Protocol.h:717
std::string message
The diagnostic's message.
Definition Protocol.h:710
Range range
The source range where the message applies.
Definition Protocol.h:699
std::optional< std::vector< DiagnosticRelatedInformation > > relatedInformation
An array of related diagnostic information, e.g.
Definition Protocol.h:714
std::string source
A human-readable string describing the source of this diagnostic, e.g.
Definition Protocol.h:707
DiagnosticSeverity severity
The diagnostic's severity.
Definition Protocol.h:703
std::optional< std::string > category
The diagnostic's category.
Definition Protocol.h:723
Parameters for the document link request.
Definition Protocol.h:1025
Represents programming constructs like variables, classes, interfaces etc.
Definition Protocol.h:603
std::optional< Range > range
An optional range is a range inside a text document that is used to visualize a hover,...
Definition Protocol.h:556
MarkupContent contents
The hover's content.
Definition Protocol.h:552
Inlay hint information.
Definition Protocol.h:1113
InlayHintKind kind
The kind of this hint.
Definition Protocol.h:1127
std::string label
The label of this hint.
Definition Protocol.h:1123
Position position
The position of this hint.
Definition Protocol.h:1117
A parameter literal used in inlay hint requests.
Definition Protocol.h:1075
A single parameter of a particular signature.
Definition Protocol.h:966
URIForFile uri
The URI for which diagnostic information is reported.
Definition Protocol.h:740
int64_t version
The version number of the document the diagnostics are published for.
Definition Protocol.h:744
std::vector< Diagnostic > diagnostics
The list of reported diagnostics.
Definition Protocol.h:742
Represents the signature of a callable.
Definition Protocol.h:1006
Represents the signature of something callable.
Definition Protocol.h:986
std::optional< Range > range
The range of the document that changed.
Definition Protocol.h:498
LogicalResult applyTo(std::string &contents) const
Try to apply this change to the given contents string.
Definition Protocol.cpp:514
std::string text
The new text of the range/document.
Definition Protocol.h:504