clang-tools  11.0.0
Marshalling.cpp
Go to the documentation of this file.
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/Serialization.h"
14 #include "index/Symbol.h"
15 #include "index/SymbolID.h"
16 #include "index/SymbolLocation.h"
17 #include "index/SymbolOrigin.h"
18 #include "support/Logger.h"
19 #include "clang/Index/IndexSymbol.h"
20 #include "llvm/ADT/None.h"
21 #include "llvm/ADT/Optional.h"
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/Error.h"
26 #include "llvm/Support/Path.h"
27 #include "llvm/Support/StringSaver.h"
28 
29 namespace clang {
30 namespace clangd {
31 namespace remote {
32 
33 namespace {
34 
35 clangd::SymbolLocation::Position fromProtobuf(const Position &Message) {
36  clangd::SymbolLocation::Position Result;
37  Result.setColumn(static_cast<uint32_t>(Message.column()));
38  Result.setLine(static_cast<uint32_t>(Message.line()));
39  return Result;
40 }
41 
42 Position toProtobuf(const clangd::SymbolLocation::Position &Position) {
43  remote::Position Result;
44  Result.set_column(Position.column());
45  Result.set_line(Position.line());
46  return Result;
47 }
48 
51  Result.Kind = static_cast<clang::index::SymbolKind>(Message.kind());
52  Result.SubKind = static_cast<clang::index::SymbolSubKind>(Message.subkind());
53  Result.Lang = static_cast<clang::index::SymbolLanguage>(Message.language());
54  Result.Properties =
55  static_cast<clang::index::SymbolPropertySet>(Message.properties());
56  return Result;
57 }
58 
60  SymbolInfo Result;
61  Result.set_kind(static_cast<uint32_t>(Info.Kind));
62  Result.set_subkind(static_cast<uint32_t>(Info.SubKind));
63  Result.set_language(static_cast<uint32_t>(Info.Lang));
64  Result.set_properties(static_cast<uint32_t>(Info.Properties));
65  return Result;
66 }
67 
68 llvm::Optional<clangd::SymbolLocation>
69 fromProtobuf(const SymbolLocation &Message, llvm::UniqueStringSaver *Strings,
70  llvm::StringRef IndexRoot) {
71  clangd::SymbolLocation Location;
72  auto URIString = relativePathToURI(Message.file_path(), IndexRoot);
73  if (!URIString)
74  return llvm::None;
75  Location.FileURI = Strings->save(*URIString).begin();
76  Location.Start = fromProtobuf(Message.start());
77  Location.End = fromProtobuf(Message.end());
78  return Location;
79 }
80 
81 llvm::Optional<SymbolLocation>
82 toProtobuf(const clangd::SymbolLocation &Location, llvm::StringRef IndexRoot) {
83  remote::SymbolLocation Result;
84  auto RelativePath = uriToRelativePath(Location.FileURI, IndexRoot);
85  if (!RelativePath)
86  return llvm::None;
87  *Result.mutable_file_path() = *RelativePath;
88  *Result.mutable_start() = toProtobuf(Location.Start);
89  *Result.mutable_end() = toProtobuf(Location.End);
90  return Result;
91 }
92 
93 llvm::Optional<HeaderWithReferences>
94 toProtobuf(const clangd::Symbol::IncludeHeaderWithReferences &IncludeHeader,
95  llvm::StringRef IndexRoot) {
96  HeaderWithReferences Result;
97  Result.set_references(IncludeHeader.References);
98  const std::string Header = IncludeHeader.IncludeHeader.str();
99  if (isLiteralInclude(Header)) {
100  Result.set_header(Header);
101  return Result;
102  }
103  auto RelativePath = uriToRelativePath(Header, IndexRoot);
104  if (!RelativePath)
105  return llvm::None;
106  Result.set_header(*RelativePath);
107  return Result;
108 }
109 
110 llvm::Optional<clangd::Symbol::IncludeHeaderWithReferences>
111 fromProtobuf(const HeaderWithReferences &Message,
112  llvm::UniqueStringSaver *Strings, llvm::StringRef IndexRoot) {
113  std::string Header = Message.header();
114  if (Header.front() != '<' && Header.front() != '"') {
115  auto URIString = relativePathToURI(Header, IndexRoot);
116  if (!URIString)
117  return llvm::None;
118  Header = *URIString;
119  }
120  return clangd::Symbol::IncludeHeaderWithReferences{Strings->save(Header),
121  Message.references()};
122 }
123 
124 } // namespace
125 
127  llvm::StringRef IndexRoot) {
129  Result.Query = Request->query();
130  for (const auto &Scope : Request->scopes())
131  Result.Scopes.push_back(Scope);
132  Result.AnyScope = Request->any_scope();
133  if (Request->limit())
134  Result.Limit = Request->limit();
135  Result.RestrictForCodeCompletion = Request->restricted_for_code_completion();
136  for (const auto &Path : Request->proximity_paths()) {
137  llvm::SmallString<256> LocalPath = llvm::StringRef(IndexRoot);
138  llvm::sys::path::append(LocalPath, Path);
139  Result.ProximityPaths.push_back(std::string(LocalPath));
140  }
141  for (const auto &Type : Request->preferred_types())
142  Result.ProximityPaths.push_back(Type);
143  return Result;
144 }
145 
146 llvm::Optional<clangd::Symbol> fromProtobuf(const Symbol &Message,
147  llvm::UniqueStringSaver *Strings,
148  llvm::StringRef IndexRoot) {
149  if (!Message.has_info() || !Message.has_definition() ||
150  !Message.has_canonical_declaration()) {
151  elog("Cannot convert Symbol from Protobuf: {0}",
152  Message.ShortDebugString());
153  return llvm::None;
154  }
155  clangd::Symbol Result;
156  auto ID = SymbolID::fromStr(Message.id());
157  if (!ID) {
158  elog("Cannot parse SymbolID {0} given Protobuf: {1}", ID.takeError(),
159  Message.ShortDebugString());
160  return llvm::None;
161  }
162  Result.ID = *ID;
163  Result.SymInfo = fromProtobuf(Message.info());
164  Result.Name = Message.name();
165  Result.Scope = Message.scope();
166  auto Definition = fromProtobuf(Message.definition(), Strings, IndexRoot);
167  if (!Definition)
168  return llvm::None;
169  Result.Definition = *Definition;
170  auto Declaration =
171  fromProtobuf(Message.canonical_declaration(), Strings, IndexRoot);
172  if (!Declaration)
173  return llvm::None;
174  Result.CanonicalDeclaration = *Declaration;
175  Result.References = Message.references();
176  Result.Origin = static_cast<clangd::SymbolOrigin>(Message.origin());
177  Result.Signature = Message.signature();
178  Result.TemplateSpecializationArgs = Message.template_specialization_args();
179  Result.CompletionSnippetSuffix = Message.completion_snippet_suffix();
180  Result.Documentation = Message.documentation();
181  Result.ReturnType = Message.return_type();
182  Result.Type = Message.type();
183  for (const auto &Header : Message.headers()) {
184  auto SerializedHeader = fromProtobuf(Header, Strings, IndexRoot);
185  if (SerializedHeader)
186  Result.IncludeHeaders.push_back(*SerializedHeader);
187  }
188  Result.Flags = static_cast<clangd::Symbol::SymbolFlag>(Message.flags());
189  return Result;
190 }
191 
192 llvm::Optional<clangd::Ref> fromProtobuf(const Ref &Message,
193  llvm::UniqueStringSaver *Strings,
194  llvm::StringRef IndexRoot) {
195  if (!Message.has_location()) {
196  elog("Cannot convert Ref from Protobuf: {}", Message.ShortDebugString());
197  return llvm::None;
198  }
199  clangd::Ref Result;
200  auto Location = fromProtobuf(Message.location(), Strings, IndexRoot);
201  if (!Location)
202  return llvm::None;
203  Result.Location = *Location;
204  Result.Kind = static_cast<clangd::RefKind>(Message.kind());
205  return Result;
206 }
207 
209  LookupRequest RPCRequest;
210  for (const auto &SymbolID : From.IDs)
211  RPCRequest.add_ids(SymbolID.str());
212  return RPCRequest;
213 }
214 
216  llvm::StringRef IndexRoot) {
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 (llvm::sys::path::replace_path_prefix(RelativePath, IndexRoot, ""))
228  RPCRequest.add_proximity_paths(llvm::sys::path::convert_to_slash(
229  RelativePath, llvm::sys::path::Style::posix));
230  }
231  for (const auto &Type : From.PreferredTypes)
232  RPCRequest.add_preferred_types(Type);
233  return RPCRequest;
234 }
235 
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  return RPCRequest;
244 }
245 
246 Symbol toProtobuf(const clangd::Symbol &From, llvm::StringRef IndexRoot) {
247  Symbol Result;
248  Result.set_id(From.ID.str());
249  *Result.mutable_info() = toProtobuf(From.SymInfo);
250  Result.set_name(From.Name.str());
251  auto Definition = toProtobuf(From.Definition, IndexRoot);
252  if (Definition)
253  *Result.mutable_definition() = *Definition;
254  Result.set_scope(From.Scope.str());
255  auto Declaration = toProtobuf(From.CanonicalDeclaration, IndexRoot);
256  if (Declaration)
257  *Result.mutable_canonical_declaration() = *Declaration;
258  Result.set_references(From.References);
259  Result.set_origin(static_cast<uint32_t>(From.Origin));
260  Result.set_signature(From.Signature.str());
261  Result.set_template_specialization_args(
262  From.TemplateSpecializationArgs.str());
263  Result.set_completion_snippet_suffix(From.CompletionSnippetSuffix.str());
264  Result.set_documentation(From.Documentation.str());
265  Result.set_return_type(From.ReturnType.str());
266  Result.set_type(From.Type.str());
267  for (const auto &Header : From.IncludeHeaders) {
268  auto Serialized = toProtobuf(Header, IndexRoot);
269  if (!Serialized)
270  continue;
271  auto *NextHeader = Result.add_headers();
272  *NextHeader = *Serialized;
273  }
274  Result.set_flags(static_cast<uint32_t>(From.Flags));
275  return Result;
276 }
277 
278 // FIXME(kirillbobyrev): A reference without location is invalid.
279 // llvm::Optional<Ref> here and on the server side?
280 Ref toProtobuf(const clangd::Ref &From, llvm::StringRef IndexRoot) {
281  Ref Result;
282  Result.set_kind(static_cast<uint32_t>(From.Kind));
283  auto Location = toProtobuf(From.Location, IndexRoot);
284  if (Location)
285  *Result.mutable_location() = *Location;
286  return Result;
287 }
288 
289 llvm::Optional<std::string> relativePathToURI(llvm::StringRef RelativePath,
290  llvm::StringRef IndexRoot) {
291  assert(RelativePath == llvm::sys::path::convert_to_slash(
292  RelativePath, llvm::sys::path::Style::posix));
293  assert(IndexRoot == llvm::sys::path::convert_to_slash(IndexRoot));
294  assert(IndexRoot.endswith(llvm::sys::path::get_separator()));
295  if (RelativePath.empty())
296  return std::string();
297  if (llvm::sys::path::is_absolute(RelativePath)) {
298  elog("Remote index client got absolute path from server: {0}",
299  RelativePath);
300  return llvm::None;
301  }
302  if (llvm::sys::path::is_relative(IndexRoot)) {
303  elog("Remote index client got a relative path as index root: {0}",
304  IndexRoot);
305  return llvm::None;
306  }
307  llvm::SmallString<256> FullPath = IndexRoot;
308  llvm::sys::path::append(FullPath, RelativePath);
309  auto Result = URI::createFile(FullPath);
310  return Result.toString();
311 }
312 
313 llvm::Optional<std::string> uriToRelativePath(llvm::StringRef URI,
314  llvm::StringRef IndexRoot) {
315  assert(IndexRoot.endswith(llvm::sys::path::get_separator()));
316  assert(IndexRoot == llvm::sys::path::convert_to_slash(IndexRoot));
317  assert(!IndexRoot.empty());
318  if (llvm::sys::path::is_relative(IndexRoot)) {
319  elog("Index root {0} is not absolute path", IndexRoot);
320  return llvm::None;
321  }
322  auto ParsedURI = URI::parse(URI);
323  if (!ParsedURI) {
324  elog("Remote index got bad URI from client {0}: {1}", URI,
325  ParsedURI.takeError());
326  return llvm::None;
327  }
328  if (ParsedURI->scheme() != "file") {
329  elog("Remote index got URI with scheme other than \"file\" {0}: {1}", URI,
330  ParsedURI->scheme());
331  return llvm::None;
332  }
333  llvm::SmallString<256> Result = ParsedURI->body();
334  if (!llvm::sys::path::replace_path_prefix(Result, IndexRoot, "")) {
335  elog("Can not get relative path from the URI {0} given the index root {1}",
336  URI, IndexRoot);
337  return llvm::None;
338  }
339  // Make sure the result has UNIX slashes.
340  return llvm::sys::path::convert_to_slash(Result,
341  llvm::sys::path::Style::posix);
342 }
343 
344 } // namespace remote
345 } // namespace clangd
346 } // namespace clang
clang::clangd::Ref::Kind
RefKind Kind
Definition: Ref.h:90
clang::find_all_symbols::SymbolInfo
Describes a named symbol from a header.
Definition: SymbolInfo.h:27
SymbolID.h
Headers.h
SymbolOrigin.h
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::clangd::Symbol::ID
SymbolID ID
The ID of the symbol.
Definition: Symbol.h:38
clang::clangd::RefKind::Declaration
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
clang::clangd::FuzzyFindRequest::PreferredTypes
std::vector< std::string > PreferredTypes
Preferred types of symbols. These are raw representation of OpaqueType.
Definition: Index.h:49
SymbolLocation.h
Location
Definition: Modularize.cpp:383
clang::clangd::Location
Definition: Protocol.h:199
clang::tidy::bugprone::Message
static const char Message[]
Definition: ReservedIdentifierCheck.cpp:31
Marshalling.h
clang::clangd::remote::fromProtobuf
clangd::FuzzyFindRequest fromProtobuf(const FuzzyFindRequest *Request, llvm::StringRef IndexRoot)
Definition: Marshalling.cpp:126
clang::clangd::FuzzyFindRequest::Scopes
std::vector< std::string > Scopes
If this is non-empty, symbols must be in at least one of the scopes (e.g.
Definition: Index.h:36
clang::clangd::TextDocumentSyncKind::None
Documents should not be synced at all.
clang::clangd::FuzzyFindRequest
Definition: Index.h:26
clang::clangd::URI::parse
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
Definition: URI.cpp:163
clang::clangd::FuzzyFindRequest::Query
std::string Query
A query string for the fuzzy find.
Definition: Index.h:29
clang::clangd::Symbol::References
unsigned References
The number of translation units that reference this symbol from their main file.
Definition: Symbol.h:59
Protocol.h
clang::clangd::Symbol::ReturnType
llvm::StringRef ReturnType
Type when this symbol is used in an expression.
Definition: Symbol.h:80
clang::clangd::remote::relativePathToURI
llvm::Optional< std::string > relativePathToURI(llvm::StringRef RelativePath, llvm::StringRef IndexRoot)
Translates RelativePath into the absolute path and builds URI for the user machine.
Definition: Marshalling.cpp:289
clang::clangd::Ref::Location
SymbolLocation Location
The source location where the symbol is named.
Definition: Ref.h:89
clang::clangd::Symbol::Origin
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.
Definition: Symbol.h:61
Logger.h
clang::clangd::Symbol
The class presents a C++ symbol, e.g.
Definition: Symbol.h:36
clang::clangd::Symbol::Flags
SymbolFlag Flags
Definition: Symbol.h:128
clang::clangd::Symbol::SymInfo
index::SymbolInfo SymInfo
The symbol information, like symbol kind.
Definition: Symbol.h:40
clang::clangd::remote::toProtobuf
LookupRequest toProtobuf(const clangd::LookupRequest &From)
Definition: Marshalling.cpp:208
clang::clangd::remote::uriToRelativePath
llvm::Optional< std::string > uriToRelativePath(llvm::StringRef URI, llvm::StringRef IndexRoot)
Translates a URI from the server's backing index to a relative path suitable to send over the wire to...
Definition: Marshalling.cpp:313
Serialization.h
clang::clangd::Symbol::Name
llvm::StringRef Name
The unqualified name of the symbol, e.g. "bar" (for ns::bar).
Definition: Symbol.h:42
clang::clangd::SymbolID::str
std::string str() const
Definition: SymbolID.cpp:33
clang::clangd::RefsRequest::IDs
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:68
clang::clangd::FuzzyFindRequest::Limit
llvm::Optional< uint32_t > Limit
The number of top candidates to return.
Definition: Index.h:42
Symbol.h
clang::clangd::Symbol::CanonicalDeclaration
SymbolLocation CanonicalDeclaration
The location of the preferred declaration of the symbol.
Definition: Symbol.h:56
clang::clangd::LookupRequest::IDs
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:64
clang::clangd::Symbol::CompletionSnippetSuffix
llvm::StringRef CompletionSnippetSuffix
What to insert when completing this symbol, after the symbol name.
Definition: Symbol.h:74
clang::clangd::RefsRequest::Filter
RefKind Filter
Definition: Index.h:69
clang::clangd::LookupRequest
Definition: Index.h:63
Info
FunctionInfo Info
Definition: FunctionSizeCheck.cpp:120
clang::clangd::isLiteralInclude
bool isLiteralInclude(llvm::StringRef Include)
Returns true if Include is literal include like "path" or <path>.
Definition: Headers.cpp:107
Strings
std::vector< llvm::StringRef > Strings
Definition: Serialization.cpp:195
clang::clangd::Ref
Represents a symbol occurrence in the source file.
Definition: Ref.h:87
clang::clangd::Symbol::TemplateSpecializationArgs
llvm::StringRef TemplateSpecializationArgs
Argument list in human-readable format, will be displayed to help disambiguate between different spec...
Definition: Symbol.h:69
clang::clangd::SymbolID::fromStr
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition: SymbolID.cpp:35
clang::clangd::Symbol::Scope
llvm::StringRef Scope
The containing namespace. e.g. "" (global), "ns::" (top-level namespace).
Definition: Symbol.h:44
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
SymbolInfo
clang::find_all_symbols::SymbolInfo SymbolInfo
Definition: FindAllSymbolsMain.cpp:38
clang::clangd::RefsRequest::Limit
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition: Index.h:73
clang::clangd::FuzzyFindRequest::AnyScope
bool AnyScope
If set to true, allow symbols from any scope.
Definition: Index.h:39
clang::clangd::Symbol::Definition
SymbolLocation Definition
The location of the symbol's definition, if one was found.
Definition: Symbol.h:47
clang::clangd::URI::scheme
llvm::StringRef scheme() const
Returns decoded scheme e.g. "https".
Definition: URI.h:33
clang::clangd::FuzzyFindRequest::RestrictForCodeCompletion
bool RestrictForCodeCompletion
If set to true, only symbols for completion support will be considered.
Definition: Index.h:44
clang::clangd::URI::createFile
static URI createFile(llvm::StringRef AbsolutePath)
This creates a file:// URI for AbsolutePath. The path must be absolute.
Definition: URI.cpp:225
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
clang::clangd::SymbolID
Definition: SymbolID.h:31
clang::clangd::Symbol::Signature
llvm::StringRef Signature
A brief description of the symbol that can be appended in the completion candidate list.
Definition: Symbol.h:65
clang::clangd::RefKind::Definition
clang::clangd::Symbol::Type
llvm::StringRef Type
Raw representation of the OpaqueType of the symbol, used for scoring purposes.
Definition: Symbol.h:85
clang::clangd::RefsRequest
Definition: Index.h:67
clang::clangd::Symbol::IncludeHeaders
llvm::SmallVector< IncludeHeaderWithReferences, 1 > IncludeHeaders
One Symbol can potentially be included via different headers.
Definition: Symbol.h:111
clang::clangd::FuzzyFindRequest::ProximityPaths
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
Definition: Index.h:47
clang::clangd::Symbol::Documentation
llvm::StringRef Documentation
Documentation including comment for the symbol declaration.
Definition: Symbol.h:76
clang::clangd::URI
A URI describes the location of a source file.
Definition: URI.h:28