| 1 | //===-- YAMLSerialization.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 | // A YAML index file is a sequence of tagged entries. |
| 10 | // Each entry either encodes a Symbol or the list of references to a symbol |
| 11 | // (a "ref bundle"). |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "Headers.h" |
| 16 | #include "index/Ref.h" |
| 17 | #include "index/Relation.h" |
| 18 | #include "index/Serialization.h" |
| 19 | #include "index/Symbol.h" |
| 20 | #include "index/SymbolLocation.h" |
| 21 | #include "index/SymbolOrigin.h" |
| 22 | #include "clang/Tooling/CompilationDatabase.h" |
| 23 | #include "llvm/ADT/StringRef.h" |
| 24 | #include "llvm/Support/Allocator.h" |
| 25 | #include "llvm/Support/StringSaver.h" |
| 26 | #include "llvm/Support/YAMLTraits.h" |
| 27 | #include "llvm/Support/raw_ostream.h" |
| 28 | #include <cstdint> |
| 29 | #include <optional> |
| 30 | |
| 31 | namespace { |
| 32 | struct YIncludeHeaderWithReferences; |
| 33 | } |
| 34 | |
| 35 | LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Symbol::IncludeHeaderWithReferences) |
| 36 | LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Ref) |
| 37 | LLVM_YAML_IS_SEQUENCE_VECTOR(YIncludeHeaderWithReferences) |
| 38 | |
| 39 | namespace { |
| 40 | using RefBundle = |
| 41 | std::pair<clang::clangd::SymbolID, std::vector<clang::clangd::Ref>>; |
| 42 | // This is a pale imitation of std::variant<Symbol, RefBundle, Relation> |
| 43 | struct VariantEntry { |
| 44 | std::optional<clang::clangd::Symbol> Symbol; |
| 45 | std::optional<RefBundle> Refs; |
| 46 | std::optional<clang::clangd::Relation> Relation; |
| 47 | std::optional<clang::clangd::IncludeGraphNode> Source; |
| 48 | std::optional<clang::tooling::CompileCommand> Cmd; |
| 49 | }; |
| 50 | // A class helps YAML to serialize the 32-bit encoded position (Line&Column), |
| 51 | // as YAMLIO can't directly map bitfields. |
| 52 | struct YPosition { |
| 53 | uint32_t Line; |
| 54 | uint32_t Column; |
| 55 | }; |
| 56 | // A class helps YAML to serialize the IncludeHeaderWithReferences as YAMLIO |
| 57 | // can't directly map bitfields. |
| 58 | struct { |
| 59 | llvm::StringRef ; |
| 60 | uint32_t ; |
| 61 | clang::clangd::Symbol::IncludeDirective ; |
| 62 | |
| 63 | () = default; |
| 64 | |
| 65 | ( |
| 66 | llvm::StringRef , uint32_t References, |
| 67 | clang::clangd::Symbol::IncludeDirective SupportedDirectives) |
| 68 | : IncludeHeader(IncludeHeader), References(References), |
| 69 | SupportedDirectives(SupportedDirectives) {} |
| 70 | }; |
| 71 | |
| 72 | // avoid ODR violation of specialization for non-owned CompileCommand |
| 73 | struct CompileCommandYAML : clang::tooling::CompileCommand {}; |
| 74 | |
| 75 | } // namespace |
| 76 | namespace llvm { |
| 77 | namespace yaml { |
| 78 | |
| 79 | using clang::clangd::FileDigest; |
| 80 | using clang::clangd::IncludeGraph; |
| 81 | using clang::clangd::IncludeGraphNode; |
| 82 | using clang::clangd::Ref; |
| 83 | using clang::clangd::RefKind; |
| 84 | using clang::clangd::Relation; |
| 85 | using clang::clangd::RelationKind; |
| 86 | using clang::clangd::Symbol; |
| 87 | using clang::clangd::SymbolID; |
| 88 | using clang::clangd::SymbolLocation; |
| 89 | using clang::index::SymbolInfo; |
| 90 | using clang::index::SymbolKind; |
| 91 | using clang::index::SymbolLanguage; |
| 92 | using clang::tooling::CompileCommand; |
| 93 | |
| 94 | // Helper to (de)serialize the SymbolID. We serialize it as a hex string. |
| 95 | struct NormalizedSymbolID { |
| 96 | NormalizedSymbolID(IO &) {} |
| 97 | NormalizedSymbolID(IO &, const SymbolID &ID) { |
| 98 | llvm::raw_string_ostream OS(HexString); |
| 99 | OS << ID; |
| 100 | } |
| 101 | |
| 102 | SymbolID denormalize(IO &I) { |
| 103 | auto ID = SymbolID::fromStr(HexString); |
| 104 | if (!ID) { |
| 105 | I.setError(llvm::toString(E: ID.takeError())); |
| 106 | return SymbolID(); |
| 107 | } |
| 108 | return *ID; |
| 109 | } |
| 110 | |
| 111 | std::string HexString; |
| 112 | }; |
| 113 | |
| 114 | struct NormalizedSymbolFlag { |
| 115 | NormalizedSymbolFlag(IO &) {} |
| 116 | NormalizedSymbolFlag(IO &, Symbol::SymbolFlag F) { |
| 117 | Flag = static_cast<uint8_t>(F); |
| 118 | } |
| 119 | |
| 120 | Symbol::SymbolFlag denormalize(IO &) { |
| 121 | return static_cast<Symbol::SymbolFlag>(Flag); |
| 122 | } |
| 123 | |
| 124 | uint8_t Flag = 0; |
| 125 | }; |
| 126 | |
| 127 | template <> struct MappingTraits<YPosition> { |
| 128 | static void mapping(IO &IO, YPosition &Value) { |
| 129 | IO.mapRequired(Key: "Line" , Val&: Value.Line); |
| 130 | IO.mapRequired(Key: "Column" , Val&: Value.Column); |
| 131 | } |
| 132 | }; |
| 133 | |
| 134 | struct NormalizedPosition { |
| 135 | using Position = clang::clangd::SymbolLocation::Position; |
| 136 | NormalizedPosition(IO &) {} |
| 137 | NormalizedPosition(IO &, const Position &Pos) { |
| 138 | P.Line = Pos.line(); |
| 139 | P.Column = Pos.column(); |
| 140 | } |
| 141 | |
| 142 | Position denormalize(IO &) { |
| 143 | Position Pos; |
| 144 | Pos.setLine(P.Line); |
| 145 | Pos.setColumn(P.Column); |
| 146 | return Pos; |
| 147 | } |
| 148 | YPosition P; |
| 149 | }; |
| 150 | |
| 151 | struct NormalizedFileURI { |
| 152 | NormalizedFileURI(IO &) {} |
| 153 | NormalizedFileURI(IO &, const char *FileURI) { URI = FileURI; } |
| 154 | |
| 155 | const char *denormalize(IO &IO) { |
| 156 | assert(IO.getContext() && |
| 157 | "Expecting an UniqueStringSaver to allocate data" ); |
| 158 | return static_cast<llvm::UniqueStringSaver *>(IO.getContext()) |
| 159 | ->save(S: URI) |
| 160 | .data(); |
| 161 | } |
| 162 | |
| 163 | std::string URI; |
| 164 | }; |
| 165 | |
| 166 | template <> struct MappingTraits<SymbolLocation> { |
| 167 | static void mapping(IO &IO, SymbolLocation &Value) { |
| 168 | MappingNormalization<NormalizedFileURI, const char *> NFile(IO, |
| 169 | Value.FileURI); |
| 170 | IO.mapRequired(Key: "FileURI" , Val&: NFile->URI); |
| 171 | MappingNormalization<NormalizedPosition, SymbolLocation::Position> NStart( |
| 172 | IO, Value.Start); |
| 173 | IO.mapRequired(Key: "Start" , Val&: NStart->P); |
| 174 | MappingNormalization<NormalizedPosition, SymbolLocation::Position> NEnd( |
| 175 | IO, Value.End); |
| 176 | IO.mapRequired(Key: "End" , Val&: NEnd->P); |
| 177 | } |
| 178 | }; |
| 179 | |
| 180 | template <> struct MappingTraits<SymbolInfo> { |
| 181 | static void mapping(IO &IO, SymbolInfo &SymInfo) { |
| 182 | // FIXME: expose other fields? |
| 183 | IO.mapRequired(Key: "Kind" , Val&: SymInfo.Kind); |
| 184 | IO.mapRequired(Key: "Lang" , Val&: SymInfo.Lang); |
| 185 | } |
| 186 | }; |
| 187 | |
| 188 | template <> struct ScalarBitSetTraits<clang::clangd::Symbol::IncludeDirective> { |
| 189 | static void bitset(IO &IO, clang::clangd::Symbol::IncludeDirective &Value) { |
| 190 | IO.bitSetCase(Val&: Value, Str: "Include" , ConstVal: clang::clangd::Symbol::Include); |
| 191 | IO.bitSetCase(Val&: Value, Str: "Import" , ConstVal: clang::clangd::Symbol::Import); |
| 192 | } |
| 193 | }; |
| 194 | |
| 195 | template <> struct MappingTraits<YIncludeHeaderWithReferences> { |
| 196 | static void (IO &IO, YIncludeHeaderWithReferences &Inc) { |
| 197 | IO.mapRequired(Key: "Header" , Val&: Inc.IncludeHeader); |
| 198 | IO.mapRequired(Key: "References" , Val&: Inc.References); |
| 199 | IO.mapOptional(Key: "Directives" , Val&: Inc.SupportedDirectives, |
| 200 | Default: clang::clangd::Symbol::Include); |
| 201 | } |
| 202 | }; |
| 203 | |
| 204 | struct { |
| 205 | using = clang::clangd::Symbol::IncludeHeaderWithReferences; |
| 206 | (IO &) {} |
| 207 | ( |
| 208 | IO &, const llvm::SmallVector<IncludeHeader, 1> &) { |
| 209 | for (auto &I : IncludeHeaders) { |
| 210 | Headers.emplace_back(Args: I.IncludeHeader, Args: I.References, |
| 211 | Args: I.supportedDirectives()); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | llvm::SmallVector<IncludeHeader, 1> (IO &) { |
| 216 | llvm::SmallVector<IncludeHeader, 1> Result; |
| 217 | for (auto &H : Headers) |
| 218 | Result.emplace_back(Args&: H.IncludeHeader, Args&: H.References, Args&: H.SupportedDirectives); |
| 219 | return Result; |
| 220 | } |
| 221 | llvm::SmallVector<YIncludeHeaderWithReferences, 1> ; |
| 222 | }; |
| 223 | |
| 224 | template <> struct MappingTraits<Symbol> { |
| 225 | static void mapping(IO &IO, Symbol &Sym) { |
| 226 | MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, Sym.ID); |
| 227 | MappingNormalization<NormalizedSymbolFlag, Symbol::SymbolFlag> NSymbolFlag( |
| 228 | IO, Sym.Flags); |
| 229 | MappingNormalization< |
| 230 | NormalizedIncludeHeaders, |
| 231 | llvm::SmallVector<Symbol::IncludeHeaderWithReferences, 1>> |
| 232 | (IO, Sym.IncludeHeaders); |
| 233 | IO.mapRequired(Key: "ID" , Val&: NSymbolID->HexString); |
| 234 | IO.mapRequired(Key: "Name" , Val&: Sym.Name); |
| 235 | IO.mapRequired(Key: "Scope" , Val&: Sym.Scope); |
| 236 | IO.mapRequired(Key: "SymInfo" , Val&: Sym.SymInfo); |
| 237 | IO.mapOptional(Key: "CanonicalDeclaration" , Val&: Sym.CanonicalDeclaration, |
| 238 | Default: SymbolLocation()); |
| 239 | IO.mapOptional(Key: "Definition" , Val&: Sym.Definition, Default: SymbolLocation()); |
| 240 | IO.mapOptional(Key: "References" , Val&: Sym.References, Default: 0u); |
| 241 | IO.mapOptional(Key: "Flags" , Val&: NSymbolFlag->Flag); |
| 242 | IO.mapOptional(Key: "Signature" , Val&: Sym.Signature); |
| 243 | IO.mapOptional(Key: "TemplateSpecializationArgs" , |
| 244 | Val&: Sym.TemplateSpecializationArgs); |
| 245 | IO.mapOptional(Key: "CompletionSnippetSuffix" , Val&: Sym.CompletionSnippetSuffix); |
| 246 | IO.mapOptional(Key: "Documentation" , Val&: Sym.Documentation); |
| 247 | IO.mapOptional(Key: "ReturnType" , Val&: Sym.ReturnType); |
| 248 | IO.mapOptional(Key: "Type" , Val&: Sym.Type); |
| 249 | IO.mapOptional(Key: "IncludeHeaders" , Val&: NIncludeHeaders->Headers); |
| 250 | } |
| 251 | }; |
| 252 | |
| 253 | template <> struct ScalarEnumerationTraits<SymbolLanguage> { |
| 254 | static void enumeration(IO &IO, SymbolLanguage &Value) { |
| 255 | IO.enumCase(Val&: Value, Str: "C" , ConstVal: SymbolLanguage::C); |
| 256 | IO.enumCase(Val&: Value, Str: "Cpp" , ConstVal: SymbolLanguage::CXX); |
| 257 | IO.enumCase(Val&: Value, Str: "ObjC" , ConstVal: SymbolLanguage::ObjC); |
| 258 | IO.enumCase(Val&: Value, Str: "Swift" , ConstVal: SymbolLanguage::Swift); |
| 259 | } |
| 260 | }; |
| 261 | |
| 262 | template <> struct ScalarEnumerationTraits<SymbolKind> { |
| 263 | static void enumeration(IO &IO, SymbolKind &Value) { |
| 264 | #define DEFINE_ENUM(name) IO.enumCase(Value, #name, SymbolKind::name) |
| 265 | |
| 266 | DEFINE_ENUM(Unknown); |
| 267 | DEFINE_ENUM(Function); |
| 268 | DEFINE_ENUM(Module); |
| 269 | DEFINE_ENUM(Namespace); |
| 270 | DEFINE_ENUM(NamespaceAlias); |
| 271 | DEFINE_ENUM(Macro); |
| 272 | DEFINE_ENUM(Enum); |
| 273 | DEFINE_ENUM(Struct); |
| 274 | DEFINE_ENUM(Class); |
| 275 | DEFINE_ENUM(Protocol); |
| 276 | DEFINE_ENUM(Extension); |
| 277 | DEFINE_ENUM(Union); |
| 278 | DEFINE_ENUM(TypeAlias); |
| 279 | DEFINE_ENUM(Function); |
| 280 | DEFINE_ENUM(Variable); |
| 281 | DEFINE_ENUM(Field); |
| 282 | DEFINE_ENUM(EnumConstant); |
| 283 | DEFINE_ENUM(InstanceMethod); |
| 284 | DEFINE_ENUM(ClassMethod); |
| 285 | DEFINE_ENUM(StaticMethod); |
| 286 | DEFINE_ENUM(InstanceProperty); |
| 287 | DEFINE_ENUM(ClassProperty); |
| 288 | DEFINE_ENUM(StaticProperty); |
| 289 | DEFINE_ENUM(Constructor); |
| 290 | DEFINE_ENUM(Destructor); |
| 291 | DEFINE_ENUM(ConversionFunction); |
| 292 | DEFINE_ENUM(Parameter); |
| 293 | DEFINE_ENUM(Using); |
| 294 | |
| 295 | #undef DEFINE_ENUM |
| 296 | } |
| 297 | }; |
| 298 | |
| 299 | template <> struct MappingTraits<RefBundle> { |
| 300 | static void mapping(IO &IO, RefBundle &Refs) { |
| 301 | MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, |
| 302 | Refs.first); |
| 303 | IO.mapRequired(Key: "ID" , Val&: NSymbolID->HexString); |
| 304 | IO.mapRequired(Key: "References" , Val&: Refs.second); |
| 305 | } |
| 306 | }; |
| 307 | |
| 308 | struct NormalizedRefKind { |
| 309 | NormalizedRefKind(IO &) {} |
| 310 | NormalizedRefKind(IO &, RefKind O) { Kind = static_cast<uint8_t>(O); } |
| 311 | |
| 312 | RefKind denormalize(IO &) { return static_cast<RefKind>(Kind); } |
| 313 | |
| 314 | uint8_t Kind = 0; |
| 315 | }; |
| 316 | |
| 317 | template <> struct MappingTraits<Ref> { |
| 318 | static void mapping(IO &IO, Ref &R) { |
| 319 | MappingNormalization<NormalizedRefKind, RefKind> NKind(IO, R.Kind); |
| 320 | IO.mapRequired(Key: "Kind" , Val&: NKind->Kind); |
| 321 | IO.mapRequired(Key: "Location" , Val&: R.Location); |
| 322 | IO.mapOptional(Key: "Container" , Val&: R.Container); |
| 323 | } |
| 324 | }; |
| 325 | |
| 326 | struct NormalizedSymbolRole { |
| 327 | NormalizedSymbolRole(IO &) {} |
| 328 | NormalizedSymbolRole(IO &IO, RelationKind R) { |
| 329 | Kind = static_cast<uint8_t>(R); |
| 330 | } |
| 331 | |
| 332 | RelationKind denormalize(IO &IO) { return static_cast<RelationKind>(Kind); } |
| 333 | |
| 334 | uint8_t Kind = 0; |
| 335 | }; |
| 336 | |
| 337 | template <> struct MappingTraits<SymbolID> { |
| 338 | static void mapping(IO &IO, SymbolID &ID) { |
| 339 | MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, ID); |
| 340 | IO.mapRequired(Key: "ID" , Val&: NSymbolID->HexString); |
| 341 | } |
| 342 | }; |
| 343 | |
| 344 | template <> struct MappingTraits<Relation> { |
| 345 | static void mapping(IO &IO, Relation &Relation) { |
| 346 | MappingNormalization<NormalizedSymbolRole, RelationKind> NRole( |
| 347 | IO, Relation.Predicate); |
| 348 | IO.mapRequired(Key: "Subject" , Val&: Relation.Subject); |
| 349 | IO.mapRequired(Key: "Predicate" , Val&: NRole->Kind); |
| 350 | IO.mapRequired(Key: "Object" , Val&: Relation.Object); |
| 351 | } |
| 352 | }; |
| 353 | |
| 354 | struct NormalizedSourceFlag { |
| 355 | NormalizedSourceFlag(IO &) {} |
| 356 | NormalizedSourceFlag(IO &, IncludeGraphNode::SourceFlag O) { |
| 357 | Flag = static_cast<uint8_t>(O); |
| 358 | } |
| 359 | |
| 360 | IncludeGraphNode::SourceFlag denormalize(IO &) { |
| 361 | return static_cast<IncludeGraphNode::SourceFlag>(Flag); |
| 362 | } |
| 363 | |
| 364 | uint8_t Flag = 0; |
| 365 | }; |
| 366 | |
| 367 | struct NormalizedFileDigest { |
| 368 | NormalizedFileDigest(IO &) {} |
| 369 | NormalizedFileDigest(IO &, const FileDigest &Digest) { |
| 370 | HexString = llvm::toHex(Input: Digest); |
| 371 | } |
| 372 | |
| 373 | FileDigest denormalize(IO &I) { |
| 374 | FileDigest Digest; |
| 375 | if (HexString.size() == Digest.size() * 2 && |
| 376 | llvm::all_of(Range&: HexString, P: llvm::isHexDigit)) { |
| 377 | memcpy(dest: Digest.data(), src: llvm::fromHex(Input: HexString).data(), n: Digest.size()); |
| 378 | } else { |
| 379 | I.setError(std::string("Bad hex file digest: " ) + HexString); |
| 380 | } |
| 381 | return Digest; |
| 382 | } |
| 383 | |
| 384 | std::string HexString; |
| 385 | }; |
| 386 | |
| 387 | template <> struct MappingTraits<IncludeGraphNode> { |
| 388 | static void mapping(IO &IO, IncludeGraphNode &Node) { |
| 389 | IO.mapRequired(Key: "URI" , Val&: Node.URI); |
| 390 | MappingNormalization<NormalizedSourceFlag, IncludeGraphNode::SourceFlag> |
| 391 | NSourceFlag(IO, Node.Flags); |
| 392 | IO.mapRequired(Key: "Flags" , Val&: NSourceFlag->Flag); |
| 393 | MappingNormalization<NormalizedFileDigest, FileDigest> NDigest(IO, |
| 394 | Node.Digest); |
| 395 | IO.mapRequired(Key: "Digest" , Val&: NDigest->HexString); |
| 396 | IO.mapRequired(Key: "DirectIncludes" , Val&: Node.DirectIncludes); |
| 397 | } |
| 398 | }; |
| 399 | |
| 400 | template <> struct MappingTraits<CompileCommandYAML> { |
| 401 | static void mapping(IO &IO, CompileCommandYAML &Cmd) { |
| 402 | IO.mapRequired(Key: "Directory" , Val&: Cmd.Directory); |
| 403 | IO.mapRequired(Key: "CommandLine" , Val&: Cmd.CommandLine); |
| 404 | } |
| 405 | }; |
| 406 | |
| 407 | template <> struct MappingTraits<VariantEntry> { |
| 408 | static void mapping(IO &IO, VariantEntry &Variant) { |
| 409 | if (IO.mapTag(Tag: "!Symbol" , Default: Variant.Symbol.has_value())) { |
| 410 | if (!IO.outputting()) |
| 411 | Variant.Symbol.emplace(); |
| 412 | MappingTraits<Symbol>::mapping(IO, Sym&: *Variant.Symbol); |
| 413 | } else if (IO.mapTag(Tag: "!Refs" , Default: Variant.Refs.has_value())) { |
| 414 | if (!IO.outputting()) |
| 415 | Variant.Refs.emplace(); |
| 416 | MappingTraits<RefBundle>::mapping(IO, Refs&: *Variant.Refs); |
| 417 | } else if (IO.mapTag(Tag: "!Relations" , Default: Variant.Relation.has_value())) { |
| 418 | if (!IO.outputting()) |
| 419 | Variant.Relation.emplace(); |
| 420 | MappingTraits<Relation>::mapping(IO, Relation&: *Variant.Relation); |
| 421 | } else if (IO.mapTag(Tag: "!Source" , Default: Variant.Source.has_value())) { |
| 422 | if (!IO.outputting()) |
| 423 | Variant.Source.emplace(); |
| 424 | MappingTraits<IncludeGraphNode>::mapping(IO, Node&: *Variant.Source); |
| 425 | } else if (IO.mapTag(Tag: "!Cmd" , Default: Variant.Cmd.has_value())) { |
| 426 | if (!IO.outputting()) |
| 427 | Variant.Cmd.emplace(); |
| 428 | MappingTraits<CompileCommandYAML>::mapping( |
| 429 | IO, Cmd&: static_cast<CompileCommandYAML &>(*Variant.Cmd)); |
| 430 | } |
| 431 | } |
| 432 | }; |
| 433 | |
| 434 | } // namespace yaml |
| 435 | } // namespace llvm |
| 436 | |
| 437 | namespace clang { |
| 438 | namespace clangd { |
| 439 | |
| 440 | void writeYAML(const IndexFileOut &O, llvm::raw_ostream &OS) { |
| 441 | llvm::yaml::Output Yout(OS); |
| 442 | for (const auto &Sym : *O.Symbols) { |
| 443 | VariantEntry Entry; |
| 444 | Entry.Symbol = Sym; |
| 445 | Yout << Entry; |
| 446 | } |
| 447 | if (O.Refs) |
| 448 | for (auto &Sym : *O.Refs) { |
| 449 | VariantEntry Entry; |
| 450 | Entry.Refs = Sym; |
| 451 | Yout << Entry; |
| 452 | } |
| 453 | if (O.Relations) |
| 454 | for (auto &R : *O.Relations) { |
| 455 | VariantEntry Entry; |
| 456 | Entry.Relation = R; |
| 457 | Yout << Entry; |
| 458 | } |
| 459 | if (O.Sources) { |
| 460 | for (const auto &Source : *O.Sources) { |
| 461 | VariantEntry Entry; |
| 462 | Entry.Source = Source.getValue(); |
| 463 | Yout << Entry; |
| 464 | } |
| 465 | } |
| 466 | if (O.Cmd) { |
| 467 | VariantEntry Entry; |
| 468 | Entry.Cmd = *O.Cmd; |
| 469 | Yout << Entry; |
| 470 | } |
| 471 | } |
| 472 | |
| 473 | llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data, |
| 474 | SymbolOrigin Origin) { |
| 475 | SymbolSlab::Builder Symbols; |
| 476 | RefSlab::Builder Refs; |
| 477 | RelationSlab::Builder Relations; |
| 478 | llvm::BumpPtrAllocator |
| 479 | Arena; // store the underlying data of Position::FileURI. |
| 480 | llvm::UniqueStringSaver Strings(Arena); |
| 481 | llvm::yaml::Input Yin(Data, &Strings); |
| 482 | IncludeGraph Sources; |
| 483 | std::optional<tooling::CompileCommand> Cmd; |
| 484 | while (Yin.setCurrentDocument()) { |
| 485 | llvm::yaml::EmptyContext Ctx; |
| 486 | VariantEntry Variant; |
| 487 | yamlize(io&: Yin, Val&: Variant, true, Ctx); |
| 488 | if (Yin.error()) |
| 489 | return llvm::errorCodeToError(EC: Yin.error()); |
| 490 | |
| 491 | if (Variant.Symbol) { |
| 492 | Variant.Symbol->Origin = Origin; |
| 493 | Symbols.insert(S: *Variant.Symbol); |
| 494 | } |
| 495 | if (Variant.Refs) |
| 496 | for (const auto &Ref : Variant.Refs->second) |
| 497 | Refs.insert(ID: Variant.Refs->first, S: Ref); |
| 498 | if (Variant.Relation) |
| 499 | Relations.insert(R: *Variant.Relation); |
| 500 | if (Variant.Source) { |
| 501 | auto &IGN = *Variant.Source; |
| 502 | auto Entry = Sources.try_emplace(Key: IGN.URI).first; |
| 503 | Entry->getValue() = std::move(IGN); |
| 504 | // Fixup refs to refer to map keys which will live on |
| 505 | Entry->getValue().URI = Entry->getKey(); |
| 506 | for (auto &Include : Entry->getValue().DirectIncludes) |
| 507 | Include = Sources.try_emplace(Key: Include).first->getKey(); |
| 508 | } |
| 509 | if (Variant.Cmd) |
| 510 | Cmd = *Variant.Cmd; |
| 511 | Yin.nextDocument(); |
| 512 | } |
| 513 | |
| 514 | IndexFileIn Result; |
| 515 | Result.Symbols.emplace(args: std::move(Symbols).build()); |
| 516 | Result.Refs.emplace(args: std::move(Refs).build()); |
| 517 | Result.Relations.emplace(args: std::move(Relations).build()); |
| 518 | if (Sources.size()) |
| 519 | Result.Sources = std::move(Sources); |
| 520 | Result.Cmd = std::move(Cmd); |
| 521 | return std::move(Result); |
| 522 | } |
| 523 | |
| 524 | std::string toYAML(const Symbol &S) { |
| 525 | std::string Buf; |
| 526 | { |
| 527 | llvm::raw_string_ostream OS(Buf); |
| 528 | llvm::yaml::Output Yout(OS); |
| 529 | Symbol Sym = S; // copy: Yout<< requires mutability. |
| 530 | Yout << Sym; |
| 531 | } |
| 532 | return Buf; |
| 533 | } |
| 534 | |
| 535 | std::string toYAML(const std::pair<SymbolID, llvm::ArrayRef<Ref>> &Data) { |
| 536 | RefBundle Refs = {Data.first, Data.second}; |
| 537 | std::string Buf; |
| 538 | { |
| 539 | llvm::raw_string_ostream OS(Buf); |
| 540 | llvm::yaml::Output Yout(OS); |
| 541 | Yout << Refs; |
| 542 | } |
| 543 | return Buf; |
| 544 | } |
| 545 | |
| 546 | std::string toYAML(const Relation &R) { |
| 547 | std::string Buf; |
| 548 | { |
| 549 | llvm::raw_string_ostream OS(Buf); |
| 550 | llvm::yaml::Output Yout(OS); |
| 551 | Relation Rel = R; // copy: Yout<< requires mutability. |
| 552 | Yout << Rel; |
| 553 | } |
| 554 | return Buf; |
| 555 | } |
| 556 | |
| 557 | std::string toYAML(const Ref &R) { |
| 558 | std::string Buf; |
| 559 | { |
| 560 | llvm::raw_string_ostream OS(Buf); |
| 561 | llvm::yaml::Output Yout(OS); |
| 562 | Ref Reference = R; // copy: Yout<< requires mutability. |
| 563 | Yout << Reference; |
| 564 | } |
| 565 | return Buf; |
| 566 | } |
| 567 | |
| 568 | } // namespace clangd |
| 569 | } // namespace clang |
| 570 | |