1 //===--- Marshalling.cpp -----------------------------------------*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "Marshalling.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"
18 #include "index/SymbolLocation.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"
35 using llvm::sys::path::append
;
36 using llvm::sys::path::convert_to_slash
;
37 using llvm::sys::path::is_absolute
;
38 using llvm::sys::path::replace_path_prefix
;
39 using llvm::sys::path::Style
;
43 template <typename IDRange
>
44 llvm::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
));
49 return SID
.takeError();
57 Marshaller::Marshaller(llvm::StringRef RemoteIndexRoot
,
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());
78 llvm::Expected
<clangd::LookupRequest
>
79 Marshaller::fromProtobuf(const LookupRequest
*Message
) {
80 clangd::LookupRequest Req
;
81 auto IDs
= getIDs(Message
->ids());
83 return IDs
.takeError();
84 Req
.IDs
= std::move(*IDs
);
88 llvm::Expected
<clangd::FuzzyFindRequest
>
89 Marshaller::fromProtobuf(const FuzzyFindRequest
*Message
) {
90 assert(!RemoteIndexRoot
.empty());
91 clangd::FuzzyFindRequest Result
;
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();
98 Result
.RestrictForCodeCompletion
= Message
->restricted_for_code_completion();
99 for (const auto &Path
: Message
->proximity_paths()) {
100 llvm::SmallString
<256> LocalPath
= llvm::StringRef(RemoteIndexRoot
);
101 append(LocalPath
, Path
);
102 // FuzzyFindRequest requires proximity paths to have platform-native format
103 // in order for SymbolIndex to process the query correctly.
104 llvm::sys::path::native(LocalPath
);
105 Result
.ProximityPaths
.push_back(std::string(LocalPath
));
107 for (const auto &Type
: Message
->preferred_types())
108 Result
.ProximityPaths
.push_back(Type
);
112 llvm::Expected
<clangd::RefsRequest
>
113 Marshaller::fromProtobuf(const RefsRequest
*Message
) {
114 clangd::RefsRequest Req
;
115 auto IDs
= getIDs(Message
->ids());
117 return IDs
.takeError();
118 Req
.IDs
= std::move(*IDs
);
119 if (Message
->has_filter())
120 Req
.Filter
= static_cast<clangd::RefKind
>(Message
->filter());
122 Req
.Filter
= clangd::RefKind::All
;
123 if (Message
->limit())
124 Req
.Limit
= Message
->limit();
125 Req
.WantContainer
= Message
->want_container();
129 llvm::Expected
<clangd::ContainedRefsRequest
>
130 Marshaller::fromProtobuf(const ContainedRefsRequest
*Message
) {
131 clangd::ContainedRefsRequest Req
;
132 if (!Message
->has_id())
133 return error("ContainedRefsRequest requires an id.");
134 auto ID
= SymbolID::fromStr(Message
->id());
136 return ID
.takeError();
138 if (Message
->has_limit())
139 Req
.Limit
= Message
->limit();
143 llvm::Expected
<clangd::RelationsRequest
>
144 Marshaller::fromProtobuf(const RelationsRequest
*Message
) {
145 clangd::RelationsRequest Req
;
146 auto IDs
= getIDs(Message
->subjects());
148 return IDs
.takeError();
149 Req
.Subjects
= std::move(*IDs
);
150 if (!Message
->has_predicate())
151 return error("RelationsRequest requires RelationKind predicate.");
152 Req
.Predicate
= static_cast<RelationKind
>(Message
->predicate());
153 if (Message
->limit())
154 Req
.Limit
= Message
->limit();
158 llvm::Expected
<clangd::Symbol
> Marshaller::fromProtobuf(const Symbol
&Message
) {
159 if (!Message
.has_info() || !Message
.has_canonical_declaration())
160 return error("Missing info or declaration.");
161 clangd::Symbol Result
;
162 auto ID
= SymbolID::fromStr(Message
.id());
164 return ID
.takeError();
166 Result
.SymInfo
= fromProtobuf(Message
.info());
167 Result
.Name
= Message
.name();
168 Result
.Scope
= Message
.scope();
169 if (Message
.has_definition()) {
170 auto Definition
= fromProtobuf(Message
.definition());
172 Result
.Definition
= *Definition
;
174 auto Declaration
= fromProtobuf(Message
.canonical_declaration());
176 return Declaration
.takeError();
177 Result
.CanonicalDeclaration
= *Declaration
;
178 Result
.References
= Message
.references();
179 // Overwrite symbol origin: it's coming from remote index.
180 Result
.Origin
= clangd::SymbolOrigin::Remote
;
181 Result
.Signature
= Message
.signature();
182 Result
.TemplateSpecializationArgs
= Message
.template_specialization_args();
183 Result
.CompletionSnippetSuffix
= Message
.completion_snippet_suffix();
184 Result
.Documentation
= Message
.documentation();
185 Result
.ReturnType
= Message
.return_type();
186 Result
.Type
= Message
.type();
187 for (const auto &Header
: Message
.headers()) {
188 auto SerializedHeader
= fromProtobuf(Header
);
189 if (!SerializedHeader
)
190 return SerializedHeader
.takeError();
191 Result
.IncludeHeaders
.push_back(*SerializedHeader
);
193 Result
.Flags
= static_cast<clangd::Symbol::SymbolFlag
>(Message
.flags());
197 llvm::Expected
<clangd::Ref
> Marshaller::fromProtobuf(const Ref
&Message
) {
198 if (!Message
.has_location())
199 return error("Missing location.");
201 auto Location
= fromProtobuf(Message
.location());
203 return Location
.takeError();
204 Result
.Location
= *Location
;
205 Result
.Kind
= static_cast<RefKind
>(Message
.kind());
209 llvm::Expected
<clangd::ContainedRefsResult
>
210 Marshaller::fromProtobuf(const ContainedRef
&Message
) {
211 clangd::ContainedRefsResult Result
;
212 if (!Message
.has_location())
213 return error("ContainedRef must have a location.");
214 if (!Message
.has_kind())
215 return error("ContainedRef must have a kind.");
216 if (!Message
.has_symbol())
217 return error("ContainedRef must have a symbol.");
218 auto Location
= fromProtobuf(Message
.location());
220 return Location
.takeError();
221 Result
.Location
= *Location
;
222 Result
.Kind
= static_cast<RefKind
>(Message
.kind());
223 auto Symbol
= SymbolID::fromStr(Message
.symbol());
225 return Symbol
.takeError();
226 Result
.Symbol
= *Symbol
;
230 llvm::Expected
<std::pair
<clangd::SymbolID
, clangd::Symbol
>>
231 Marshaller::fromProtobuf(const Relation
&Message
) {
232 auto SubjectID
= SymbolID::fromStr(Message
.subject_id());
234 return SubjectID
.takeError();
235 if (!Message
.has_object())
236 return error("Missing Object.");
237 auto Object
= fromProtobuf(Message
.object());
239 return Object
.takeError();
240 return std::make_pair(*SubjectID
, *Object
);
243 LookupRequest
Marshaller::toProtobuf(const clangd::LookupRequest
&From
) {
244 LookupRequest RPCRequest
;
245 for (const auto &SymbolID
: From
.IDs
)
246 RPCRequest
.add_ids(SymbolID
.str());
250 FuzzyFindRequest
Marshaller::toProtobuf(const clangd::FuzzyFindRequest
&From
) {
251 assert(!LocalIndexRoot
.empty());
252 FuzzyFindRequest RPCRequest
;
253 RPCRequest
.set_query(From
.Query
);
254 for (const auto &Scope
: From
.Scopes
)
255 RPCRequest
.add_scopes(Scope
);
256 RPCRequest
.set_any_scope(From
.AnyScope
);
258 RPCRequest
.set_limit(*From
.Limit
);
259 RPCRequest
.set_restricted_for_code_completion(From
.RestrictForCodeCompletion
);
260 for (const auto &Path
: From
.ProximityPaths
) {
261 llvm::SmallString
<256> RelativePath
= llvm::StringRef(Path
);
262 if (replace_path_prefix(RelativePath
, LocalIndexRoot
, ""))
263 RPCRequest
.add_proximity_paths(
264 convert_to_slash(RelativePath
, Style::windows
));
266 for (const auto &Type
: From
.PreferredTypes
)
267 RPCRequest
.add_preferred_types(Type
);
271 RefsRequest
Marshaller::toProtobuf(const clangd::RefsRequest
&From
) {
272 RefsRequest RPCRequest
;
273 for (const auto &ID
: From
.IDs
)
274 RPCRequest
.add_ids(ID
.str());
275 RPCRequest
.set_filter(static_cast<uint32_t>(From
.Filter
));
277 RPCRequest
.set_limit(*From
.Limit
);
278 RPCRequest
.set_want_container(From
.WantContainer
);
283 Marshaller::toProtobuf(const clangd::ContainedRefsRequest
&From
) {
284 ContainedRefsRequest RPCRequest
;
285 RPCRequest
.set_id(From
.ID
.str());
287 RPCRequest
.set_limit(*From
.Limit
);
291 RelationsRequest
Marshaller::toProtobuf(const clangd::RelationsRequest
&From
) {
292 RelationsRequest RPCRequest
;
293 for (const auto &ID
: From
.Subjects
)
294 RPCRequest
.add_subjects(ID
.str());
295 RPCRequest
.set_predicate(static_cast<uint32_t>(From
.Predicate
));
297 RPCRequest
.set_limit(*From
.Limit
);
301 llvm::Expected
<Symbol
> Marshaller::toProtobuf(const clangd::Symbol
&From
) {
303 Result
.set_id(From
.ID
.str());
304 *Result
.mutable_info() = toProtobuf(From
.SymInfo
);
305 Result
.set_name(From
.Name
.str());
306 if (*From
.Definition
.FileURI
) {
307 auto Definition
= toProtobuf(From
.Definition
);
309 return Definition
.takeError();
310 *Result
.mutable_definition() = *Definition
;
312 Result
.set_scope(From
.Scope
.str());
313 auto Declaration
= toProtobuf(From
.CanonicalDeclaration
);
315 return Declaration
.takeError();
316 *Result
.mutable_canonical_declaration() = *Declaration
;
317 Result
.set_references(From
.References
);
318 Result
.set_signature(From
.Signature
.str());
319 Result
.set_template_specialization_args(
320 From
.TemplateSpecializationArgs
.str());
321 Result
.set_completion_snippet_suffix(From
.CompletionSnippetSuffix
.str());
322 Result
.set_documentation(From
.Documentation
.str());
323 Result
.set_return_type(From
.ReturnType
.str());
324 Result
.set_type(From
.Type
.str());
325 for (const auto &Header
: From
.IncludeHeaders
) {
326 auto Serialized
= toProtobuf(Header
);
328 return Serialized
.takeError();
329 auto *NextHeader
= Result
.add_headers();
330 *NextHeader
= *Serialized
;
332 Result
.set_flags(static_cast<uint32_t>(From
.Flags
));
336 llvm::Expected
<Ref
> Marshaller::toProtobuf(const clangd::Ref
&From
) {
338 Result
.set_kind(static_cast<uint32_t>(From
.Kind
));
339 auto Location
= toProtobuf(From
.Location
);
341 return Location
.takeError();
342 *Result
.mutable_location() = *Location
;
346 llvm::Expected
<ContainedRef
>
347 Marshaller::toProtobuf(const clangd::ContainedRefsResult
&From
) {
349 auto Location
= toProtobuf(From
.Location
);
351 return Location
.takeError();
352 *Result
.mutable_location() = *Location
;
353 Result
.set_kind(static_cast<uint32_t>(From
.Kind
));
354 *Result
.mutable_symbol() = From
.Symbol
.str();
358 llvm::Expected
<Relation
> Marshaller::toProtobuf(const clangd::SymbolID
&Subject
,
359 const clangd::Symbol
&Object
) {
361 *Result
.mutable_subject_id() = Subject
.str();
362 auto SerializedObject
= toProtobuf(Object
);
363 if (!SerializedObject
)
364 return SerializedObject
.takeError();
365 *Result
.mutable_object() = *SerializedObject
;
369 llvm::Expected
<std::string
>
370 Marshaller::relativePathToURI(llvm::StringRef RelativePath
) {
371 assert(!LocalIndexRoot
.empty());
372 assert(RelativePath
== convert_to_slash(RelativePath
));
373 if (RelativePath
.empty())
374 return error("Empty relative path.");
375 if (is_absolute(RelativePath
, Style::posix
))
376 return error("RelativePath '{0}' is absolute.", RelativePath
);
377 llvm::SmallString
<256> FullPath
= llvm::StringRef(LocalIndexRoot
);
378 append(FullPath
, RelativePath
);
379 auto Result
= URI::createFile(FullPath
);
380 return Result
.toString();
383 llvm::Expected
<std::string
> Marshaller::uriToRelativePath(llvm::StringRef URI
) {
384 assert(!RemoteIndexRoot
.empty());
385 auto ParsedURI
= URI::parse(URI
);
387 return ParsedURI
.takeError();
388 if (ParsedURI
->scheme() != "file")
389 return error("Can not use URI schemes other than file, given: '{0}'.", URI
);
390 llvm::SmallString
<256> Result
= ParsedURI
->body();
391 llvm::StringRef
Path(Result
);
392 // Check for Windows paths (URI=file:///X:/path => Body=/X:/path)
393 if (is_absolute(Path
.substr(1), Style::windows
))
394 Result
= Path
.drop_front();
395 if (!replace_path_prefix(Result
, RemoteIndexRoot
, ""))
396 return error("File path '{0}' doesn't start with '{1}'.", Result
.str(),
398 assert(Result
== convert_to_slash(Result
, Style::windows
));
399 return std::string(Result
);
402 clangd::SymbolLocation::Position
403 Marshaller::fromProtobuf(const Position
&Message
) {
404 clangd::SymbolLocation::Position Result
;
405 Result
.setColumn(static_cast<uint32_t>(Message
.column()));
406 Result
.setLine(static_cast<uint32_t>(Message
.line()));
411 Marshaller::toProtobuf(const clangd::SymbolLocation::Position
&Position
) {
412 remote::Position Result
;
413 Result
.set_column(Position
.column());
414 Result
.set_line(Position
.line());
418 clang::index::SymbolInfo
Marshaller::fromProtobuf(const SymbolInfo
&Message
) {
419 clang::index::SymbolInfo Result
;
420 Result
.Kind
= static_cast<clang::index::SymbolKind
>(Message
.kind());
421 Result
.SubKind
= static_cast<clang::index::SymbolSubKind
>(Message
.subkind());
422 Result
.Lang
= static_cast<clang::index::SymbolLanguage
>(Message
.language());
424 static_cast<clang::index::SymbolPropertySet
>(Message
.properties());
428 SymbolInfo
Marshaller::toProtobuf(const clang::index::SymbolInfo
&Info
) {
430 Result
.set_kind(static_cast<uint32_t>(Info
.Kind
));
431 Result
.set_subkind(static_cast<uint32_t>(Info
.SubKind
));
432 Result
.set_language(static_cast<uint32_t>(Info
.Lang
));
433 Result
.set_properties(static_cast<uint32_t>(Info
.Properties
));
437 llvm::Expected
<clangd::SymbolLocation
>
438 Marshaller::fromProtobuf(const SymbolLocation
&Message
) {
439 clangd::SymbolLocation Location
;
440 auto URIString
= relativePathToURI(Message
.file_path());
442 return URIString
.takeError();
443 Location
.FileURI
= Strings
.save(*URIString
).begin();
444 Location
.Start
= fromProtobuf(Message
.start());
445 Location
.End
= fromProtobuf(Message
.end());
449 llvm::Expected
<SymbolLocation
>
450 Marshaller::toProtobuf(const clangd::SymbolLocation
&Location
) {
451 remote::SymbolLocation Result
;
452 auto RelativePath
= uriToRelativePath(Location
.FileURI
);
454 return RelativePath
.takeError();
455 *Result
.mutable_file_path() = *RelativePath
;
456 *Result
.mutable_start() = toProtobuf(Location
.Start
);
457 *Result
.mutable_end() = toProtobuf(Location
.End
);
461 llvm::Expected
<HeaderWithReferences
> Marshaller::toProtobuf(
462 const clangd::Symbol::IncludeHeaderWithReferences
&IncludeHeader
) {
463 HeaderWithReferences Result
;
464 Result
.set_references(IncludeHeader
.References
);
465 Result
.set_supported_directives(IncludeHeader
.SupportedDirectives
);
466 const std::string Header
= IncludeHeader
.IncludeHeader
.str();
467 if (isLiteralInclude(Header
)) {
468 Result
.set_header(Header
);
471 auto RelativePath
= uriToRelativePath(Header
);
473 return RelativePath
.takeError();
474 Result
.set_header(*RelativePath
);
478 llvm::Expected
<clangd::Symbol::IncludeHeaderWithReferences
>
479 Marshaller::fromProtobuf(const HeaderWithReferences
&Message
) {
480 std::string Header
= Message
.header();
481 if (!isLiteralInclude(Header
)) {
482 auto URIString
= relativePathToURI(Header
);
484 return URIString
.takeError();
487 auto Directives
= clangd::Symbol::IncludeDirective::Include
;
488 if (Message
.has_supported_directives())
489 Directives
= static_cast<clangd::Symbol::IncludeDirective
>(
490 Message
.supported_directives());
491 return clangd::Symbol::IncludeHeaderWithReferences
{
492 Strings
.save(Header
), Message
.references(), Directives
};
495 } // namespace remote
496 } // namespace clangd