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::RelationsRequest
>
130 Marshaller::fromProtobuf(const RelationsRequest
*Message
) {
131 clangd::RelationsRequest Req
;
132 auto IDs
= getIDs(Message
->subjects());
134 return IDs
.takeError();
135 Req
.Subjects
= std::move(*IDs
);
136 if (!Message
->has_predicate())
137 return error("RelationsRequest requires RelationKind predicate.");
138 Req
.Predicate
= static_cast<RelationKind
>(Message
->predicate());
139 if (Message
->limit())
140 Req
.Limit
= Message
->limit();
144 llvm::Expected
<clangd::Symbol
> Marshaller::fromProtobuf(const Symbol
&Message
) {
145 if (!Message
.has_info() || !Message
.has_canonical_declaration())
146 return error("Missing info or declaration.");
147 clangd::Symbol Result
;
148 auto ID
= SymbolID::fromStr(Message
.id());
150 return ID
.takeError();
152 Result
.SymInfo
= fromProtobuf(Message
.info());
153 Result
.Name
= Message
.name();
154 Result
.Scope
= Message
.scope();
155 if (Message
.has_definition()) {
156 auto Definition
= fromProtobuf(Message
.definition());
158 Result
.Definition
= *Definition
;
160 auto Declaration
= fromProtobuf(Message
.canonical_declaration());
162 return Declaration
.takeError();
163 Result
.CanonicalDeclaration
= *Declaration
;
164 Result
.References
= Message
.references();
165 // Overwrite symbol origin: it's coming from remote index.
166 Result
.Origin
= clangd::SymbolOrigin::Remote
;
167 Result
.Signature
= Message
.signature();
168 Result
.TemplateSpecializationArgs
= Message
.template_specialization_args();
169 Result
.CompletionSnippetSuffix
= Message
.completion_snippet_suffix();
170 Result
.Documentation
= Message
.documentation();
171 Result
.ReturnType
= Message
.return_type();
172 Result
.Type
= Message
.type();
173 for (const auto &Header
: Message
.headers()) {
174 auto SerializedHeader
= fromProtobuf(Header
);
175 if (!SerializedHeader
)
176 return SerializedHeader
.takeError();
177 Result
.IncludeHeaders
.push_back(*SerializedHeader
);
179 Result
.Flags
= static_cast<clangd::Symbol::SymbolFlag
>(Message
.flags());
183 llvm::Expected
<clangd::Ref
> Marshaller::fromProtobuf(const Ref
&Message
) {
184 if (!Message
.has_location())
185 return error("Missing location.");
187 auto Location
= fromProtobuf(Message
.location());
189 return Location
.takeError();
190 Result
.Location
= *Location
;
191 Result
.Kind
= static_cast<RefKind
>(Message
.kind());
195 llvm::Expected
<std::pair
<clangd::SymbolID
, clangd::Symbol
>>
196 Marshaller::fromProtobuf(const Relation
&Message
) {
197 auto SubjectID
= SymbolID::fromStr(Message
.subject_id());
199 return SubjectID
.takeError();
200 if (!Message
.has_object())
201 return error("Missing Object.");
202 auto Object
= fromProtobuf(Message
.object());
204 return Object
.takeError();
205 return std::make_pair(*SubjectID
, *Object
);
208 LookupRequest
Marshaller::toProtobuf(const clangd::LookupRequest
&From
) {
209 LookupRequest RPCRequest
;
210 for (const auto &SymbolID
: From
.IDs
)
211 RPCRequest
.add_ids(SymbolID
.str());
215 FuzzyFindRequest
Marshaller::toProtobuf(const clangd::FuzzyFindRequest
&From
) {
216 assert(!LocalIndexRoot
.empty());
217 FuzzyFindRequest RPCRequest
;
218 RPCRequest
.set_query(From
.Query
);
219 for (const auto &Scope
: From
.Scopes
)
220 RPCRequest
.add_scopes(Scope
);
221 RPCRequest
.set_any_scope(From
.AnyScope
);
223 RPCRequest
.set_limit(*From
.Limit
);
224 RPCRequest
.set_restricted_for_code_completion(From
.RestrictForCodeCompletion
);
225 for (const auto &Path
: From
.ProximityPaths
) {
226 llvm::SmallString
<256> RelativePath
= llvm::StringRef(Path
);
227 if (replace_path_prefix(RelativePath
, LocalIndexRoot
, ""))
228 RPCRequest
.add_proximity_paths(
229 convert_to_slash(RelativePath
, Style::windows
));
231 for (const auto &Type
: From
.PreferredTypes
)
232 RPCRequest
.add_preferred_types(Type
);
236 RefsRequest
Marshaller::toProtobuf(const clangd::RefsRequest
&From
) {
237 RefsRequest RPCRequest
;
238 for (const auto &ID
: From
.IDs
)
239 RPCRequest
.add_ids(ID
.str());
240 RPCRequest
.set_filter(static_cast<uint32_t>(From
.Filter
));
242 RPCRequest
.set_limit(*From
.Limit
);
243 RPCRequest
.set_want_container(From
.WantContainer
);
247 RelationsRequest
Marshaller::toProtobuf(const clangd::RelationsRequest
&From
) {
248 RelationsRequest RPCRequest
;
249 for (const auto &ID
: From
.Subjects
)
250 RPCRequest
.add_subjects(ID
.str());
251 RPCRequest
.set_predicate(static_cast<uint32_t>(From
.Predicate
));
253 RPCRequest
.set_limit(*From
.Limit
);
257 llvm::Expected
<Symbol
> Marshaller::toProtobuf(const clangd::Symbol
&From
) {
259 Result
.set_id(From
.ID
.str());
260 *Result
.mutable_info() = toProtobuf(From
.SymInfo
);
261 Result
.set_name(From
.Name
.str());
262 if (*From
.Definition
.FileURI
) {
263 auto Definition
= toProtobuf(From
.Definition
);
265 return Definition
.takeError();
266 *Result
.mutable_definition() = *Definition
;
268 Result
.set_scope(From
.Scope
.str());
269 auto Declaration
= toProtobuf(From
.CanonicalDeclaration
);
271 return Declaration
.takeError();
272 *Result
.mutable_canonical_declaration() = *Declaration
;
273 Result
.set_references(From
.References
);
274 Result
.set_signature(From
.Signature
.str());
275 Result
.set_template_specialization_args(
276 From
.TemplateSpecializationArgs
.str());
277 Result
.set_completion_snippet_suffix(From
.CompletionSnippetSuffix
.str());
278 Result
.set_documentation(From
.Documentation
.str());
279 Result
.set_return_type(From
.ReturnType
.str());
280 Result
.set_type(From
.Type
.str());
281 for (const auto &Header
: From
.IncludeHeaders
) {
282 auto Serialized
= toProtobuf(Header
);
284 return Serialized
.takeError();
285 auto *NextHeader
= Result
.add_headers();
286 *NextHeader
= *Serialized
;
288 Result
.set_flags(static_cast<uint32_t>(From
.Flags
));
292 llvm::Expected
<Ref
> Marshaller::toProtobuf(const clangd::Ref
&From
) {
294 Result
.set_kind(static_cast<uint32_t>(From
.Kind
));
295 auto Location
= toProtobuf(From
.Location
);
297 return Location
.takeError();
298 *Result
.mutable_location() = *Location
;
302 llvm::Expected
<Relation
> Marshaller::toProtobuf(const clangd::SymbolID
&Subject
,
303 const clangd::Symbol
&Object
) {
305 *Result
.mutable_subject_id() = Subject
.str();
306 auto SerializedObject
= toProtobuf(Object
);
307 if (!SerializedObject
)
308 return SerializedObject
.takeError();
309 *Result
.mutable_object() = *SerializedObject
;
313 llvm::Expected
<std::string
>
314 Marshaller::relativePathToURI(llvm::StringRef RelativePath
) {
315 assert(!LocalIndexRoot
.empty());
316 assert(RelativePath
== convert_to_slash(RelativePath
));
317 if (RelativePath
.empty())
318 return error("Empty relative path.");
319 if (is_absolute(RelativePath
, Style::posix
))
320 return error("RelativePath '{0}' is absolute.", RelativePath
);
321 llvm::SmallString
<256> FullPath
= llvm::StringRef(LocalIndexRoot
);
322 append(FullPath
, RelativePath
);
323 auto Result
= URI::createFile(FullPath
);
324 return Result
.toString();
327 llvm::Expected
<std::string
> Marshaller::uriToRelativePath(llvm::StringRef URI
) {
328 assert(!RemoteIndexRoot
.empty());
329 auto ParsedURI
= URI::parse(URI
);
331 return ParsedURI
.takeError();
332 if (ParsedURI
->scheme() != "file")
333 return error("Can not use URI schemes other than file, given: '{0}'.", URI
);
334 llvm::SmallString
<256> Result
= ParsedURI
->body();
335 llvm::StringRef
Path(Result
);
336 // Check for Windows paths (URI=file:///X:/path => Body=/X:/path)
337 if (is_absolute(Path
.substr(1), Style::windows
))
338 Result
= Path
.drop_front();
339 if (!replace_path_prefix(Result
, RemoteIndexRoot
, ""))
340 return error("File path '{0}' doesn't start with '{1}'.", Result
.str(),
342 assert(Result
== convert_to_slash(Result
, Style::windows
));
343 return std::string(Result
);
346 clangd::SymbolLocation::Position
347 Marshaller::fromProtobuf(const Position
&Message
) {
348 clangd::SymbolLocation::Position Result
;
349 Result
.setColumn(static_cast<uint32_t>(Message
.column()));
350 Result
.setLine(static_cast<uint32_t>(Message
.line()));
355 Marshaller::toProtobuf(const clangd::SymbolLocation::Position
&Position
) {
356 remote::Position Result
;
357 Result
.set_column(Position
.column());
358 Result
.set_line(Position
.line());
362 clang::index::SymbolInfo
Marshaller::fromProtobuf(const SymbolInfo
&Message
) {
363 clang::index::SymbolInfo Result
;
364 Result
.Kind
= static_cast<clang::index::SymbolKind
>(Message
.kind());
365 Result
.SubKind
= static_cast<clang::index::SymbolSubKind
>(Message
.subkind());
366 Result
.Lang
= static_cast<clang::index::SymbolLanguage
>(Message
.language());
368 static_cast<clang::index::SymbolPropertySet
>(Message
.properties());
372 SymbolInfo
Marshaller::toProtobuf(const clang::index::SymbolInfo
&Info
) {
374 Result
.set_kind(static_cast<uint32_t>(Info
.Kind
));
375 Result
.set_subkind(static_cast<uint32_t>(Info
.SubKind
));
376 Result
.set_language(static_cast<uint32_t>(Info
.Lang
));
377 Result
.set_properties(static_cast<uint32_t>(Info
.Properties
));
381 llvm::Expected
<clangd::SymbolLocation
>
382 Marshaller::fromProtobuf(const SymbolLocation
&Message
) {
383 clangd::SymbolLocation Location
;
384 auto URIString
= relativePathToURI(Message
.file_path());
386 return URIString
.takeError();
387 Location
.FileURI
= Strings
.save(*URIString
).begin();
388 Location
.Start
= fromProtobuf(Message
.start());
389 Location
.End
= fromProtobuf(Message
.end());
393 llvm::Expected
<SymbolLocation
>
394 Marshaller::toProtobuf(const clangd::SymbolLocation
&Location
) {
395 remote::SymbolLocation Result
;
396 auto RelativePath
= uriToRelativePath(Location
.FileURI
);
398 return RelativePath
.takeError();
399 *Result
.mutable_file_path() = *RelativePath
;
400 *Result
.mutable_start() = toProtobuf(Location
.Start
);
401 *Result
.mutable_end() = toProtobuf(Location
.End
);
405 llvm::Expected
<HeaderWithReferences
> Marshaller::toProtobuf(
406 const clangd::Symbol::IncludeHeaderWithReferences
&IncludeHeader
) {
407 HeaderWithReferences Result
;
408 Result
.set_references(IncludeHeader
.References
);
409 Result
.set_supported_directives(IncludeHeader
.SupportedDirectives
);
410 const std::string Header
= IncludeHeader
.IncludeHeader
.str();
411 if (isLiteralInclude(Header
)) {
412 Result
.set_header(Header
);
415 auto RelativePath
= uriToRelativePath(Header
);
417 return RelativePath
.takeError();
418 Result
.set_header(*RelativePath
);
422 llvm::Expected
<clangd::Symbol::IncludeHeaderWithReferences
>
423 Marshaller::fromProtobuf(const HeaderWithReferences
&Message
) {
424 std::string Header
= Message
.header();
425 if (!isLiteralInclude(Header
)) {
426 auto URIString
= relativePathToURI(Header
);
428 return URIString
.takeError();
431 auto Directives
= clangd::Symbol::IncludeDirective::Include
;
432 if (Message
.has_supported_directives())
433 Directives
= static_cast<clangd::Symbol::IncludeDirective
>(
434 Message
.supported_directives());
435 return clangd::Symbol::IncludeHeaderWithReferences
{
436 Strings
.save(Header
), Message
.references(), Directives
};
439 } // namespace remote
440 } // namespace clangd