clang-tools 23.0.0git
Marshalling.cpp
Go to the documentation of this file.
1//===--- Marshalling.cpp -----------------------------------------*- C++-*-===//
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#include "Marshalling.h"
10#include "Headers.h"
11#include "Index.pb.h"
12#include "Protocol.h"
13#include "index/Index.h"
14#include "index/Ref.h"
15#include "index/Serialization.h"
16#include "index/Symbol.h"
17#include "index/SymbolID.h"
19#include "index/SymbolOrigin.h"
20#include "support/Logger.h"
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"
30
31namespace clang {
32namespace clangd {
33namespace remote {
34
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;
40
41namespace {
42
43template <typename IDRange>
44llvm::Expected<llvm::DenseSet<SymbolID>> getIDs(IDRange IDs) {
45 llvm::DenseSet<SymbolID> Result;
46 for (const auto &ID : IDs) {
47 auto SID = SymbolID::fromStr(StringRef(ID));
48 if (!SID)
49 return SID.takeError();
50 Result.insert(*SID);
51 }
52 return Result;
53}
54
55} // namespace
56
57Marshaller::Marshaller(llvm::StringRef RemoteIndexRoot,
58 llvm::StringRef LocalIndexRoot)
59 : Strings(Arena) {
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;
68 }
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;
76 }
77 assert(!RemoteIndexRoot.empty() || !LocalIndexRoot.empty());
78}
79
80llvm::Expected<clangd::LookupRequest>
83 auto IDs = getIDs(Message->ids());
84 if (!IDs)
85 return IDs.takeError();
86 Req.IDs = std::move(*IDs);
87 return Req;
88}
89
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();
98 if (Message->limit())
99 Result.Limit = Message->limit();
100 Result.RestrictForCodeCompletion = Message->restricted_for_code_completion();
101 for (const auto &Path : Message->proximity_paths()) {
102 llvm::SmallString<256> LocalPath = llvm::StringRef(RemoteIndexRoot);
103 append(LocalPath, Path);
104 // FuzzyFindRequest requires proximity paths to have platform-native format
105 // in order for SymbolIndex to process the query correctly.
106 llvm::sys::path::native(LocalPath);
107 Result.ProximityPaths.push_back(std::string(LocalPath));
108 }
109 for (const auto &Type : Message->preferred_types())
110 Result.ProximityPaths.push_back(Type);
111 return Result;
112}
113
114llvm::Expected<clangd::RefsRequest>
117 auto IDs = getIDs(Message->ids());
118 if (!IDs)
119 return IDs.takeError();
120 Req.IDs = std::move(*IDs);
121 if (Message->has_filter())
122 Req.Filter = static_cast<clangd::RefKind>(Message->filter());
123 else
125 if (Message->limit())
126 Req.Limit = Message->limit();
127 Req.WantContainer = Message->want_container();
128 return Req;
129}
130
131llvm::Expected<clangd::ContainedRefsRequest>
134 if (!Message->has_id())
135 return error("ContainedRefsRequest requires an id.");
136 auto ID = SymbolID::fromStr(Message->id());
137 if (!ID)
138 return ID.takeError();
139 Req.ID = *ID;
140 if (Message->has_limit())
141 Req.Limit = Message->limit();
142 return Req;
143}
144
145llvm::Expected<clangd::RelationsRequest>
148 auto IDs = getIDs(Message->subjects());
149 if (!IDs)
150 return IDs.takeError();
151 Req.Subjects = std::move(*IDs);
152 if (!Message->has_predicate())
153 return error("RelationsRequest requires RelationKind predicate.");
154 Req.Predicate = static_cast<RelationKind>(Message->predicate());
155 if (Message->limit())
156 Req.Limit = Message->limit();
157 return Req;
158}
159
160llvm::Expected<clangd::Symbol> Marshaller::fromProtobuf(const Symbol &Message) {
161 if (!Message.has_info() || !Message.has_canonical_declaration())
162 return error("Missing info or declaration.");
163 clangd::Symbol Result;
164 auto ID = SymbolID::fromStr(Message.id());
165 if (!ID)
166 return ID.takeError();
167 Result.ID = *ID;
168 Result.SymInfo = fromProtobuf(Message.info());
169 Result.Name = Message.name();
170 Result.Scope = Message.scope();
171 if (Message.has_definition()) {
172 auto Definition = fromProtobuf(Message.definition());
173 if (Definition)
174 Result.Definition = *Definition;
175 }
176 auto Declaration = fromProtobuf(Message.canonical_declaration());
177 if (!Declaration)
178 return Declaration.takeError();
180 Result.References = Message.references();
181 // Overwrite symbol origin: it's coming from remote index.
183 Result.Signature = Message.signature();
184 Result.TemplateSpecializationArgs = Message.template_specialization_args();
185 Result.CompletionSnippetSuffix = Message.completion_snippet_suffix();
186 Result.Documentation = Message.documentation();
187 Result.ReturnType = Message.return_type();
188 Result.Type = Message.type();
189 for (const auto &Header : Message.headers()) {
190 auto SerializedHeader = fromProtobuf(Header);
191 if (!SerializedHeader)
192 return SerializedHeader.takeError();
193 Result.IncludeHeaders.push_back(*SerializedHeader);
194 }
195 Result.Flags = static_cast<clangd::Symbol::SymbolFlag>(Message.flags());
196 return Result;
197}
198
199llvm::Expected<clangd::Ref> Marshaller::fromProtobuf(const Ref &Message) {
200 if (!Message.has_location())
201 return error("Missing location.");
202 clangd::Ref Result;
203 auto Location = fromProtobuf(Message.location());
204 if (!Location)
205 return Location.takeError();
206 Result.Location = *Location;
207 Result.Kind = static_cast<RefKind>(Message.kind());
208 auto ContainerID = SymbolID::fromStr(Message.container());
209 if (ContainerID)
210 Result.Container = *ContainerID;
211 return Result;
212}
213
214llvm::Expected<clangd::ContainedRefsResult>
215Marshaller::fromProtobuf(const ContainedRef &Message) {
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.");
223 auto Location = fromProtobuf(Message.location());
224 if (!Location)
225 return Location.takeError();
226 Result.Location = *Location;
227 Result.Kind = static_cast<RefKind>(Message.kind());
228 auto Symbol = SymbolID::fromStr(Message.symbol());
229 if (!Symbol)
230 return Symbol.takeError();
231 Result.Symbol = *Symbol;
232 return Result;
233}
234
235llvm::Expected<std::pair<clangd::SymbolID, clangd::Symbol>>
237 auto SubjectID = SymbolID::fromStr(Message.subject_id());
238 if (!SubjectID)
239 return SubjectID.takeError();
240 if (!Message.has_object())
241 return error("Missing Object.");
242 auto Object = fromProtobuf(Message.object());
243 if (!Object)
244 return Object.takeError();
245 return std::make_pair(*SubjectID, *Object);
246}
247
249 LookupRequest RPCRequest;
250 for (const auto &SymbolID : From.IDs)
251 RPCRequest.add_ids(SymbolID.str());
252 return RPCRequest;
253}
254
256 assert(!LocalIndexRoot.empty());
257 FuzzyFindRequest RPCRequest;
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);
262 if (From.Limit)
263 RPCRequest.set_limit(*From.Limit);
264 RPCRequest.set_restricted_for_code_completion(From.RestrictForCodeCompletion);
265 for (const auto &Path : From.ProximityPaths) {
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));
270 }
271 for (const auto &Type : From.PreferredTypes)
272 RPCRequest.add_preferred_types(Type);
273 return RPCRequest;
274}
275
277 RefsRequest RPCRequest;
278 for (const auto &ID : From.IDs)
279 RPCRequest.add_ids(ID.str());
280 RPCRequest.set_filter(static_cast<uint32_t>(From.Filter));
281 if (From.Limit)
282 RPCRequest.set_limit(*From.Limit);
283 RPCRequest.set_want_container(From.WantContainer);
284 return RPCRequest;
285}
286
289 ContainedRefsRequest RPCRequest;
290 RPCRequest.set_id(From.ID.str());
291 if (From.Limit)
292 RPCRequest.set_limit(*From.Limit);
293 return RPCRequest;
294}
295
297 RelationsRequest RPCRequest;
298 for (const auto &ID : From.Subjects)
299 RPCRequest.add_subjects(ID.str());
300 RPCRequest.set_predicate(static_cast<uint32_t>(From.Predicate));
301 if (From.Limit)
302 RPCRequest.set_limit(*From.Limit);
303 return RPCRequest;
304}
305
306llvm::Expected<Symbol> Marshaller::toProtobuf(const clangd::Symbol &From) {
307 Symbol Result;
308 Result.set_id(From.ID.str());
309 *Result.mutable_info() = toProtobuf(From.SymInfo);
310 Result.set_name(From.Name.str());
311 if (*From.Definition.FileURI) {
312 auto Definition = toProtobuf(From.Definition);
313 if (!Definition)
314 return Definition.takeError();
315 *Result.mutable_definition() = *Definition;
316 }
317 Result.set_scope(From.Scope.str());
319 if (!Declaration)
320 return Declaration.takeError();
321 *Result.mutable_canonical_declaration() = *Declaration;
322 Result.set_references(From.References);
323 Result.set_signature(From.Signature.str());
324 Result.set_template_specialization_args(
325 From.TemplateSpecializationArgs.str());
326 Result.set_completion_snippet_suffix(From.CompletionSnippetSuffix.str());
327 Result.set_documentation(From.Documentation.str());
328 Result.set_return_type(From.ReturnType.str());
329 Result.set_type(From.Type.str());
330 for (const auto &Header : From.IncludeHeaders) {
331 auto Serialized = toProtobuf(Header);
332 if (!Serialized)
333 return Serialized.takeError();
334 auto *NextHeader = Result.add_headers();
335 *NextHeader = *Serialized;
336 }
337 Result.set_flags(static_cast<uint32_t>(From.Flags));
338 return Result;
339}
340
341llvm::Expected<Ref> Marshaller::toProtobuf(const clangd::Ref &From) {
342 Ref Result;
343 Result.set_kind(static_cast<uint32_t>(From.Kind));
344 auto Location = toProtobuf(From.Location);
345 if (!Location)
346 return Location.takeError();
347 *Result.mutable_location() = *Location;
348 Result.set_container(From.Container.str());
349 return Result;
350}
351
352llvm::Expected<ContainedRef>
354 ContainedRef Result;
355 auto Location = toProtobuf(From.Location);
356 if (!Location)
357 return Location.takeError();
358 *Result.mutable_location() = *Location;
359 Result.set_kind(static_cast<uint32_t>(From.Kind));
360 *Result.mutable_symbol() = From.Symbol.str();
361 return Result;
362}
363
364llvm::Expected<Relation> Marshaller::toProtobuf(const clangd::SymbolID &Subject,
365 const clangd::Symbol &Object) {
366 Relation Result;
367 *Result.mutable_subject_id() = Subject.str();
368 auto SerializedObject = toProtobuf(Object);
369 if (!SerializedObject)
370 return SerializedObject.takeError();
371 *Result.mutable_object() = *SerializedObject;
372 return Result;
373}
374
375llvm::Expected<std::string>
376Marshaller::relativePathToURI(llvm::StringRef RelativePath) {
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);
385 auto Result = URI::createFile(FullPath);
386 return Result.toString();
387}
388
389llvm::Expected<std::string> Marshaller::uriToRelativePath(llvm::StringRef URI) {
390 assert(!RemoteIndexRoot.empty());
391 auto ParsedURI = URI::parse(URI);
392 if (!ParsedURI)
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);
398 // Check for Windows paths (URI=file:///X:/path => Body=/X:/path)
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(),
403 RemoteIndexRoot);
404 assert(Result == convert_to_slash(Result, Style::windows));
405 return std::string(Result);
406}
407
409Marshaller::fromProtobuf(const Position &Message) {
411 Result.setColumn(static_cast<uint32_t>(Message.column()));
412 Result.setLine(static_cast<uint32_t>(Message.line()));
413 return Result;
414}
415
418 remote::Position Result;
419 Result.set_column(Position.column());
420 Result.set_line(Position.line());
421 return Result;
422}
423
424clang::index::SymbolInfo Marshaller::fromProtobuf(const SymbolInfo &Message) {
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());
429 Result.Properties =
430 static_cast<clang::index::SymbolPropertySet>(Message.properties());
431 return Result;
432}
433
434SymbolInfo Marshaller::toProtobuf(const clang::index::SymbolInfo &Info) {
435 SymbolInfo Result;
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));
440 return Result;
441}
442
443llvm::Expected<clangd::SymbolLocation>
444Marshaller::fromProtobuf(const SymbolLocation &Message) {
445 clangd::SymbolLocation Location;
446 auto URIString = relativePathToURI(Message.file_path());
447 if (!URIString)
448 return URIString.takeError();
449 Location.FileURI = Strings.save(*URIString).begin();
450 Location.Start = fromProtobuf(Message.start());
451 Location.End = fromProtobuf(Message.end());
452 return Location;
453}
454
455llvm::Expected<SymbolLocation>
456Marshaller::toProtobuf(const clangd::SymbolLocation &Location) {
457 remote::SymbolLocation Result;
458 auto RelativePath = uriToRelativePath(Location.FileURI);
459 if (!RelativePath)
460 return RelativePath.takeError();
461 *Result.mutable_file_path() = *RelativePath;
462 *Result.mutable_start() = toProtobuf(Location.Start);
463 *Result.mutable_end() = toProtobuf(Location.End);
464 return Result;
465}
466
467llvm::Expected<HeaderWithReferences> Marshaller::toProtobuf(
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();
473 if (isLiteralInclude(Header)) {
474 Result.set_header(Header);
475 return Result;
476 }
477 auto RelativePath = uriToRelativePath(Header);
478 if (!RelativePath)
479 return RelativePath.takeError();
480 Result.set_header(*RelativePath);
481 return Result;
482}
483
484llvm::Expected<clangd::Symbol::IncludeHeaderWithReferences>
485Marshaller::fromProtobuf(const HeaderWithReferences &Message) {
486 std::string Header = Message.header();
487 if (!isLiteralInclude(Header)) {
488 auto URIString = relativePathToURI(Header);
489 if (!URIString)
490 return URIString.takeError();
491 Header = *URIString;
492 }
494 if (Message.has_supported_directives())
495 Directives = static_cast<clangd::Symbol::IncludeDirective>(
496 Message.supported_directives());
497 return clangd::Symbol::IncludeHeaderWithReferences{
498 Strings.save(Header), Message.references(), Directives};
499}
500
501} // namespace remote
502} // namespace clangd
503} // namespace clang
clang::find_all_symbols::SymbolInfo SymbolInfo
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition SymbolID.cpp:37
std::string str() const
Definition SymbolID.cpp:35
A URI describes the location of a source file.
Definition URI.h:28
static URI createFile(llvm::StringRef AbsolutePath)
This creates a file:// URI for AbsolutePath. The path must be absolute.
Definition URI.cpp:237
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
Definition URI.cpp:176
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.
Definition AST.cpp:44
bool isLiteralInclude(llvm::StringRef Include)
Returns true if Include is literal include like "path" or <path>.
Definition Headers.cpp:134
@ Info
An information message.
Definition Protocol.h:755
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
Definition Logger.h:79
RefKind
Describes the kind of a cross-reference.
Definition Ref.h:28
@ Type
An inlay hint that for a type annotation.
Definition Protocol.h:1731
std::string Path
A typedef to represent a file path.
Definition Path.h:26
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition Index.h:90
SymbolID Symbol
The ID of the symbol which is referred to.
Definition Index.h:105
SymbolLocation Location
The source location where the symbol is named.
Definition Index.h:102
std::vector< std::string > Scopes
If this is non-empty, symbols must be in at least one of the scopes (e.g.
Definition Index.h:36
bool RestrictForCodeCompletion
If set to true, only symbols for completion support will be considered.
Definition Index.h:44
std::string Query
A query string for the fuzzy find.
Definition Index.h:29
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
Definition Index.h:47
bool AnyScope
If set to true, allow symbols from any scope.
Definition Index.h:39
std::optional< uint32_t > Limit
The number of top candidates to return.
Definition Index.h:42
std::vector< std::string > PreferredTypes
Preferred types of symbols. These are raw representation of OpaqueType.
Definition Index.h:49
llvm::DenseSet< SymbolID > IDs
Definition Index.h:65
int line
Line position in a document (zero-based).
Definition Protocol.h:159
Represents a symbol occurrence in the source file.
Definition Ref.h:88
RefKind Kind
Definition Ref.h:91
SymbolID Container
The ID of the symbol whose definition contains this reference.
Definition Ref.h:95
SymbolLocation Location
The source location where the symbol is named.
Definition Ref.h:90
bool WantContainer
If set, populates the container of the reference.
Definition Index.h:77
llvm::DenseSet< SymbolID > IDs
Definition Index.h:69
std::optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition Index.h:74
Represents a relation between two symbols.
Definition Relation.h:32
std::optional< uint32_t > Limit
If set, limit the number of relations returned from the index.
Definition Index.h:97
llvm::DenseSet< SymbolID > Subjects
Definition Index.h:94
The class presents a C++ symbol, e.g.
Definition Symbol.h:39
SymbolFlag Flags
Definition Symbol.h:151
@ Include
#include "header.h"
Definition Symbol.h:93
SymbolLocation Definition
The location of the symbol's definition, if one was found.
Definition Symbol.h:50
llvm::StringRef Type
Raw representation of the OpaqueType of the symbol, used for scoring purposes.
Definition Symbol.h:88
llvm::StringRef Documentation
Documentation including comment for the symbol declaration.
Definition Symbol.h:79
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
Definition Symbol.h:43
llvm::SmallVector< IncludeHeaderWithReferences, 1 > IncludeHeaders
One Symbol can potentially be included via different headers.
Definition Symbol.h:133
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
Definition Symbol.h:45
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
Definition Symbol.h:47
llvm::StringRef Signature
A brief description of the symbol that can be appended in the completion candidate list.
Definition Symbol.h:68
unsigned References
The number of translation units that reference this symbol from their main file.
Definition Symbol.h:62
llvm::StringRef ReturnType
Type when this symbol is used in an expression.
Definition Symbol.h:83
llvm::StringRef TemplateSpecializationArgs
Argument list in human-readable format, will be displayed to help disambiguate between different spec...
Definition Symbol.h:72
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
Definition Symbol.h:59
llvm::StringRef CompletionSnippetSuffix
What to insert when completing this symbol, after the symbol name.
Definition Symbol.h:77
SymbolID ID
The ID of the symbol.
Definition Symbol.h:41
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.
Definition Symbol.h:64