21#include "clang/Index/IndexSymbol.h"
22#include "llvm/ADT/DenseSet.h"
23#include "llvm/ADT/SmallString.h"
24#include "llvm/ADT/SmallVector.h"
25#include "llvm/ADT/StringRef.h"
26#include "llvm/Support/Error.h"
27#include "llvm/Support/FormatVariadic.h"
28#include "llvm/Support/Path.h"
29#include "llvm/Support/StringSaver.h"
35using llvm::sys::path::append;
36using llvm::sys::path::convert_to_slash;
37using llvm::sys::path::is_absolute;
38using llvm::sys::path::replace_path_prefix;
39using llvm::sys::path::Style;
43template <
typename IDRange>
44llvm::Expected<llvm::DenseSet<SymbolID>> getIDs(IDRange IDs) {
45 llvm::DenseSet<SymbolID> Result;
46 for (
const auto &ID : IDs) {
49 return SID.takeError();
58 llvm::StringRef LocalIndexRoot)
60 llvm::StringRef PosixSeparator = get_separator(Style::posix);
61 if (!RemoteIndexRoot.empty()) {
62 assert(is_absolute(RemoteIndexRoot, Style::posix) ||
63 is_absolute(RemoteIndexRoot, Style::windows));
64 this->RemoteIndexRoot = convert_to_slash(RemoteIndexRoot, Style::windows);
65 llvm::StringRef
Path(this->RemoteIndexRoot);
66 if (!is_separator(this->RemoteIndexRoot.back(), Style::posix))
67 this->RemoteIndexRoot += PosixSeparator;
69 if (!LocalIndexRoot.empty()) {
70 assert(is_absolute(LocalIndexRoot, Style::posix) ||
71 is_absolute(LocalIndexRoot, Style::windows));
72 this->LocalIndexRoot = convert_to_slash(LocalIndexRoot, Style::windows);
73 llvm::StringRef
Path(this->LocalIndexRoot);
74 if (!is_separator(this->LocalIndexRoot.back(), Style::posix))
75 this->LocalIndexRoot += PosixSeparator;
77 assert(!RemoteIndexRoot.empty() || !LocalIndexRoot.empty());
80llvm::Expected<clangd::LookupRequest>
83 auto IDs = getIDs(Message->ids());
85 return IDs.takeError();
86 Req.
IDs = std::move(*IDs);
90llvm::Expected<clangd::FuzzyFindRequest>
92 assert(!RemoteIndexRoot.empty());
94 Result.
Query = Message->query();
95 for (
const auto &Scope : Message->scopes())
96 Result.
Scopes.push_back(Scope);
97 Result.
AnyScope = Message->any_scope();
99 Result.
Limit = Message->limit();
101 for (
const auto &
Path : Message->proximity_paths()) {
102 llvm::SmallString<256> LocalPath = llvm::StringRef(RemoteIndexRoot);
103 append(LocalPath,
Path);
106 llvm::sys::path::native(LocalPath);
109 for (
const auto &
Type : Message->preferred_types())
114llvm::Expected<clangd::RefsRequest>
117 auto IDs = getIDs(Message->ids());
119 return IDs.takeError();
120 Req.
IDs = std::move(*IDs);
121 if (Message->has_filter())
125 if (Message->limit())
126 Req.
Limit = Message->limit();
131llvm::Expected<clangd::ContainedRefsRequest>
134 if (!Message->has_id())
135 return error(
"ContainedRefsRequest requires an id.");
138 return ID.takeError();
140 if (Message->has_limit())
141 Req.
Limit = Message->limit();
145llvm::Expected<clangd::RelationsRequest>
148 auto IDs = getIDs(Message->subjects());
150 return IDs.takeError();
152 if (!Message->has_predicate())
153 return error(
"RelationsRequest requires RelationKind predicate.");
155 if (Message->limit())
156 Req.
Limit = Message->limit();
161 if (!Message.has_info() || !Message.has_canonical_declaration())
162 return error(
"Missing info or declaration.");
166 return ID.takeError();
169 Result.
Name = Message.name();
170 Result.
Scope = Message.scope();
171 if (Message.has_definition()) {
188 Result.
Type = Message.type();
189 for (
const auto &Header : Message.headers()) {
191 if (!SerializedHeader)
192 return SerializedHeader.takeError();
200 if (!Message.has_location())
201 return error(
"Missing location.");
207 Result.
Kind =
static_cast<RefKind>(Message.kind());
214llvm::Expected<clangd::ContainedRefsResult>
217 if (!Message.has_location())
218 return error(
"ContainedRef must have a location.");
219 if (!Message.has_kind())
220 return error(
"ContainedRef must have a kind.");
221 if (!Message.has_symbol())
222 return error(
"ContainedRef must have a symbol.");
227 Result.
Kind =
static_cast<RefKind>(Message.kind());
230 return Symbol.takeError();
235llvm::Expected<std::pair<clangd::SymbolID, clangd::Symbol>>
239 return SubjectID.takeError();
240 if (!Message.has_object())
241 return error(
"Missing Object.");
244 return Object.takeError();
245 return std::make_pair(*SubjectID, *
Object);
256 assert(!LocalIndexRoot.empty());
258 RPCRequest.set_query(From.
Query);
259 for (
const auto &Scope : From.
Scopes)
260 RPCRequest.add_scopes(Scope);
261 RPCRequest.set_any_scope(From.
AnyScope);
263 RPCRequest.set_limit(*From.
Limit);
266 llvm::SmallString<256> RelativePath = llvm::StringRef(
Path);
267 if (replace_path_prefix(RelativePath, LocalIndexRoot,
""))
268 RPCRequest.add_proximity_paths(
269 convert_to_slash(RelativePath, Style::windows));
272 RPCRequest.add_preferred_types(
Type);
278 for (
const auto &ID : From.
IDs)
279 RPCRequest.add_ids(ID.str());
280 RPCRequest.set_filter(
static_cast<uint32_t
>(From.
Filter));
282 RPCRequest.set_limit(*From.
Limit);
290 RPCRequest.set_id(From.
ID.
str());
292 RPCRequest.set_limit(*From.
Limit);
298 for (
const auto &ID : From.
Subjects)
299 RPCRequest.add_subjects(ID.str());
300 RPCRequest.set_predicate(
static_cast<uint32_t
>(From.
Predicate));
302 RPCRequest.set_limit(*From.
Limit);
308 Result.set_id(From.
ID.
str());
310 Result.set_name(From.
Name.str());
317 Result.set_scope(From.
Scope.str());
321 *Result.mutable_canonical_declaration() = *
Declaration;
323 Result.set_signature(From.
Signature.str());
324 Result.set_template_specialization_args(
328 Result.set_return_type(From.
ReturnType.str());
329 Result.set_type(From.
Type.str());
333 return Serialized.takeError();
334 auto *NextHeader = Result.add_headers();
335 *NextHeader = *Serialized;
337 Result.set_flags(
static_cast<uint32_t
>(From.
Flags));
343 Result.set_kind(
static_cast<uint32_t
>(From.
Kind));
347 *Result.mutable_location() = *
Location;
352llvm::Expected<ContainedRef>
358 *Result.mutable_location() = *
Location;
359 Result.set_kind(
static_cast<uint32_t
>(From.
Kind));
360 *Result.mutable_symbol() = From.
Symbol.
str();
367 *Result.mutable_subject_id() = Subject.
str();
369 if (!SerializedObject)
370 return SerializedObject.takeError();
371 *Result.mutable_object() = *SerializedObject;
375llvm::Expected<std::string>
377 assert(!LocalIndexRoot.empty());
378 assert(RelativePath == convert_to_slash(RelativePath));
379 if (RelativePath.empty())
380 return error(
"Empty relative path.");
381 if (is_absolute(RelativePath, Style::posix))
382 return error(
"RelativePath '{0}' is absolute.", RelativePath);
383 llvm::SmallString<256> FullPath = llvm::StringRef(LocalIndexRoot);
384 append(FullPath, RelativePath);
386 return Result.toString();
390 assert(!RemoteIndexRoot.empty());
393 return ParsedURI.takeError();
394 if (ParsedURI->scheme() !=
"file")
395 return error(
"Can not use URI schemes other than file, given: '{0}'.",
URI);
396 llvm::SmallString<256> Result = ParsedURI->body();
397 llvm::StringRef
Path(Result);
399 if (is_absolute(
Path.substr(1), Style::windows))
400 Result =
Path.drop_front().str();
401 if (!replace_path_prefix(Result, RemoteIndexRoot,
""))
402 return error(
"File path '{0}' doesn't start with '{1}'.", Result.str(),
404 assert(Result == convert_to_slash(Result, Style::windows));
405 return std::string(Result);
411 Result.
setColumn(
static_cast<uint32_t
>(Message.column()));
412 Result.
setLine(
static_cast<uint32_t
>(Message.
line()));
418 remote::Position Result;
419 Result.set_column(
Position.column());
425 clang::index::SymbolInfo Result;
426 Result.Kind =
static_cast<clang::index::SymbolKind
>(Message.kind());
427 Result.SubKind =
static_cast<clang::index::SymbolSubKind
>(Message.subkind());
428 Result.Lang =
static_cast<clang::index::SymbolLanguage
>(Message.language());
430 static_cast<clang::index::SymbolPropertySet
>(Message.properties());
436 Result.set_kind(
static_cast<uint32_t
>(
Info.Kind));
437 Result.set_subkind(
static_cast<uint32_t
>(
Info.SubKind));
438 Result.set_language(
static_cast<uint32_t
>(
Info.Lang));
439 Result.set_properties(
static_cast<uint32_t
>(
Info.Properties));
443llvm::Expected<clangd::SymbolLocation>
445 clangd::SymbolLocation Location;
448 return URIString.takeError();
449 Location.FileURI = Strings.save(*URIString).begin();
455llvm::Expected<SymbolLocation>
457 remote::SymbolLocation Result;
460 return RelativePath.takeError();
461 *Result.mutable_file_path() = *RelativePath;
462 *Result.mutable_start() =
toProtobuf(Location.Start);
463 *Result.mutable_end() =
toProtobuf(Location.End);
468 const clangd::Symbol::IncludeHeaderWithReferences &IncludeHeader) {
469 HeaderWithReferences Result;
470 Result.set_references(IncludeHeader.References);
471 Result.set_supported_directives(IncludeHeader.SupportedDirectives);
472 const std::string Header = IncludeHeader.IncludeHeader.str();
474 Result.set_header(Header);
479 return RelativePath.takeError();
480 Result.set_header(*RelativePath);
484llvm::Expected<clangd::Symbol::IncludeHeaderWithReferences>
486 std::string Header = Message.header();
490 return URIString.takeError();
494 if (Message.has_supported_directives())
496 Message.supported_directives());
497 return clangd::Symbol::IncludeHeaderWithReferences{
498 Strings.save(Header), Message.references(), Directives};
clang::find_all_symbols::SymbolInfo SymbolInfo
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
A URI describes the location of a source file.
static URI createFile(llvm::StringRef AbsolutePath)
This creates a file:// URI for AbsolutePath. The path must be absolute.
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
LookupRequest toProtobuf(const clangd::LookupRequest &From)
toProtobuf() functions serialize native clangd types and strip IndexRoot from the file paths specific...
llvm::Expected< std::string > uriToRelativePath(llvm::StringRef URI)
Translates a URI from the server's backing index to a relative path suitable to send over the wire to...
llvm::Expected< clangd::Symbol > fromProtobuf(const Symbol &Message)
llvm::Expected< std::string > relativePathToURI(llvm::StringRef RelativePath)
Translates RelativePath into the absolute path and builds URI for the user machine.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
bool isLiteralInclude(llvm::StringRef Include)
Returns true if Include is literal include like "path" or <path>.
@ Info
An information message.
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
RefKind
Describes the kind of a cross-reference.
@ Type
An inlay hint that for a type annotation.
std::string Path
A typedef to represent a file path.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
SymbolID Symbol
The ID of the symbol which is referred to.
SymbolLocation Location
The source location where the symbol is named.
std::vector< std::string > Scopes
If this is non-empty, symbols must be in at least one of the scopes (e.g.
bool RestrictForCodeCompletion
If set to true, only symbols for completion support will be considered.
std::string Query
A query string for the fuzzy find.
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
bool AnyScope
If set to true, allow symbols from any scope.
std::optional< uint32_t > Limit
The number of top candidates to return.
std::vector< std::string > PreferredTypes
Preferred types of symbols. These are raw representation of OpaqueType.
llvm::DenseSet< SymbolID > IDs
int line
Line position in a document (zero-based).
Represents a symbol occurrence in the source file.
SymbolID Container
The ID of the symbol whose definition contains this reference.
SymbolLocation Location
The source location where the symbol is named.
bool WantContainer
If set, populates the container of the reference.
llvm::DenseSet< SymbolID > IDs
std::optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Represents a relation between two symbols.
std::optional< uint32_t > Limit
If set, limit the number of relations returned from the index.
llvm::DenseSet< SymbolID > Subjects
void setColumn(uint32_t Column)
void setLine(uint32_t Line)
The class presents a C++ symbol, e.g.
@ Include
#include "header.h"
SymbolLocation Definition
The location of the symbol's definition, if one was found.
llvm::StringRef Type
Raw representation of the OpaqueType of the symbol, used for scoring purposes.
llvm::StringRef Documentation
Documentation including comment for the symbol declaration.
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
llvm::SmallVector< IncludeHeaderWithReferences, 1 > IncludeHeaders
One Symbol can potentially be included via different headers.
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
llvm::StringRef Signature
A brief description of the symbol that can be appended in the completion candidate list.
unsigned References
The number of translation units that reference this symbol from their main file.
llvm::StringRef ReturnType
Type when this symbol is used in an expression.
llvm::StringRef TemplateSpecializationArgs
Argument list in human-readable format, will be displayed to help disambiguate between different spec...
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
llvm::StringRef CompletionSnippetSuffix
What to insert when completing this symbol, after the symbol name.
SymbolID ID
The ID of the symbol.
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.