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