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