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>
getIDs(IDRange IDs)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(*SID);
51   }
52   return Result;
53 }
54 
55 } // namespace
56 
Marshaller(llvm::StringRef RemoteIndexRoot,llvm::StringRef LocalIndexRoot)57 Marshaller::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));
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;
67   }
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;
74   }
75   assert(!RemoteIndexRoot.empty() || !LocalIndexRoot.empty());
76 }
77 
78 llvm::Expected<clangd::LookupRequest>
fromProtobuf(const LookupRequest * Message)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>
fromProtobuf(const FuzzyFindRequest * Message)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>
fromProtobuf(const RefsRequest * Message)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>
fromProtobuf(const RelationsRequest * Message)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("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 
fromProtobuf(const Symbol & Message)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());
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 
fromProtobuf(const Ref & Message)183 llvm::Expected<clangd::Ref> Marshaller::fromProtobuf(const Ref &Message) {
184   if (!Message.has_location())
185     return error("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>>
fromProtobuf(const Relation & Message)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("Missing Object.");
202   auto Object = fromProtobuf(Message.object());
203   if (!Object)
204     return Object.takeError();
205   return std::make_pair(*SubjectID, *Object);
206 }
207 
toProtobuf(const clangd::LookupRequest & From)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 
toProtobuf(const clangd::FuzzyFindRequest & From)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(RelativePath, LocalIndexRoot, ""))
228       RPCRequest.add_proximity_paths(
229           convert_to_slash(RelativePath, Style::windows));
230   }
231   for (const auto &Type : From.PreferredTypes)
232     RPCRequest.add_preferred_types(Type);
233   return RPCRequest;
234 }
235 
toProtobuf(const clangd::RefsRequest & From)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 
toProtobuf(const clangd::RelationsRequest & From)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 
toProtobuf(const clangd::Symbol & From)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(From.SymInfo);
261   Result.set_name(From.Name.str());
262   if (*From.Definition.FileURI) {
263     auto Definition = toProtobuf(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(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 &Header : From.IncludeHeaders) {
282     auto Serialized = toProtobuf(Header);
283     if (!Serialized)
284       return Serialized.takeError();
285     auto *NextHeader = Result.add_headers();
286     *NextHeader = *Serialized;
287   }
288   Result.set_flags(static_cast<uint32_t>(From.Flags));
289   return Result;
290 }
291 
toProtobuf(const clangd::Ref & From)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(From.Location);
296   if (!Location)
297     return Location.takeError();
298   *Result.mutable_location() = *Location;
299   return Result;
300 }
301 
toProtobuf(const clangd::SymbolID & Subject,const clangd::Symbol & Object)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(Object);
307   if (!SerializedObject)
308     return SerializedObject.takeError();
309   *Result.mutable_object() = *SerializedObject;
310   return Result;
311 }
312 
313 llvm::Expected<std::string>
relativePathToURI(llvm::StringRef RelativePath)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();
325 }
326 
uriToRelativePath(llvm::StringRef URI)327 llvm::Expected<std::string> Marshaller::uriToRelativePath(llvm::StringRef URI) {
328   assert(!RemoteIndexRoot.empty());
329   auto ParsedURI = URI::parse(URI);
330   if (!ParsedURI)
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(),
341                  RemoteIndexRoot);
342   assert(Result == convert_to_slash(Result, Style::windows));
343   return std::string(Result);
344 }
345 
346 clangd::SymbolLocation::Position
fromProtobuf(const Position & Message)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
toProtobuf(const clangd::SymbolLocation::Position & 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 
fromProtobuf(const SymbolInfo & Message)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 
toProtobuf(const clang::index::SymbolInfo & Info)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>
fromProtobuf(const SymbolLocation & Message)382 Marshaller::fromProtobuf(const SymbolLocation &Message) {
383   clangd::SymbolLocation Location;
384   auto URIString = relativePathToURI(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>
toProtobuf(const clangd::SymbolLocation & Location)394 Marshaller::toProtobuf(const clangd::SymbolLocation &Location) {
395   remote::SymbolLocation Result;
396   auto RelativePath = uriToRelativePath(Location.FileURI);
397   if (!RelativePath)
398     return RelativePath.takeError();
399   *Result.mutable_file_path() = *RelativePath;
400   *Result.mutable_start() = toProtobuf(Location.Start);
401   *Result.mutable_end() = toProtobuf(Location.End);
402   return Result;
403 }
404 
toProtobuf(const clangd::Symbol::IncludeHeaderWithReferences & IncludeHeader)405 llvm::Expected<HeaderWithReferences> Marshaller::toProtobuf(
406     const clangd::Symbol::IncludeHeaderWithReferences &IncludeHeader) {
407   HeaderWithReferences Result;
408   Result.set_references(IncludeHeader.References);
409   const std::string Header = IncludeHeader.IncludeHeader.str();
410   if (isLiteralInclude(Header)) {
411     Result.set_header(Header);
412     return Result;
413   }
414   auto RelativePath = uriToRelativePath(Header);
415   if (!RelativePath)
416     return RelativePath.takeError();
417   Result.set_header(*RelativePath);
418   return Result;
419 }
420 
421 llvm::Expected<clangd::Symbol::IncludeHeaderWithReferences>
fromProtobuf(const HeaderWithReferences & Message)422 Marshaller::fromProtobuf(const HeaderWithReferences &Message) {
423   std::string Header = Message.header();
424   if (!isLiteralInclude(Header)) {
425     auto URIString = relativePathToURI(Header);
426     if (!URIString)
427       return URIString.takeError();
428     Header = *URIString;
429   }
430   return clangd::Symbol::IncludeHeaderWithReferences{Strings.save(Header),
431                                                      Message.references()};
432 }
433 
434 } // namespace remote
435 } // namespace clangd
436 } // namespace clang
437