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));
63 this->RemoteIndexRoot = convert_to_slash(RemoteIndexRoot, Style::windows);
64 llvm::StringRef
Path(this->RemoteIndexRoot);
65 if (!is_separator(this->RemoteIndexRoot.back(), Style::posix))
66 this->RemoteIndexRoot += PosixSeparator;
68 if (!LocalIndexRoot.empty()) {
69 assert(is_absolute(LocalIndexRoot));
70 this->LocalIndexRoot = convert_to_slash(LocalIndexRoot, Style::windows);
71 llvm::StringRef
Path(this->LocalIndexRoot);
72 if (!is_separator(this->LocalIndexRoot.back(), Style::posix))
73 this->LocalIndexRoot += PosixSeparator;
75 assert(!RemoteIndexRoot.empty() || !LocalIndexRoot.empty());
78llvm::Expected<clangd::LookupRequest>
81 auto IDs = getIDs(Message->ids());
83 return IDs.takeError();
84 Req.
IDs = std::move(*IDs);
88llvm::Expected<clangd::FuzzyFindRequest>
90 assert(!RemoteIndexRoot.empty());
92 Result.
Query = Message->query();
93 for (
const auto &Scope : Message->scopes())
94 Result.
Scopes.push_back(Scope);
95 Result.
AnyScope = Message->any_scope();
97 Result.
Limit = Message->limit();
99 for (
const auto &
Path : Message->proximity_paths()) {
100 llvm::SmallString<256> LocalPath = llvm::StringRef(RemoteIndexRoot);
101 append(LocalPath,
Path);
104 llvm::sys::path::native(LocalPath);
107 for (
const auto &
Type : Message->preferred_types())
112llvm::Expected<clangd::RefsRequest>
115 auto IDs = getIDs(Message->ids());
117 return IDs.takeError();
118 Req.
IDs = std::move(*IDs);
119 if (Message->has_filter())
123 if (Message->limit())
124 Req.
Limit = Message->limit();
129llvm::Expected<clangd::ContainedRefsRequest>
132 if (!Message->has_id())
133 return error(
"ContainedRefsRequest requires an id.");
136 return ID.takeError();
138 if (Message->has_limit())
139 Req.
Limit = Message->limit();
143llvm::Expected<clangd::RelationsRequest>
146 auto IDs = getIDs(Message->subjects());
148 return IDs.takeError();
150 if (!Message->has_predicate())
151 return error(
"RelationsRequest requires RelationKind predicate.");
153 if (Message->limit())
154 Req.
Limit = Message->limit();
159 if (!Message.has_info() || !Message.has_canonical_declaration())
160 return error(
"Missing info or declaration.");
164 return ID.takeError();
167 Result.
Name = Message.name();
168 Result.
Scope = Message.scope();
169 if (Message.has_definition()) {
186 Result.
Type = Message.type();
187 for (
const auto &Header : Message.headers()) {
189 if (!SerializedHeader)
190 return SerializedHeader.takeError();
198 if (!Message.has_location())
199 return error(
"Missing location.");
205 Result.
Kind =
static_cast<RefKind>(Message.kind());
212llvm::Expected<clangd::ContainedRefsResult>
215 if (!Message.has_location())
216 return error(
"ContainedRef must have a location.");
217 if (!Message.has_kind())
218 return error(
"ContainedRef must have a kind.");
219 if (!Message.has_symbol())
220 return error(
"ContainedRef must have a symbol.");
225 Result.
Kind =
static_cast<RefKind>(Message.kind());
228 return Symbol.takeError();
233llvm::Expected<std::pair<clangd::SymbolID, clangd::Symbol>>
237 return SubjectID.takeError();
238 if (!Message.has_object())
239 return error(
"Missing Object.");
242 return Object.takeError();
243 return std::make_pair(*SubjectID, *
Object);
254 assert(!LocalIndexRoot.empty());
256 RPCRequest.set_query(From.
Query);
257 for (
const auto &Scope : From.
Scopes)
258 RPCRequest.add_scopes(Scope);
259 RPCRequest.set_any_scope(From.
AnyScope);
261 RPCRequest.set_limit(*From.
Limit);
264 llvm::SmallString<256> RelativePath = llvm::StringRef(
Path);
265 if (replace_path_prefix(RelativePath, LocalIndexRoot,
""))
266 RPCRequest.add_proximity_paths(
267 convert_to_slash(RelativePath, Style::windows));
270 RPCRequest.add_preferred_types(
Type);
276 for (
const auto &ID : From.
IDs)
277 RPCRequest.add_ids(ID.str());
278 RPCRequest.set_filter(
static_cast<uint32_t
>(From.
Filter));
280 RPCRequest.set_limit(*From.
Limit);
288 RPCRequest.set_id(From.
ID.
str());
290 RPCRequest.set_limit(*From.
Limit);
296 for (
const auto &ID : From.
Subjects)
297 RPCRequest.add_subjects(ID.str());
298 RPCRequest.set_predicate(
static_cast<uint32_t
>(From.
Predicate));
300 RPCRequest.set_limit(*From.
Limit);
306 Result.set_id(From.
ID.
str());
308 Result.set_name(From.
Name.str());
315 Result.set_scope(From.
Scope.str());
319 *Result.mutable_canonical_declaration() = *
Declaration;
321 Result.set_signature(From.
Signature.str());
322 Result.set_template_specialization_args(
326 Result.set_return_type(From.
ReturnType.str());
327 Result.set_type(From.
Type.str());
331 return Serialized.takeError();
332 auto *NextHeader = Result.add_headers();
333 *NextHeader = *Serialized;
335 Result.set_flags(
static_cast<uint32_t
>(From.
Flags));
341 Result.set_kind(
static_cast<uint32_t
>(From.
Kind));
345 *Result.mutable_location() = *
Location;
350llvm::Expected<ContainedRef>
356 *Result.mutable_location() = *
Location;
357 Result.set_kind(
static_cast<uint32_t
>(From.
Kind));
358 *Result.mutable_symbol() = From.
Symbol.
str();
365 *Result.mutable_subject_id() = Subject.
str();
367 if (!SerializedObject)
368 return SerializedObject.takeError();
369 *Result.mutable_object() = *SerializedObject;
373llvm::Expected<std::string>
375 assert(!LocalIndexRoot.empty());
376 assert(RelativePath == convert_to_slash(RelativePath));
377 if (RelativePath.empty())
378 return error(
"Empty relative path.");
379 if (is_absolute(RelativePath, Style::posix))
380 return error(
"RelativePath '{0}' is absolute.", RelativePath);
381 llvm::SmallString<256> FullPath = llvm::StringRef(LocalIndexRoot);
382 append(FullPath, RelativePath);
384 return Result.toString();
388 assert(!RemoteIndexRoot.empty());
391 return ParsedURI.takeError();
392 if (ParsedURI->scheme() !=
"file")
393 return error(
"Can not use URI schemes other than file, given: '{0}'.",
URI);
394 llvm::SmallString<256> Result = ParsedURI->body();
395 llvm::StringRef
Path(Result);
397 if (is_absolute(
Path.substr(1), Style::windows))
398 Result =
Path.drop_front();
399 if (!replace_path_prefix(Result, RemoteIndexRoot,
""))
400 return error(
"File path '{0}' doesn't start with '{1}'.", Result.str(),
402 assert(Result == convert_to_slash(Result, Style::windows));
403 return std::string(Result);
409 Result.
setColumn(
static_cast<uint32_t
>(Message.column()));
410 Result.
setLine(
static_cast<uint32_t
>(Message.
line()));
416 remote::Position Result;
417 Result.set_column(
Position.column());
423 clang::index::SymbolInfo Result;
424 Result.Kind =
static_cast<clang::index::SymbolKind
>(Message.kind());
425 Result.SubKind =
static_cast<clang::index::SymbolSubKind
>(Message.subkind());
426 Result.Lang =
static_cast<clang::index::SymbolLanguage
>(Message.language());
428 static_cast<clang::index::SymbolPropertySet
>(Message.properties());
434 Result.set_kind(
static_cast<uint32_t
>(
Info.Kind));
435 Result.set_subkind(
static_cast<uint32_t
>(
Info.SubKind));
436 Result.set_language(
static_cast<uint32_t
>(
Info.Lang));
437 Result.set_properties(
static_cast<uint32_t
>(
Info.Properties));
441llvm::Expected<clangd::SymbolLocation>
443 clangd::SymbolLocation Location;
446 return URIString.takeError();
447 Location.FileURI = Strings.save(*URIString).begin();
453llvm::Expected<SymbolLocation>
455 remote::SymbolLocation Result;
458 return RelativePath.takeError();
459 *Result.mutable_file_path() = *RelativePath;
460 *Result.mutable_start() =
toProtobuf(Location.Start);
461 *Result.mutable_end() =
toProtobuf(Location.End);
466 const clangd::Symbol::IncludeHeaderWithReferences &IncludeHeader) {
467 HeaderWithReferences Result;
468 Result.set_references(IncludeHeader.References);
469 Result.set_supported_directives(IncludeHeader.SupportedDirectives);
470 const std::string Header = IncludeHeader.IncludeHeader.str();
472 Result.set_header(Header);
477 return RelativePath.takeError();
478 Result.set_header(*RelativePath);
482llvm::Expected<clangd::Symbol::IncludeHeaderWithReferences>
484 std::string Header = Message.header();
488 return URIString.takeError();
492 if (Message.has_supported_directives())
494 Message.supported_directives());
495 return clangd::Symbol::IncludeHeaderWithReferences{
496 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.