15 #include "llvm/ADT/Hashing.h"
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/StringSet.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include "llvm/Support/Format.h"
21 #include "llvm/Support/FormatVariadic.h"
22 #include "llvm/Support/JSON.h"
23 #include "llvm/Support/MemoryBuffer.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/raw_ostream.h"
33 llvm::StringLiteral prop, T &out,
34 llvm::json::Path path) {
35 const llvm::json::Object *o = params.getAsObject();
39 auto *v = o->get(prop);
40 if (!v || v->getAsNull())
42 return fromJSON(*v, out, path.field(prop));
56 return path.size() > 1 && llvm::isAlpha(path[0]) && path[1] ==
':';
60 return path.size() > 2 && path[0] == path[1] &&
61 llvm::sys::path::is_separator(path[0]);
66 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
67 (c >=
'0' && c <=
'9'))
89 for (
unsigned char c : content) {
92 out.push_back(llvm::hexdigit(c / 16));
93 out.push_back(llvm::hexdigit(c % 16));
103 for (
auto i = content.begin(), e = content.end(); i != e; ++i) {
108 if (*i ==
'%' && i + 2 < content.end() && llvm::isHexDigit(*(i + 1)) &&
109 llvm::isHexDigit(*(i + 2))) {
110 result.push_back(llvm::hexFromNibbles(*(i + 1), *(i + 2)));
113 result.push_back(*i);
131 if (!llvm::isAlpha(scheme[0]))
133 return llvm::all_of(llvm::drop_begin(scheme), [](
char c) {
134 return llvm::isAlnum(c) || c ==
'+' || c ==
'.' || c ==
'-';
142 StringRef root = llvm::sys::path::root_name(absolutePath);
145 authority = root.drop_front(2);
146 absolutePath.consume_front(root);
151 body += llvm::sys::path::convert_to_slash(absolutePath);
153 std::string uri = scheme.str() +
":";
154 if (authority.empty() && body.empty())
159 if (!authority.empty() || StringRef(body).starts_with(
"/")) {
169 if (!body.starts_with(
"/"))
170 return llvm::createStringError(
171 llvm::inconvertibleErrorCode(),
172 "File scheme: expect body to be an absolute path starting "
176 if (!authority.empty()) {
178 (
"//" + authority).toVector(path);
181 body.consume_front(
"/");
184 llvm::sys::path::native(path);
185 return std::string(path);
189 StringRef uri = origUri;
192 size_t pos = uri.find(
':');
193 if (pos == StringRef::npos)
194 return llvm::createStringError(llvm::inconvertibleErrorCode(),
195 "Scheme must be provided in URI: " +
197 StringRef schemeStr = uri.substr(0, pos);
200 return llvm::createStringError(llvm::inconvertibleErrorCode(),
201 "Invalid scheme: " + schemeStr +
202 " (decoded: " + uriScheme +
")");
203 uri = uri.substr(pos + 1);
206 std::string uriAuthority;
207 if (uri.consume_front(
"//")) {
210 uri = uri.substr(pos);
218 return llvm::createStringError(llvm::inconvertibleErrorCode(),
219 "unsupported URI scheme `" + uriScheme +
220 "' for workspace files");
228 return filePath.takeError();
237 return uri.takeError();
248 llvm::json::Path path) {
249 if (std::optional<StringRef> str = value.getAsString()) {
252 path.report(
"unresolvable URI");
253 consumeError(expectedURI.takeError());
256 result = std::move(*expectedURI);
267 return os << value.
uri();
276 const llvm::json::Object *o = value.getAsObject();
278 path.report(
"expected object");
281 if (
const llvm::json::Object *textDocument = o->getObject(
"textDocument")) {
282 if (
const llvm::json::Object *documentSymbol =
283 textDocument->getObject(
"documentSymbol")) {
284 if (std::optional<bool> hierarchicalSupport =
285 documentSymbol->getBoolean(
"hierarchicalDocumentSymbolSupport"))
288 if (
auto *codeAction = textDocument->getObject(
"codeAction")) {
289 if (codeAction->getObject(
"codeActionLiteralSupport"))
301 llvm::json::Path path) {
302 llvm::json::ObjectMapper o(value, path);
303 if (!o || !o.map(
"name", result.
name))
307 o.map(
"version", result.
version);
316 llvm::json::Path path) {
317 if (std::optional<StringRef> str = value.getAsString()) {
322 if (*str ==
"messages") {
326 if (*str ==
"verbose") {
336 llvm::json::ObjectMapper o(value, path);
341 o.map(
"trace", result.
trace);
353 llvm::json::ObjectMapper o(value, 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);
364 return llvm::json::Object{{
"uri", value.
uri}};
369 llvm::json::Path path) {
370 llvm::json::ObjectMapper o(value, path);
371 return o && o.map(
"uri", result.
uri);
380 return llvm::json::Object{
388 llvm::json::Path path) {
389 llvm::json::ObjectMapper o(value, path);
390 return o && o.map(
"uri", result.
uri) && o.map(
"version", result.
version);
398 llvm::json::Path path) {
399 llvm::json::ObjectMapper o(value, path);
400 return o && o.map(
"line", result.
line) &&
405 return llvm::json::Object{
406 {
"line", value.
line},
420 llvm::json::Path path) {
421 llvm::json::ObjectMapper o(value, path);
422 return o && o.map(
"start", result.
start) && o.map(
"end", result.
end);
426 return llvm::json::Object{
427 {
"start", value.
start},
433 return os << value.
start <<
'-' << value.
end;
441 llvm::json::Path path) {
442 llvm::json::ObjectMapper o(value, path);
443 return o && o.map(
"uri", result.
uri) && o.map(
"range", result.
range);
447 return llvm::json::Object{
449 {
"range", value.
range},
454 return os << value.
range <<
'@' << value.
uri;
463 llvm::json::Path path) {
464 llvm::json::ObjectMapper o(value, path);
465 return o && o.map(
"textDocument", result.
textDocument) &&
475 llvm::json::ObjectMapper o(value, path);
482 llvm::json::ObjectMapper o(value, path);
483 return fromJSON(value, base, path) && o &&
484 o.mapOptional(
"context", result.
context);
493 llvm::json::Path path) {
494 llvm::json::ObjectMapper o(value, path);
504 llvm::json::Path path) {
505 llvm::json::ObjectMapper o(value, path);
522 llvm::SourceMgr tmpScrMgr;
523 tmpScrMgr.AddNewSourceBuffer(llvm::MemoryBuffer::getMemBuffer(contents),
525 SMRange rangeLoc =
range->getAsSMRange(tmpScrMgr);
526 if (!rangeLoc.isValid())
529 contents.replace(rangeLoc.Start.getPointer() - contents.data(),
530 rangeLoc.End.getPointer() - rangeLoc.Start.getPointer(),
537 for (
const auto &change : changes)
538 if (failed(change.applyTo(contents)))
545 llvm::json::Path path) {
546 llvm::json::ObjectMapper o(value, path);
547 return o && o.map(
"range", result.
range) &&
548 o.map(
"rangeLength", result.
rangeLength) && o.map(
"text", result.
text);
553 llvm::json::Path path) {
554 llvm::json::ObjectMapper o(value, path);
555 return o && o.map(
"textDocument", result.
textDocument) &&
570 llvm_unreachable(
"Invalid MarkupKind");
578 if (mc.
value.empty())
581 return llvm::json::Object{
595 return std::move(result);
603 llvm::json::Object result{{
"name", symbol.
name},
604 {
"kind",
static_cast<int>(symbol.
kind)},
605 {
"range", symbol.
range},
608 if (!symbol.
detail.empty())
609 result[
"detail"] = symbol.
detail;
611 result[
"children"] = symbol.
children;
612 return std::move(result);
621 llvm::json::ObjectMapper o(value, path);
631 llvm::json::Path path) {
632 llvm::json::ObjectMapper o(value, path);
633 return o && o.map(
"location", result.
location) &&
634 o.map(
"message", result.
message);
638 return llvm::json::Object{
649 return static_cast<int>(tag);
653 llvm::json::Path path) {
654 if (std::optional<int64_t> i = value.getAsInteger()) {
663 llvm::json::Object result{
664 {
"range",
diag.range},
665 {
"severity", (int)
diag.severity},
666 {
"message",
diag.message},
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);
680 llvm::json::Path path) {
681 llvm::json::ObjectMapper o(value, path);
689 return o.map(
"range", result.
range) && o.map(
"message", result.
message) &&
702 return llvm::json::Object{
714 llvm::json::Path path) {
715 llvm::json::ObjectMapper o(value, path);
716 return o && o.map(
"range", result.
range) && o.map(
"newText", result.
newText);
720 return llvm::json::Object{
721 {
"range", value.
range},
727 os << value.
range <<
" => \"";
728 llvm::printEscapedString(value.
newText, os);
738 if (std::optional<int64_t> intValue = value.getAsInteger()) {
751 size_t kindVal =
static_cast<size_t>(kind);
753 kindVal <= supportedCompletionItemKinds.size() &&
754 supportedCompletionItemKinds[kindVal])
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) {
776 if (
fromJSON((*arrayValue)[i], kindOut, path.index(i)))
777 result.set(
size_t(kindOut));
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;
798 result[
"sortText"] = value.
sortText;
806 result[
"textEdit"] = *value.
textEdit;
808 result[
"additionalTextEdits"] =
813 return std::move(result);
818 return os << value.
label <<
" - " <<
toJSON(value);
832 return llvm::json::Object{
834 {
"items", llvm::json::Array(value.
items)},
844 llvm::json::ObjectMapper o(value, path);
846 if (!o || !o.map(
"triggerKind", triggerKind) ||
861 if (
const llvm::json::Value *context = value.getAsObject()->get(
"context"))
872 "parameter information label is required");
873 llvm::json::Object result;
875 result[
"label"] = llvm::json::Array(
881 return std::move(result);
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)},
896 return std::move(result);
901 return os << value.
label <<
" - " <<
toJSON(value);
910 "Unexpected negative value for number of active signatures.");
912 "Unexpected negative value for active parameter index");
913 return llvm::json::Object{
916 {
"signatures", llvm::json::Array(value.
signatures)},
926 llvm::json::ObjectMapper o(value, path);
935 return llvm::json::Object{
936 {
"range", value.
range},
947 llvm::json::ObjectMapper o(value, path);
948 return o && o.map(
"textDocument", result.
textDocument) &&
949 o.map(
"range", result.
range);
957 return llvm::json::Object{{
"position", value.
position},
958 {
"kind", (int)value.
kind},
959 {
"label", value.
label},
976 return os <<
"parameter";
980 llvm_unreachable(
"Unknown InlayHintKind");
989 llvm::json::ObjectMapper o(value, path);
990 if (!o || !o.map(
"diagnostics", result.
diagnostics))
992 o.map(
"only", result.
only);
1002 llvm::json::ObjectMapper o(value, path);
1003 return o && o.map(
"textDocument", result.
textDocument) &&
1004 o.map(
"range", result.
range) && o.map(
"context", result.
context);
1012 llvm::json::Path path) {
1013 llvm::json::ObjectMapper o(value, path);
1014 return o && o.map(
"changes", result.
changes);
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)}};
1033 llvm::json::Object codeAction{{
"title", value.
title}};
1035 codeAction[
"kind"] = *value.
kind;
1037 codeAction[
"diagnostics"] = llvm::json::Array(*value.
diagnostics);
1039 codeAction[
"isPreferred"] =
true;
1041 codeAction[
"edit"] = *value.
edit;
1042 return std::move(codeAction);
static std::string diag(const llvm::Value &value)
URI in "file" scheme for a file.
StringRef uri() const
Returns the original uri of the file.
static void registerSupportedScheme(StringRef scheme)
Register a supported URI scheme.
static llvm::Expected< URIForFile > fromFile(StringRef absoluteFilepath, StringRef scheme="file")
Try to build a URIForFile from the given absolute file path and optional scheme.
static llvm::Expected< URIForFile > fromURI(StringRef uri)
Try to build a URIForFile from the given URI string.
StringRef scheme() const
Return the scheme of the uri.
static llvm::Expected< std::string > uriFromAbsolutePath(StringRef absolutePath, StringRef scheme)
static bool isNetworkPath(StringRef path)
static llvm::Expected< std::string > getAbsolutePath(StringRef authority, StringRef body)
static llvm::StringRef toTextKind(MarkupKind kind)
static std::string percentDecode(StringRef content)
Decodes a string according to percent-encoding.
static void percentEncode(StringRef content, std::string &out)
Encodes a string according to percent-encoding.
static bool isStructurallyValidScheme(StringRef scheme)
Returns true if the given scheme is structurally valid, i.e.
static StringSet & getSupportedSchemes()
Return the set containing the supported URI schemes.
static bool isWindowsPath(StringRef path)
static bool mapOptOrNull(const llvm::json::Value ¶ms, llvm::StringLiteral prop, T &out, llvm::json::Path path)
static llvm::Expected< std::string > parseFilePathFromURI(StringRef origUri)
static bool shouldEscapeInURI(unsigned char c)
llvm::json::Value toJSON(const URIForFile &value)
Add support for JSON serialization.
raw_ostream & operator<<(raw_ostream &os, const URIForFile &value)
bool operator<(const CompletionItem &lhs, const CompletionItem &rhs)
constexpr auto kCompletionItemKindMin
MarkupKind
Describes the content type that a client supports in various result literals like Hover.
bool contains(SMRange range, SMLoc loc)
Returns true if the given range contains the given source location.
bool fromJSON(const llvm::json::Value &value, URIForFile &result, llvm::json::Path path)
CompletionItemKind adjustKindToCapability(CompletionItemKind kind, CompletionItemKindBitset &supportedCompletionItemKinds)
std::bitset< kCompletionItemKindMax+1 > CompletionItemKindBitset
InlayHintKind
Inlay hint kinds.
@ Parameter
An inlay hint that is for a parameter.
@ Type
An inlay hint that for a type annotation.
CompletionItemKind
The kind of a completion entry.
bool operator==(const TextEdit &lhs, const TextEdit &rhs)
Include the generated interface declarations.
bool codeActionStructure
Client supports CodeAction return value for textDocument/codeAction.
bool hierarchicalDocumentSymbol
Client supports hierarchical document symbols.
std::string name
The name of the client as defined by the client.
std::optional< std::string > version
The client's version as defined by the client.
std::vector< std::string > only
Requested kind of actions to return.
std::vector< Diagnostic > diagnostics
An array of diagnostics known on the client side overlapping the range provided to the textDocument/c...
TextDocumentIdentifier textDocument
The document in which the command was invoked.
Range range
The range for which the command was invoked.
CodeActionContext context
Context carrying additional information.
A code action represents a change that can be performed in code, e.g.
bool isPreferred
Marks this as a preferred action.
std::optional< WorkspaceEdit > edit
The workspace edit this code action performs.
std::optional< std::string > kind
The kind of the code action.
static const llvm::StringLiteral kRefactor
static const llvm::StringLiteral kInfo
std::optional< std::vector< Diagnostic > > diagnostics
The diagnostics that this code action resolves.
static const llvm::StringLiteral kQuickFix
std::string title
A short, human-readable, title for this code action.
std::string triggerCharacter
The trigger character (a single character) that has trigger code complete.
CompletionTriggerKind triggerKind
How the completion was triggered.
std::string detail
A human-readable string with additional information about this item, like type or symbol information.
std::string filterText
A string that should be used when filtering a set of completion items.
std::optional< TextEdit > textEdit
An edit which is applied to a document when selecting this completion.
std::optional< MarkupContent > documentation
A human-readable string that represents a doc-comment.
std::string insertText
A string that should be inserted to a document when selecting this completion.
std::string label
The label of this completion item.
bool deprecated
Indicates if this item is deprecated.
CompletionItemKind kind
The kind of this completion item.
std::vector< TextEdit > additionalTextEdits
An optional array of additional text edits that are applied when selecting this completion.
InsertTextFormat insertTextFormat
The format of the insert text.
std::string sortText
A string that should be used when comparing this item with other items.
Represents a collection of completion items to be presented in the editor.
std::vector< CompletionItem > items
The completion items.
bool isIncomplete
The list is not complete.
CompletionContext context
std::vector< DiagnosticTag > tags
Additional metadata about the diagnostic.
std::string source
A human-readable string describing the source of this diagnostic, e.g.
DiagnosticSeverity severity
The diagnostic's severity.
Range range
The source range where the message applies.
std::optional< std::vector< DiagnosticRelatedInformation > > relatedInformation
An array of related diagnostic information, e.g.
std::string message
The diagnostic's message.
std::optional< std::string > category
The diagnostic's category.
VersionedTextDocumentIdentifier textDocument
The document that changed.
std::vector< TextDocumentContentChangeEvent > contentChanges
The actual content changes.
TextDocumentIdentifier textDocument
The document that was closed.
TextDocumentItem textDocument
The document that was opened.
Parameters for the document link request.
TextDocumentIdentifier textDocument
The document to provide document links for.
A range in a text document that links to an internal or external resource, like another text document...
Range range
The range this link applies to.
URIForFile target
The uri this link points to. If missing a resolve request is sent later.
TextDocumentIdentifier textDocument
Represents programming constructs like variables, classes, interfaces etc.
std::string detail
More detail for this symbol, e.g the signature of a function.
Range range
The range enclosing this symbol not including leading/trailing whitespace but everything else like co...
Range selectionRange
The range that should be selected and revealed when this symbol is being picked, e....
std::vector< DocumentSymbol > children
Children of this symbol, e.g. properties of a class.
SymbolKind kind
The kind of this symbol.
std::string name
The name of this symbol.
std::optional< Range > range
An optional range is a range inside a text document that is used to visualize a hover,...
MarkupContent contents
The hover's content.
std::optional< ClientInfo > clientInfo
Information about the client.
ClientCapabilities capabilities
The capabilities provided by the client (editor or tool).
std::optional< TraceLevel > trace
The initial trace setting. If omitted trace is disabled ('off').
bool paddingLeft
Render padding before the hint.
InlayHintKind kind
The kind of this hint.
Position position
The position of this hint.
bool paddingRight
Render padding after the hint.
std::string label
The label of this hint.
A parameter literal used in inlay hint requests.
Range range
The visible document range for which inlay hints should be computed.
TextDocumentIdentifier textDocument
The text document.
URIForFile uri
The text document's URI.
int line
Line position in a document (zero-based).
int character
Character offset on a line in a document (zero-based).
std::vector< Diagnostic > diagnostics
The list of reported diagnostics.
URIForFile uri
The URI for which diagnostic information is reported.
int64_t version
The version number of the document the diagnostics are published for.
Position end
The range's end position.
Position start
The range's start position.
bool includeDeclaration
Include the declaration of the current symbol.
Represents the signature of a callable.
int activeSignature
The active signature.
int activeParameter
The active parameter of the active signature.
std::vector< SignatureInformation > signatures
The resulting signatures.
std::string text
The new text of the range/document.
LogicalResult applyTo(std::string &contents) const
Try to apply this change to the given contents string.
std::optional< Range > range
The range of the document that changed.
std::optional< int > rangeLength
The length of the range that got replaced.
URIForFile uri
The text document's URI.
std::string languageId
The text document's language identifier.
int64_t version
The version number of this document.
std::string text
The content of the opened text document.
URIForFile uri
The text document's URI.
TextDocumentIdentifier textDocument
The text document.
Position position
The position inside the text document.
std::string newText
The string to be inserted.
Range range
The range of the text document to be manipulated.
int64_t version
The version number of this document.
URIForFile uri
The text document's URI.
std::map< std::string, std::vector< TextEdit > > changes
Holds changes to existing resources.