16 #include "llvm/ADT/Hashing.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/ADT/StringSet.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include "llvm/Support/Format.h"
22 #include "llvm/Support/FormatVariadic.h"
23 #include "llvm/Support/JSON.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/Path.h"
26 #include "llvm/Support/raw_ostream.h"
34 llvm::StringLiteral prop, T &out,
35 llvm::json::Path path) {
36 const llvm::json::Object *o = params.getAsObject();
40 auto *v = o->get(prop);
41 if (!v || v->getAsNull())
43 return fromJSON(*v, out, path.field(prop));
57 return path.size() > 1 && llvm::isAlpha(path[0]) && path[1] ==
':';
61 return path.size() > 2 && path[0] == path[1] &&
62 llvm::sys::path::is_separator(path[0]);
67 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
68 (c >=
'0' && c <=
'9'))
90 for (
unsigned char c : content) {
93 out.push_back(llvm::hexdigit(c / 16));
94 out.push_back(llvm::hexdigit(c % 16));
104 for (
auto i = content.begin(), e = content.end(); i != e; ++i) {
109 if (*i ==
'%' && i + 2 < content.end() && llvm::isHexDigit(*(i + 1)) &&
110 llvm::isHexDigit(*(i + 2))) {
111 result.push_back(llvm::hexFromNibbles(*(i + 1), *(i + 2)));
114 result.push_back(*i);
132 if (!llvm::isAlpha(scheme[0]))
134 return llvm::all_of(llvm::drop_begin(scheme), [](
char c) {
135 return llvm::isAlnum(c) || c ==
'+' || c ==
'.' || c ==
'-';
143 StringRef root = llvm::sys::path::root_name(absolutePath);
146 authority = root.drop_front(2);
147 absolutePath.consume_front(root);
152 body += llvm::sys::path::convert_to_slash(absolutePath);
154 std::string uri = scheme.str() +
":";
155 if (authority.empty() && body.empty())
160 if (!authority.empty() || StringRef(body).startswith(
"/")) {
170 if (!body.startswith(
"/"))
171 return llvm::createStringError(
172 llvm::inconvertibleErrorCode(),
173 "File scheme: expect body to be an absolute path starting "
177 if (!authority.empty()) {
179 (
"//" + authority).toVector(path);
182 body.consume_front(
"/");
185 llvm::sys::path::native(path);
186 return std::string(path);
190 StringRef uri = origUri;
193 size_t pos = uri.find(
':');
194 if (pos == StringRef::npos)
195 return llvm::createStringError(llvm::inconvertibleErrorCode(),
196 "Scheme must be provided in URI: " +
198 StringRef schemeStr = uri.substr(0, pos);
201 return llvm::createStringError(llvm::inconvertibleErrorCode(),
202 "Invalid scheme: " + schemeStr +
203 " (decoded: " + uriScheme +
")");
204 uri = uri.substr(pos + 1);
207 std::string uriAuthority;
208 if (uri.consume_front(
"//")) {
211 uri = uri.substr(pos);
219 return llvm::createStringError(llvm::inconvertibleErrorCode(),
220 "unsupported URI scheme `" + uriScheme +
221 "' for workspace files");
229 return filePath.takeError();
238 return uri.takeError();
249 llvm::json::Path path) {
250 if (std::optional<StringRef> str = value.getAsString()) {
253 path.report(
"unresolvable URI");
254 consumeError(expectedURI.takeError());
257 result = std::move(*expectedURI);
268 return os << value.
uri();
277 const llvm::json::Object *o = value.getAsObject();
279 path.report(
"expected object");
282 if (
const llvm::json::Object *textDocument = o->getObject(
"textDocument")) {
283 if (
const llvm::json::Object *documentSymbol =
284 textDocument->getObject(
"documentSymbol")) {
285 if (std::optional<bool> hierarchicalSupport =
286 documentSymbol->getBoolean(
"hierarchicalDocumentSymbolSupport"))
289 if (
auto *codeAction = textDocument->getObject(
"codeAction")) {
290 if (codeAction->getObject(
"codeActionLiteralSupport"))
302 llvm::json::Path path) {
303 llvm::json::ObjectMapper o(value, path);
304 if (!o || !o.map(
"name", result.
name))
308 o.map(
"version", result.
version);
317 llvm::json::Path path) {
318 if (std::optional<StringRef> str = value.getAsString()) {
323 if (*str ==
"messages") {
327 if (*str ==
"verbose") {
337 llvm::json::ObjectMapper o(value, path);
342 o.map(
"trace", result.
trace);
354 llvm::json::ObjectMapper o(value, path);
355 return o && o.map(
"uri", result.
uri) &&
356 o.map(
"languageId", result.
languageId) && o.map(
"text", result.
text) &&
357 o.map(
"version", result.
version);
365 return llvm::json::Object{{
"uri", value.
uri}};
370 llvm::json::Path path) {
371 llvm::json::ObjectMapper o(value, path);
372 return o && o.map(
"uri", result.
uri);
381 return llvm::json::Object{
389 llvm::json::Path path) {
390 llvm::json::ObjectMapper o(value, path);
391 return o && o.map(
"uri", result.
uri) && o.map(
"version", result.
version);
399 llvm::json::Path path) {
400 llvm::json::ObjectMapper o(value, path);
401 return o && o.map(
"line", result.
line) &&
406 return llvm::json::Object{
407 {
"line", value.
line},
421 llvm::json::Path path) {
422 llvm::json::ObjectMapper o(value, path);
423 return o && o.map(
"start", result.
start) && o.map(
"end", result.
end);
427 return llvm::json::Object{
428 {
"start", value.
start},
434 return os << value.
start <<
'-' << value.
end;
442 llvm::json::Path path) {
443 llvm::json::ObjectMapper o(value, path);
444 return o && o.map(
"uri", result.
uri) && o.map(
"range", result.
range);
448 return llvm::json::Object{
450 {
"range", value.
range},
455 return os << value.
range <<
'@' << value.
uri;
464 llvm::json::Path path) {
465 llvm::json::ObjectMapper o(value, path);
466 return o && o.map(
"textDocument", result.
textDocument) &&
476 llvm::json::ObjectMapper o(value, path);
483 llvm::json::ObjectMapper o(value, path);
484 return fromJSON(value, base, path) && o &&
485 o.mapOptional(
"context", result.
context);
494 llvm::json::Path path) {
495 llvm::json::ObjectMapper o(value, path);
505 llvm::json::Path path) {
506 llvm::json::ObjectMapper o(value, path);
523 llvm::SourceMgr tmpScrMgr;
524 tmpScrMgr.AddNewSourceBuffer(llvm::MemoryBuffer::getMemBuffer(contents),
526 SMRange rangeLoc =
range->getAsSMRange(tmpScrMgr);
527 if (!rangeLoc.isValid())
530 contents.replace(rangeLoc.Start.getPointer() - contents.data(),
531 rangeLoc.End.getPointer() - rangeLoc.Start.getPointer(),
538 for (
const auto &change : changes)
539 if (
failed(change.applyTo(contents)))
546 llvm::json::Path path) {
547 llvm::json::ObjectMapper o(value, path);
548 return o && o.map(
"range", result.
range) &&
549 o.map(
"rangeLength", result.
rangeLength) && o.map(
"text", result.
text);
554 llvm::json::Path path) {
555 llvm::json::ObjectMapper o(value, path);
556 return o && o.map(
"textDocument", result.
textDocument) &&
571 llvm_unreachable(
"Invalid MarkupKind");
579 if (mc.
value.empty())
582 return llvm::json::Object{
596 return std::move(result);
604 llvm::json::Object result{{
"name", symbol.
name},
605 {
"kind",
static_cast<int>(symbol.
kind)},
606 {
"range", symbol.
range},
609 if (!symbol.
detail.empty())
610 result[
"detail"] = symbol.
detail;
612 result[
"children"] = symbol.
children;
613 return std::move(result);
622 llvm::json::ObjectMapper o(value, path);
632 llvm::json::Path path) {
633 llvm::json::ObjectMapper o(value, path);
634 return o && o.map(
"location", result.
location) &&
635 o.map(
"message", result.
message);
639 return llvm::json::Object{
650 llvm::json::Object result{
651 {
"range",
diag.range},
652 {
"severity", (int)
diag.severity},
653 {
"message",
diag.message},
656 result[
"category"] = *
diag.category;
657 if (!
diag.source.empty())
658 result[
"source"] =
diag.source;
659 if (
diag.relatedInformation)
660 result[
"relatedInformation"] = *
diag.relatedInformation;
661 return std::move(result);
665 llvm::json::Path path) {
666 llvm::json::ObjectMapper o(value, path);
674 return o.map(
"range", result.
range) && o.map(
"message", result.
message) &&
686 return llvm::json::Object{
698 llvm::json::Path path) {
699 llvm::json::ObjectMapper o(value, path);
700 return o && o.map(
"range", result.
range) && o.map(
"newText", result.
newText);
704 return llvm::json::Object{
705 {
"range", value.
range},
711 os << value.
range <<
" => \"";
712 llvm::printEscapedString(value.
newText, os);
722 if (std::optional<int64_t> intValue = value.getAsInteger()) {
735 size_t kindVal =
static_cast<size_t>(kind);
737 kindVal <= supportedCompletionItemKinds.size() &&
738 supportedCompletionItemKinds[kindVal])
756 llvm::json::Path path) {
757 if (
const llvm::json::Array *arrayValue = value.getAsArray()) {
758 for (
size_t i = 0, e = arrayValue->size(); i < e; ++i) {
760 if (
fromJSON((*arrayValue)[i], kindOut, path.index(i)))
761 result.set(
size_t(kindOut));
773 assert(!value.
label.empty() &&
"completion item label is required");
774 llvm::json::Object result{{
"label", value.
label}};
776 result[
"kind"] =
static_cast<int>(value.
kind);
777 if (!value.
detail.empty())
778 result[
"detail"] = value.
detail;
782 result[
"sortText"] = value.
sortText;
790 result[
"textEdit"] = *value.
textEdit;
792 result[
"additionalTextEdits"] =
797 return std::move(result);
802 return os << value.
label <<
" - " <<
toJSON(value);
816 return llvm::json::Object{
818 {
"items", llvm::json::Array(value.
items)},
828 llvm::json::ObjectMapper o(value, path);
830 if (!o || !o.map(
"triggerKind", triggerKind) ||
845 if (
const llvm::json::Value *context = value.getAsObject()->get(
"context"))
856 "parameter information label is required");
857 llvm::json::Object result;
859 result[
"label"] = llvm::json::Array(
865 return std::move(result);
873 assert(!value.
label.empty() &&
"signature information label is required");
874 llvm::json::Object result{
875 {
"label", value.
label},
876 {
"parameters", llvm::json::Array(value.
parameters)},
880 return std::move(result);
885 return os << value.
label <<
" - " <<
toJSON(value);
894 "Unexpected negative value for number of active signatures.");
896 "Unexpected negative value for active parameter index");
897 return llvm::json::Object{
900 {
"signatures", llvm::json::Array(value.
signatures)},
910 llvm::json::ObjectMapper o(value, path);
919 return llvm::json::Object{
920 {
"range", value.
range},
931 llvm::json::ObjectMapper o(value, path);
932 return o && o.map(
"textDocument", result.
textDocument) &&
933 o.map(
"range", result.
range);
941 return llvm::json::Object{{
"position", value.
position},
942 {
"kind", (int)value.
kind},
943 {
"label", value.
label},
960 return os <<
"parameter";
964 llvm_unreachable(
"Unknown InlayHintKind");
973 llvm::json::ObjectMapper o(value, path);
974 if (!o || !o.map(
"diagnostics", result.
diagnostics))
976 o.map(
"only", result.
only);
986 llvm::json::ObjectMapper o(value, path);
987 return o && o.map(
"textDocument", result.
textDocument) &&
988 o.map(
"range", result.
range) && o.map(
"context", result.
context);
996 llvm::json::Path path) {
997 llvm::json::ObjectMapper o(value, path);
998 return o && o.map(
"changes", result.
changes);
1002 llvm::json::Object fileChanges;
1003 for (
auto &change : value.
changes)
1004 fileChanges[change.first] = llvm::json::Array(change.second);
1005 return llvm::json::Object{{
"changes", std::move(fileChanges)}};
1017 llvm::json::Object codeAction{{
"title", value.
title}};
1019 codeAction[
"kind"] = *value.
kind;
1021 codeAction[
"diagnostics"] = llvm::json::Array(*value.
diagnostics);
1023 codeAction[
"isPreferred"] =
true;
1025 codeAction[
"edit"] = *value.
edit;
1026 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)
This header declares functions that assist transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
This class represents an efficient way to signal success or failure.
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::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.