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" |
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" |
30 | |
31 | namespace clang { |
32 | namespace clangd { |
33 | namespace remote { |
34 | |
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; |
40 | |
41 | namespace { |
42 | |
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)); |
48 | if (!SID) |
49 | return SID.takeError(); |
50 | Result.insert(V: *SID); |
51 | } |
52 | return Result; |
53 | } |
54 | |
55 | } // namespace |
56 | |
57 | Marshaller::Marshaller(llvm::StringRef RemoteIndexRoot, |
58 | llvm::StringRef LocalIndexRoot) |
59 | : Strings(Arena) { |
60 | llvm::StringRef PosixSeparator = get_separator(style: Style::posix); |
61 | if (!RemoteIndexRoot.empty()) { |
62 | assert(is_absolute(RemoteIndexRoot)); |
63 | this->RemoteIndexRoot = convert_to_slash(path: RemoteIndexRoot, style: Style::windows); |
64 | llvm::StringRef Path(this->RemoteIndexRoot); |
65 | if (!is_separator(value: this->RemoteIndexRoot.back(), style: Style::posix)) |
66 | this->RemoteIndexRoot += PosixSeparator; |
67 | } |
68 | if (!LocalIndexRoot.empty()) { |
69 | assert(is_absolute(LocalIndexRoot)); |
70 | this->LocalIndexRoot = convert_to_slash(path: LocalIndexRoot, style: Style::windows); |
71 | llvm::StringRef Path(this->LocalIndexRoot); |
72 | if (!is_separator(value: this->LocalIndexRoot.back(), style: Style::posix)) |
73 | this->LocalIndexRoot += PosixSeparator; |
74 | } |
75 | assert(!RemoteIndexRoot.empty() || !LocalIndexRoot.empty()); |
76 | } |
77 | |
78 | llvm::Expected<clangd::LookupRequest> |
79 | Marshaller::fromProtobuf(const LookupRequest *Message) { |
80 | clangd::LookupRequest Req; |
81 | auto IDs = getIDs(Message->ids()); |
82 | if (!IDs) |
83 | return IDs.takeError(); |
84 | Req.IDs = std::move(*IDs); |
85 | return Req; |
86 | } |
87 | |
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(); |
96 | if (Message->limit()) |
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)); |
106 | } |
107 | for (const auto &Type : Message->preferred_types()) |
108 | Result.ProximityPaths.push_back(Type); |
109 | return Result; |
110 | } |
111 | |
112 | llvm::Expected<clangd::RefsRequest> |
113 | Marshaller::fromProtobuf(const RefsRequest *Message) { |
114 | clangd::RefsRequest Req; |
115 | auto IDs = getIDs(Message->ids()); |
116 | if (!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()); |
121 | else |
122 | Req.Filter = clangd::RefKind::All; |
123 | if (Message->limit()) |
124 | Req.Limit = Message->limit(); |
125 | Req.WantContainer = Message->want_container(); |
126 | return Req; |
127 | } |
128 | |
129 | llvm::Expected<clangd::RelationsRequest> |
130 | Marshaller::fromProtobuf(const RelationsRequest *Message) { |
131 | clangd::RelationsRequest Req; |
132 | auto IDs = getIDs(Message->subjects()); |
133 | if (!IDs) |
134 | return IDs.takeError(); |
135 | Req.Subjects = std::move(*IDs); |
136 | if (!Message->has_predicate()) |
137 | return error(Fmt: "RelationsRequest requires RelationKind predicate." ); |
138 | Req.Predicate = static_cast<RelationKind>(Message->predicate()); |
139 | if (Message->limit()) |
140 | Req.Limit = Message->limit(); |
141 | return Req; |
142 | } |
143 | |
144 | llvm::Expected<clangd::Symbol> Marshaller::fromProtobuf(const Symbol &Message) { |
145 | if (!Message.has_info() || !Message.has_canonical_declaration()) |
146 | return error(Fmt: "Missing info or declaration." ); |
147 | clangd::Symbol Result; |
148 | auto ID = SymbolID::fromStr(Message.id()); |
149 | if (!ID) |
150 | return ID.takeError(); |
151 | Result.ID = *ID; |
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()); |
157 | if (Definition) |
158 | Result.Definition = *Definition; |
159 | } |
160 | auto Declaration = fromProtobuf(Message.canonical_declaration()); |
161 | if (!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); |
178 | } |
179 | Result.Flags = static_cast<clangd::Symbol::SymbolFlag>(Message.flags()); |
180 | return Result; |
181 | } |
182 | |
183 | llvm::Expected<clangd::Ref> Marshaller::fromProtobuf(const Ref &Message) { |
184 | if (!Message.has_location()) |
185 | return error(Fmt: "Missing location." ); |
186 | clangd::Ref Result; |
187 | auto Location = fromProtobuf(Message.location()); |
188 | if (!Location) |
189 | return Location.takeError(); |
190 | Result.Location = *Location; |
191 | Result.Kind = static_cast<RefKind>(Message.kind()); |
192 | return Result; |
193 | } |
194 | |
195 | llvm::Expected<std::pair<clangd::SymbolID, clangd::Symbol>> |
196 | Marshaller::fromProtobuf(const Relation &Message) { |
197 | auto SubjectID = SymbolID::fromStr(Message.subject_id()); |
198 | if (!SubjectID) |
199 | return SubjectID.takeError(); |
200 | if (!Message.has_object()) |
201 | return error(Fmt: "Missing Object." ); |
202 | auto Object = fromProtobuf(Message.object()); |
203 | if (!Object) |
204 | return Object.takeError(); |
205 | return std::make_pair(*SubjectID, *Object); |
206 | } |
207 | |
208 | LookupRequest Marshaller::toProtobuf(const clangd::LookupRequest &From) { |
209 | LookupRequest RPCRequest; |
210 | for (const auto &SymbolID : From.IDs) |
211 | RPCRequest.add_ids(SymbolID.str()); |
212 | return RPCRequest; |
213 | } |
214 | |
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); |
222 | if (From.Limit) |
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(Path&: RelativePath, OldPrefix: LocalIndexRoot, NewPrefix: "" )) |
228 | RPCRequest.add_proximity_paths( |
229 | convert_to_slash(path: RelativePath, style: Style::windows)); |
230 | } |
231 | for (const auto &Type : From.PreferredTypes) |
232 | RPCRequest.add_preferred_types(Type); |
233 | return RPCRequest; |
234 | } |
235 | |
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)); |
241 | if (From.Limit) |
242 | RPCRequest.set_limit(*From.Limit); |
243 | RPCRequest.set_want_container(From.WantContainer); |
244 | return RPCRequest; |
245 | } |
246 | |
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)); |
252 | if (From.Limit) |
253 | RPCRequest.set_limit(*From.Limit); |
254 | return RPCRequest; |
255 | } |
256 | |
257 | llvm::Expected<Symbol> Marshaller::toProtobuf(const clangd::Symbol &From) { |
258 | Symbol Result; |
259 | Result.set_id(From.ID.str()); |
260 | *Result.mutable_info() = toProtobuf(Info: From.SymInfo); |
261 | Result.set_name(From.Name.str()); |
262 | if (*From.Definition.FileURI) { |
263 | auto Definition = toProtobuf(Location: From.Definition); |
264 | if (!Definition) |
265 | return Definition.takeError(); |
266 | *Result.mutable_definition() = *Definition; |
267 | } |
268 | Result.set_scope(From.Scope.str()); |
269 | auto Declaration = toProtobuf(Location: From.CanonicalDeclaration); |
270 | if (!Declaration) |
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 & : From.IncludeHeaders) { |
282 | auto Serialized = toProtobuf(Header); |
283 | if (!Serialized) |
284 | return Serialized.takeError(); |
285 | auto * = Result.add_headers(); |
286 | *NextHeader = *Serialized; |
287 | } |
288 | Result.set_flags(static_cast<uint32_t>(From.Flags)); |
289 | return Result; |
290 | } |
291 | |
292 | llvm::Expected<Ref> Marshaller::toProtobuf(const clangd::Ref &From) { |
293 | Ref Result; |
294 | Result.set_kind(static_cast<uint32_t>(From.Kind)); |
295 | auto Location = toProtobuf(Location: From.Location); |
296 | if (!Location) |
297 | return Location.takeError(); |
298 | *Result.mutable_location() = *Location; |
299 | return Result; |
300 | } |
301 | |
302 | llvm::Expected<Relation> Marshaller::toProtobuf(const clangd::SymbolID &Subject, |
303 | const clangd::Symbol &Object) { |
304 | Relation Result; |
305 | *Result.mutable_subject_id() = Subject.str(); |
306 | auto SerializedObject = toProtobuf(From: Object); |
307 | if (!SerializedObject) |
308 | return SerializedObject.takeError(); |
309 | *Result.mutable_object() = *SerializedObject; |
310 | return Result; |
311 | } |
312 | |
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(Fmt: "Empty relative path." ); |
319 | if (is_absolute(path: RelativePath, style: Style::posix)) |
320 | return error(Fmt: "RelativePath '{0}' is absolute." , Vals&: RelativePath); |
321 | llvm::SmallString<256> FullPath = llvm::StringRef(LocalIndexRoot); |
322 | append(path&: FullPath, a: RelativePath); |
323 | auto Result = URI::createFile(AbsolutePath: FullPath); |
324 | return Result.toString(); |
325 | } |
326 | |
327 | llvm::Expected<std::string> Marshaller::uriToRelativePath(llvm::StringRef URI) { |
328 | assert(!RemoteIndexRoot.empty()); |
329 | auto ParsedURI = URI::parse(Uri: URI); |
330 | if (!ParsedURI) |
331 | return ParsedURI.takeError(); |
332 | if (ParsedURI->scheme() != "file" ) |
333 | return error(Fmt: "Can not use URI schemes other than file, given: '{0}'." , Vals&: 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: Path.substr(Start: 1), style: Style::windows)) |
338 | Result = Path.drop_front(); |
339 | if (!replace_path_prefix(Path&: Result, OldPrefix: RemoteIndexRoot, NewPrefix: "" )) |
340 | return error(Fmt: "File path '{0}' doesn't start with '{1}'." , Vals: Result.str(), |
341 | Vals&: RemoteIndexRoot); |
342 | assert(Result == convert_to_slash(Result, Style::windows)); |
343 | return std::string(Result); |
344 | } |
345 | |
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())); |
351 | return Result; |
352 | } |
353 | |
354 | Position |
355 | Marshaller::toProtobuf(const clangd::SymbolLocation::Position &Position) { |
356 | remote::Position Result; |
357 | Result.set_column(Position.column()); |
358 | Result.set_line(Position.line()); |
359 | return Result; |
360 | } |
361 | |
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()); |
367 | Result.Properties = |
368 | static_cast<clang::index::SymbolPropertySet>(Message.properties()); |
369 | return Result; |
370 | } |
371 | |
372 | SymbolInfo Marshaller::toProtobuf(const clang::index::SymbolInfo &Info) { |
373 | SymbolInfo Result; |
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)); |
378 | return Result; |
379 | } |
380 | |
381 | llvm::Expected<clangd::SymbolLocation> |
382 | Marshaller::fromProtobuf(const SymbolLocation &Message) { |
383 | clangd::SymbolLocation Location; |
384 | auto URIString = relativePathToURI(RelativePath: Message.file_path()); |
385 | if (!URIString) |
386 | return URIString.takeError(); |
387 | Location.FileURI = Strings.save(*URIString).begin(); |
388 | Location.Start = fromProtobuf(Message.start()); |
389 | Location.End = fromProtobuf(Message.end()); |
390 | return Location; |
391 | } |
392 | |
393 | llvm::Expected<SymbolLocation> |
394 | Marshaller::toProtobuf(const clangd::SymbolLocation &Location) { |
395 | remote::SymbolLocation Result; |
396 | auto RelativePath = uriToRelativePath(URI: Location.FileURI); |
397 | if (!RelativePath) |
398 | return RelativePath.takeError(); |
399 | *Result.mutable_file_path() = *RelativePath; |
400 | *Result.mutable_start() = toProtobuf(Position: Location.Start); |
401 | *Result.mutable_end() = toProtobuf(Position: Location.End); |
402 | return Result; |
403 | } |
404 | |
405 | llvm::Expected<HeaderWithReferences> Marshaller::( |
406 | const clangd::Symbol::IncludeHeaderWithReferences &) { |
407 | HeaderWithReferences Result; |
408 | Result.set_references(IncludeHeader.References); |
409 | Result.set_supported_directives(IncludeHeader.SupportedDirectives); |
410 | const std::string = IncludeHeader.IncludeHeader.str(); |
411 | if (isLiteralInclude(Include: Header)) { |
412 | Result.set_header(Header); |
413 | return Result; |
414 | } |
415 | auto RelativePath = uriToRelativePath(URI: Header); |
416 | if (!RelativePath) |
417 | return RelativePath.takeError(); |
418 | Result.set_header(*RelativePath); |
419 | return Result; |
420 | } |
421 | |
422 | llvm::Expected<clangd::Symbol::IncludeHeaderWithReferences> |
423 | Marshaller::fromProtobuf(const HeaderWithReferences &Message) { |
424 | std::string = Message.header(); |
425 | if (!isLiteralInclude(Include: Header)) { |
426 | auto URIString = relativePathToURI(RelativePath: Header); |
427 | if (!URIString) |
428 | return URIString.takeError(); |
429 | Header = *URIString; |
430 | } |
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(S: Header), Message.references(), Directives}; |
437 | } |
438 | |
439 | } // namespace remote |
440 | } // namespace clangd |
441 | } // namespace clang |
442 | |