1 //===- TextStub.cpp -------------------------------------------------------===// 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 // Implements the text stub file reader/writer. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "TextAPIContext.h" 14 #include "TextStubCommon.h" 15 #include "llvm/ADT/BitmaskEnum.h" 16 #include "llvm/ADT/SmallString.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/Support/Allocator.h" 19 #include "llvm/Support/SourceMgr.h" 20 #include "llvm/Support/YAMLTraits.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include "llvm/TextAPI/Architecture.h" 23 #include "llvm/TextAPI/ArchitectureSet.h" 24 #include "llvm/TextAPI/InterfaceFile.h" 25 #include "llvm/TextAPI/PackedVersion.h" 26 #include "llvm/TextAPI/TextAPIReader.h" 27 #include "llvm/TextAPI/TextAPIWriter.h" 28 #include <set> 29 30 // clang-format off 31 /* 32 33 YAML Format specification. 34 35 The TBD v1 format only support two level address libraries and is per 36 definition application extension safe. 37 38 --- # the tag !tapi-tbd-v1 is optional and 39 # shouldn't be emitted to support older linker. 40 archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are 41 # supported by this file. 42 platform: ios # Specifies the platform (macosx, ios, etc) 43 install-name: /u/l/libfoo.dylib # 44 current-version: 1.2.3 # Optional: defaults to 1.0 45 compatibility-version: 1.0 # Optional: defaults to 1.0 46 swift-version: 0 # Optional: defaults to 0 47 objc-constraint: none # Optional: defaults to none 48 exports: # List of export sections 49 ... 50 51 Each export section is defined as following: 52 53 - archs: [ arm64 ] # the list of architecture slices 54 allowed-clients: [ client ] # Optional: List of clients 55 re-exports: [ ] # Optional: List of re-exports 56 symbols: [ _sym ] # Optional: List of symbols 57 objc-classes: [] # Optional: List of Objective-C classes 58 objc-ivars: [] # Optional: List of Objective C Instance 59 # Variables 60 weak-def-symbols: [] # Optional: List of weak defined symbols 61 thread-local-symbols: [] # Optional: List of thread local symbols 62 */ 63 64 /* 65 66 YAML Format specification. 67 68 --- !tapi-tbd-v2 69 archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are 70 # supported by this file. 71 uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs. 72 platform: ios # Specifies the platform (macosx, ios, etc) 73 flags: [] # Optional: 74 install-name: /u/l/libfoo.dylib # 75 current-version: 1.2.3 # Optional: defaults to 1.0 76 compatibility-version: 1.0 # Optional: defaults to 1.0 77 swift-version: 0 # Optional: defaults to 0 78 objc-constraint: retain_release # Optional: defaults to retain_release 79 parent-umbrella: # Optional: 80 exports: # List of export sections 81 ... 82 undefineds: # List of undefineds sections 83 ... 84 85 Each export section is defined as following: 86 87 - archs: [ arm64 ] # the list of architecture slices 88 allowed-clients: [ client ] # Optional: List of clients 89 re-exports: [ ] # Optional: List of re-exports 90 symbols: [ _sym ] # Optional: List of symbols 91 objc-classes: [] # Optional: List of Objective-C classes 92 objc-ivars: [] # Optional: List of Objective C Instance 93 # Variables 94 weak-def-symbols: [] # Optional: List of weak defined symbols 95 thread-local-symbols: [] # Optional: List of thread local symbols 96 97 Each undefineds section is defined as following: 98 - archs: [ arm64 ] # the list of architecture slices 99 symbols: [ _sym ] # Optional: List of symbols 100 objc-classes: [] # Optional: List of Objective-C classes 101 objc-ivars: [] # Optional: List of Objective C Instance Variables 102 weak-ref-symbols: [] # Optional: List of weak defined symbols 103 */ 104 105 /* 106 107 YAML Format specification. 108 109 --- !tapi-tbd-v3 110 archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are 111 # supported by this file. 112 uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs. 113 platform: ios # Specifies the platform (macosx, ios, etc) 114 flags: [] # Optional: 115 install-name: /u/l/libfoo.dylib # 116 current-version: 1.2.3 # Optional: defaults to 1.0 117 compatibility-version: 1.0 # Optional: defaults to 1.0 118 swift-abi-version: 0 # Optional: defaults to 0 119 objc-constraint: retain_release # Optional: defaults to retain_release 120 parent-umbrella: # Optional: 121 exports: # List of export sections 122 ... 123 undefineds: # List of undefineds sections 124 ... 125 126 Each export section is defined as following: 127 128 - archs: [ arm64 ] # the list of architecture slices 129 allowed-clients: [ client ] # Optional: List of clients 130 re-exports: [ ] # Optional: List of re-exports 131 symbols: [ _sym ] # Optional: List of symbols 132 objc-classes: [] # Optional: List of Objective-C classes 133 objc-eh-types: [] # Optional: List of Objective-C classes 134 # with EH 135 objc-ivars: [] # Optional: List of Objective C Instance 136 # Variables 137 weak-def-symbols: [] # Optional: List of weak defined symbols 138 thread-local-symbols: [] # Optional: List of thread local symbols 139 140 Each undefineds section is defined as following: 141 - archs: [ arm64 ] # the list of architecture slices 142 symbols: [ _sym ] # Optional: List of symbols 143 objc-classes: [] # Optional: List of Objective-C classes 144 objc-eh-types: [] # Optional: List of Objective-C classes 145 # with EH 146 objc-ivars: [] # Optional: List of Objective C Instance Variables 147 weak-ref-symbols: [] # Optional: List of weak defined symbols 148 */ 149 150 /* 151 152 YAML Format specification. 153 154 --- !tapi-tbd 155 tbd-version: 4 # The tbd version for format 156 targets: [ armv7-ios, x86_64-maccatalyst ] # The list of applicable tapi supported target triples 157 uuids: # Optional: List of target and UUID pairs. 158 - target: armv7-ios 159 value: ... 160 - target: x86_64-maccatalyst 161 value: ... 162 flags: [] # Optional: 163 install-name: /u/l/libfoo.dylib # 164 current-version: 1.2.3 # Optional: defaults to 1.0 165 compatibility-version: 1.0 # Optional: defaults to 1.0 166 swift-abi-version: 0 # Optional: defaults to 0 167 parent-umbrella: # Optional: 168 allowable-clients: 169 - targets: [ armv7-ios ] # Optional: 170 clients: [ clientA ] 171 exports: # List of export sections 172 ... 173 re-exports: # List of reexport sections 174 ... 175 undefineds: # List of undefineds sections 176 ... 177 178 Each export and reexport section is defined as following: 179 180 - targets: [ arm64-macos ] # The list of target triples associated with symbols 181 symbols: [ _symA ] # Optional: List of symbols 182 objc-classes: [] # Optional: List of Objective-C classes 183 objc-eh-types: [] # Optional: List of Objective-C classes 184 # with EH 185 objc-ivars: [] # Optional: List of Objective C Instance 186 # Variables 187 weak-symbols: [] # Optional: List of weak defined symbols 188 thread-local-symbols: [] # Optional: List of thread local symbols 189 - targets: [ arm64-macos, x86_64-maccatalyst ] # Optional: Targets for applicable additional symbols 190 symbols: [ _symB ] # Optional: List of symbols 191 192 Each undefineds section is defined as following: 193 - targets: [ arm64-macos ] # The list of target triples associated with symbols 194 symbols: [ _symC ] # Optional: List of symbols 195 objc-classes: [] # Optional: List of Objective-C classes 196 objc-eh-types: [] # Optional: List of Objective-C classes 197 # with EH 198 objc-ivars: [] # Optional: List of Objective C Instance Variables 199 weak-symbols: [] # Optional: List of weak defined symbols 200 */ 201 // clang-format on 202 203 using namespace llvm; 204 using namespace llvm::yaml; 205 using namespace llvm::MachO; 206 207 namespace { 208 struct ExportSection { 209 std::vector<Architecture> Architectures; 210 std::vector<FlowStringRef> AllowableClients; 211 std::vector<FlowStringRef> ReexportedLibraries; 212 std::vector<FlowStringRef> Symbols; 213 std::vector<FlowStringRef> Classes; 214 std::vector<FlowStringRef> ClassEHs; 215 std::vector<FlowStringRef> IVars; 216 std::vector<FlowStringRef> WeakDefSymbols; 217 std::vector<FlowStringRef> TLVSymbols; 218 }; 219 220 struct UndefinedSection { 221 std::vector<Architecture> Architectures; 222 std::vector<FlowStringRef> Symbols; 223 std::vector<FlowStringRef> Classes; 224 std::vector<FlowStringRef> ClassEHs; 225 std::vector<FlowStringRef> IVars; 226 std::vector<FlowStringRef> WeakRefSymbols; 227 }; 228 229 // Sections for direct target mapping in TBDv4 230 struct SymbolSection { 231 TargetList Targets; 232 std::vector<FlowStringRef> Symbols; 233 std::vector<FlowStringRef> Classes; 234 std::vector<FlowStringRef> ClassEHs; 235 std::vector<FlowStringRef> Ivars; 236 std::vector<FlowStringRef> WeakSymbols; 237 std::vector<FlowStringRef> TlvSymbols; 238 }; 239 240 struct MetadataSection { 241 enum Option { Clients, Libraries }; 242 std::vector<Target> Targets; 243 std::vector<FlowStringRef> Values; 244 }; 245 246 struct UmbrellaSection { 247 std::vector<Target> Targets; 248 std::string Umbrella; 249 }; 250 251 // UUID's for TBDv4 are mapped to target not arch 252 struct UUIDv4 { 253 Target TargetID; 254 std::string Value; 255 256 UUIDv4() = default; 257 UUIDv4(const Target &TargetID, const std::string &Value) 258 : TargetID(TargetID), Value(Value) {} 259 }; 260 } // end anonymous namespace. 261 262 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture) 263 LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection) 264 LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection) 265 // Specific to TBDv4 266 LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection) 267 LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection) 268 LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection) 269 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target) 270 LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4) 271 272 namespace llvm { 273 namespace yaml { 274 275 template <> struct MappingTraits<ExportSection> { 276 static void mapping(IO &IO, ExportSection &Section) { 277 const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 278 assert((!Ctx || Ctx->FileKind != FileType::Invalid) && 279 "File type is not set in YAML context"); 280 281 IO.mapRequired("archs", Section.Architectures); 282 if (Ctx->FileKind == FileType::TBD_V1) 283 IO.mapOptional("allowed-clients", Section.AllowableClients); 284 else 285 IO.mapOptional("allowable-clients", Section.AllowableClients); 286 IO.mapOptional("re-exports", Section.ReexportedLibraries); 287 IO.mapOptional("symbols", Section.Symbols); 288 IO.mapOptional("objc-classes", Section.Classes); 289 if (Ctx->FileKind == FileType::TBD_V3) 290 IO.mapOptional("objc-eh-types", Section.ClassEHs); 291 IO.mapOptional("objc-ivars", Section.IVars); 292 IO.mapOptional("weak-def-symbols", Section.WeakDefSymbols); 293 IO.mapOptional("thread-local-symbols", Section.TLVSymbols); 294 } 295 }; 296 297 template <> struct MappingTraits<UndefinedSection> { 298 static void mapping(IO &IO, UndefinedSection &Section) { 299 const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 300 assert((!Ctx || Ctx->FileKind != FileType::Invalid) && 301 "File type is not set in YAML context"); 302 303 IO.mapRequired("archs", Section.Architectures); 304 IO.mapOptional("symbols", Section.Symbols); 305 IO.mapOptional("objc-classes", Section.Classes); 306 if (Ctx->FileKind == FileType::TBD_V3) 307 IO.mapOptional("objc-eh-types", Section.ClassEHs); 308 IO.mapOptional("objc-ivars", Section.IVars); 309 IO.mapOptional("weak-ref-symbols", Section.WeakRefSymbols); 310 } 311 }; 312 313 template <> struct MappingTraits<SymbolSection> { 314 static void mapping(IO &IO, SymbolSection &Section) { 315 IO.mapRequired("targets", Section.Targets); 316 IO.mapOptional("symbols", Section.Symbols); 317 IO.mapOptional("objc-classes", Section.Classes); 318 IO.mapOptional("objc-eh-types", Section.ClassEHs); 319 IO.mapOptional("objc-ivars", Section.Ivars); 320 IO.mapOptional("weak-symbols", Section.WeakSymbols); 321 IO.mapOptional("thread-local-symbols", Section.TlvSymbols); 322 } 323 }; 324 325 template <> struct MappingTraits<UmbrellaSection> { 326 static void mapping(IO &IO, UmbrellaSection &Section) { 327 IO.mapRequired("targets", Section.Targets); 328 IO.mapRequired("umbrella", Section.Umbrella); 329 } 330 }; 331 332 template <> struct MappingTraits<UUIDv4> { 333 static void mapping(IO &IO, UUIDv4 &UUID) { 334 IO.mapRequired("target", UUID.TargetID); 335 IO.mapRequired("value", UUID.Value); 336 } 337 }; 338 339 template <> 340 struct MappingContextTraits<MetadataSection, MetadataSection::Option> { 341 static void mapping(IO &IO, MetadataSection &Section, 342 MetadataSection::Option &OptionKind) { 343 IO.mapRequired("targets", Section.Targets); 344 switch (OptionKind) { 345 case MetadataSection::Option::Clients: 346 IO.mapRequired("clients", Section.Values); 347 return; 348 case MetadataSection::Option::Libraries: 349 IO.mapRequired("libraries", Section.Values); 350 return; 351 } 352 llvm_unreachable("unexpected option for metadata"); 353 } 354 }; 355 356 template <> struct ScalarBitSetTraits<TBDFlags> { 357 static void bitset(IO &IO, TBDFlags &Flags) { 358 IO.bitSetCase(Flags, "flat_namespace", TBDFlags::FlatNamespace); 359 IO.bitSetCase(Flags, "not_app_extension_safe", 360 TBDFlags::NotApplicationExtensionSafe); 361 IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI); 362 IO.bitSetCase(Flags, "not_for_dyld_shared_cache", 363 TBDFlags::OSLibNotForSharedCache); 364 } 365 }; 366 367 template <> struct ScalarTraits<Target> { 368 static void output(const Target &Value, void *, raw_ostream &OS) { 369 OS << Value.Arch << "-"; 370 switch (Value.Platform) { 371 #define PLATFORM(platform, id, name, build_name, target, tapi_target, \ 372 marketing) \ 373 case PLATFORM_##platform: \ 374 OS << #tapi_target; \ 375 break; 376 #include "llvm/BinaryFormat/MachO.def" 377 } 378 } 379 380 static StringRef input(StringRef Scalar, void *, Target &Value) { 381 auto Result = Target::create(Scalar); 382 if (!Result) { 383 consumeError(Result.takeError()); 384 return "unparsable target"; 385 } 386 387 Value = *Result; 388 if (Value.Arch == AK_unknown) 389 return "unknown architecture"; 390 if (Value.Platform == PLATFORM_UNKNOWN) 391 return "unknown platform"; 392 393 return {}; 394 } 395 396 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 397 }; 398 399 template <> struct MappingTraits<const InterfaceFile *> { 400 struct NormalizedTBD { 401 explicit NormalizedTBD(IO &IO) {} 402 NormalizedTBD(IO &IO, const InterfaceFile *&File) { 403 Architectures = File->getArchitectures(); 404 Platforms = File->getPlatforms(); 405 InstallName = File->getInstallName(); 406 CurrentVersion = PackedVersion(File->getCurrentVersion()); 407 CompatibilityVersion = PackedVersion(File->getCompatibilityVersion()); 408 SwiftABIVersion = File->getSwiftABIVersion(); 409 ObjCConstraint = File->getObjCConstraint(); 410 411 Flags = TBDFlags::None; 412 if (!File->isApplicationExtensionSafe()) 413 Flags |= TBDFlags::NotApplicationExtensionSafe; 414 415 if (!File->isTwoLevelNamespace()) 416 Flags |= TBDFlags::FlatNamespace; 417 418 if (!File->umbrellas().empty()) 419 ParentUmbrella = File->umbrellas().begin()->second; 420 421 std::set<ArchitectureSet> ArchSet; 422 for (const auto &Library : File->allowableClients()) 423 ArchSet.insert(Library.getArchitectures()); 424 425 for (const auto &Library : File->reexportedLibraries()) 426 ArchSet.insert(Library.getArchitectures()); 427 428 std::map<const Symbol *, ArchitectureSet> SymbolToArchSet; 429 for (const auto *Symbol : File->symbols()) { 430 auto Architectures = Symbol->getArchitectures(); 431 SymbolToArchSet[Symbol] = Architectures; 432 ArchSet.insert(Architectures); 433 } 434 435 for (auto Architectures : ArchSet) { 436 ExportSection Section; 437 Section.Architectures = Architectures; 438 439 for (const auto &Library : File->allowableClients()) 440 if (Library.getArchitectures() == Architectures) 441 Section.AllowableClients.emplace_back(Library.getInstallName()); 442 443 for (const auto &Library : File->reexportedLibraries()) 444 if (Library.getArchitectures() == Architectures) 445 Section.ReexportedLibraries.emplace_back(Library.getInstallName()); 446 447 for (const auto &SymArch : SymbolToArchSet) { 448 if (SymArch.second != Architectures) 449 continue; 450 451 const auto *Symbol = SymArch.first; 452 switch (Symbol->getKind()) { 453 case EncodeKind::GlobalSymbol: 454 if (Symbol->isWeakDefined()) 455 Section.WeakDefSymbols.emplace_back(Symbol->getName()); 456 else if (Symbol->isThreadLocalValue()) 457 Section.TLVSymbols.emplace_back(Symbol->getName()); 458 else 459 Section.Symbols.emplace_back(Symbol->getName()); 460 break; 461 case EncodeKind::ObjectiveCClass: 462 if (File->getFileType() != FileType::TBD_V3) 463 Section.Classes.emplace_back( 464 copyString("_" + Symbol->getName().str())); 465 else 466 Section.Classes.emplace_back(Symbol->getName()); 467 break; 468 case EncodeKind::ObjectiveCClassEHType: 469 if (File->getFileType() != FileType::TBD_V3) 470 Section.Symbols.emplace_back( 471 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); 472 else 473 Section.ClassEHs.emplace_back(Symbol->getName()); 474 break; 475 case EncodeKind::ObjectiveCInstanceVariable: 476 if (File->getFileType() != FileType::TBD_V3) 477 Section.IVars.emplace_back( 478 copyString("_" + Symbol->getName().str())); 479 else 480 Section.IVars.emplace_back(Symbol->getName()); 481 break; 482 } 483 } 484 llvm::sort(Section.Symbols); 485 llvm::sort(Section.Classes); 486 llvm::sort(Section.ClassEHs); 487 llvm::sort(Section.IVars); 488 llvm::sort(Section.WeakDefSymbols); 489 llvm::sort(Section.TLVSymbols); 490 Exports.emplace_back(std::move(Section)); 491 } 492 493 ArchSet.clear(); 494 SymbolToArchSet.clear(); 495 496 for (const auto *Symbol : File->undefineds()) { 497 auto Architectures = Symbol->getArchitectures(); 498 SymbolToArchSet[Symbol] = Architectures; 499 ArchSet.insert(Architectures); 500 } 501 502 for (auto Architectures : ArchSet) { 503 UndefinedSection Section; 504 Section.Architectures = Architectures; 505 506 for (const auto &SymArch : SymbolToArchSet) { 507 if (SymArch.second != Architectures) 508 continue; 509 510 const auto *Symbol = SymArch.first; 511 switch (Symbol->getKind()) { 512 case EncodeKind::GlobalSymbol: 513 if (Symbol->isWeakReferenced()) 514 Section.WeakRefSymbols.emplace_back(Symbol->getName()); 515 else 516 Section.Symbols.emplace_back(Symbol->getName()); 517 break; 518 case EncodeKind::ObjectiveCClass: 519 if (File->getFileType() != FileType::TBD_V3) 520 Section.Classes.emplace_back( 521 copyString("_" + Symbol->getName().str())); 522 else 523 Section.Classes.emplace_back(Symbol->getName()); 524 break; 525 case EncodeKind::ObjectiveCClassEHType: 526 if (File->getFileType() != FileType::TBD_V3) 527 Section.Symbols.emplace_back( 528 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); 529 else 530 Section.ClassEHs.emplace_back(Symbol->getName()); 531 break; 532 case EncodeKind::ObjectiveCInstanceVariable: 533 if (File->getFileType() != FileType::TBD_V3) 534 Section.IVars.emplace_back( 535 copyString("_" + Symbol->getName().str())); 536 else 537 Section.IVars.emplace_back(Symbol->getName()); 538 break; 539 } 540 } 541 llvm::sort(Section.Symbols); 542 llvm::sort(Section.Classes); 543 llvm::sort(Section.ClassEHs); 544 llvm::sort(Section.IVars); 545 llvm::sort(Section.WeakRefSymbols); 546 Undefineds.emplace_back(std::move(Section)); 547 } 548 } 549 550 // TBD v1 - TBD v3 files only support one platform and several 551 // architectures. It is possible to have more than one platform for TBD v3 552 // files, but the architectures don't apply to all 553 // platforms, specifically to filter out the i386 slice from 554 // platform macCatalyst. 555 TargetList synthesizeTargets(ArchitectureSet Architectures, 556 const PlatformSet &Platforms) { 557 TargetList Targets; 558 559 for (auto Platform : Platforms) { 560 Platform = mapToPlatformType(Platform, Architectures.hasX86()); 561 562 for (const auto &&Architecture : Architectures) { 563 if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST)) 564 continue; 565 566 Targets.emplace_back(Architecture, Platform); 567 } 568 } 569 return Targets; 570 } 571 572 const InterfaceFile *denormalize(IO &IO) { 573 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 574 assert(Ctx); 575 576 auto *File = new InterfaceFile; 577 File->setPath(Ctx->Path); 578 File->setFileType(Ctx->FileKind); 579 File->addTargets(synthesizeTargets(Architectures, Platforms)); 580 File->setInstallName(InstallName); 581 File->setCurrentVersion(CurrentVersion); 582 File->setCompatibilityVersion(CompatibilityVersion); 583 File->setSwiftABIVersion(SwiftABIVersion); 584 File->setObjCConstraint(ObjCConstraint); 585 for (const auto &Target : File->targets()) 586 File->addParentUmbrella(Target, ParentUmbrella); 587 588 if (Ctx->FileKind == FileType::TBD_V1) { 589 File->setTwoLevelNamespace(); 590 File->setApplicationExtensionSafe(); 591 } else { 592 File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); 593 File->setApplicationExtensionSafe( 594 !(Flags & TBDFlags::NotApplicationExtensionSafe)); 595 } 596 597 // For older file formats, the segment where the symbol 598 // comes from is unknown, treat all symbols as Data 599 // in these cases. 600 const auto Flags = SymbolFlags::Data; 601 602 for (const auto &Section : Exports) { 603 const auto Targets = 604 synthesizeTargets(Section.Architectures, Platforms); 605 606 for (const auto &Lib : Section.AllowableClients) 607 for (const auto &Target : Targets) 608 File->addAllowableClient(Lib, Target); 609 610 for (const auto &Lib : Section.ReexportedLibraries) 611 for (const auto &Target : Targets) 612 File->addReexportedLibrary(Lib, Target); 613 614 for (const auto &Symbol : Section.Symbols) { 615 if (Ctx->FileKind != FileType::TBD_V3 && 616 Symbol.value.starts_with(ObjC2EHTypePrefix)) 617 File->addSymbol(EncodeKind::ObjectiveCClassEHType, 618 Symbol.value.drop_front(15), Targets, Flags); 619 else 620 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, Flags); 621 } 622 for (auto &Symbol : Section.Classes) { 623 auto Name = Symbol.value; 624 if (Ctx->FileKind != FileType::TBD_V3) 625 Name = Name.drop_front(); 626 File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets, Flags); 627 } 628 for (auto &Symbol : Section.ClassEHs) 629 File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets, 630 Flags); 631 for (auto &Symbol : Section.IVars) { 632 auto Name = Symbol.value; 633 if (Ctx->FileKind != FileType::TBD_V3) 634 Name = Name.drop_front(); 635 File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets, 636 Flags); 637 } 638 for (auto &Symbol : Section.WeakDefSymbols) 639 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, 640 SymbolFlags::WeakDefined | Flags); 641 for (auto &Symbol : Section.TLVSymbols) 642 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, 643 SymbolFlags::ThreadLocalValue | Flags); 644 } 645 646 for (const auto &Section : Undefineds) { 647 const auto Targets = 648 synthesizeTargets(Section.Architectures, Platforms); 649 for (auto &Symbol : Section.Symbols) { 650 if (Ctx->FileKind != FileType::TBD_V3 && 651 Symbol.value.starts_with(ObjC2EHTypePrefix)) 652 File->addSymbol(EncodeKind::ObjectiveCClassEHType, 653 Symbol.value.drop_front(15), Targets, 654 SymbolFlags::Undefined | Flags); 655 else 656 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, 657 SymbolFlags::Undefined | Flags); 658 } 659 for (auto &Symbol : Section.Classes) { 660 auto Name = Symbol.value; 661 if (Ctx->FileKind != FileType::TBD_V3) 662 Name = Name.drop_front(); 663 File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets, 664 SymbolFlags::Undefined | Flags); 665 } 666 for (auto &Symbol : Section.ClassEHs) 667 File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets, 668 SymbolFlags::Undefined | Flags); 669 for (auto &Symbol : Section.IVars) { 670 auto Name = Symbol.value; 671 if (Ctx->FileKind != FileType::TBD_V3) 672 Name = Name.drop_front(); 673 File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets, 674 SymbolFlags::Undefined | Flags); 675 } 676 for (auto &Symbol : Section.WeakRefSymbols) 677 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, 678 SymbolFlags::Undefined | SymbolFlags::WeakReferenced | 679 Flags); 680 } 681 682 return File; 683 } 684 685 llvm::BumpPtrAllocator Allocator; 686 StringRef copyString(StringRef String) { 687 if (String.empty()) 688 return {}; 689 690 void *Ptr = Allocator.Allocate(String.size(), 1); 691 memcpy(Ptr, String.data(), String.size()); 692 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 693 } 694 695 std::vector<Architecture> Architectures; 696 std::vector<UUID> UUIDs; 697 PlatformSet Platforms; 698 StringRef InstallName; 699 PackedVersion CurrentVersion; 700 PackedVersion CompatibilityVersion; 701 SwiftVersion SwiftABIVersion{0}; 702 ObjCConstraintType ObjCConstraint{ObjCConstraintType::None}; 703 TBDFlags Flags{TBDFlags::None}; 704 StringRef ParentUmbrella; 705 std::vector<ExportSection> Exports; 706 std::vector<UndefinedSection> Undefineds; 707 }; 708 709 static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) { 710 if (IO.mapTag("!tapi-tbd", false)) 711 Ctx->FileKind = FileType::TBD_V4; 712 else if (IO.mapTag("!tapi-tbd-v3", false)) 713 Ctx->FileKind = FileType::TBD_V3; 714 else if (IO.mapTag("!tapi-tbd-v2", false)) 715 Ctx->FileKind = FileType::TBD_V2; 716 else if (IO.mapTag("!tapi-tbd-v1", false) || 717 IO.mapTag("tag:yaml.org,2002:map", false)) 718 Ctx->FileKind = FileType::TBD_V1; 719 else { 720 Ctx->FileKind = FileType::Invalid; 721 return; 722 } 723 } 724 725 static void mapping(IO &IO, const InterfaceFile *&File) { 726 auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 727 assert((!Ctx || !IO.outputting() || 728 (Ctx && Ctx->FileKind != FileType::Invalid)) && 729 "File type is not set in YAML context"); 730 731 if (!IO.outputting()) { 732 setFileTypeForInput(Ctx, IO); 733 switch (Ctx->FileKind) { 734 default: 735 break; 736 case FileType::TBD_V4: 737 mapKeysToValuesV4(IO, File); 738 return; 739 case FileType::Invalid: 740 IO.setError("unsupported file type"); 741 return; 742 } 743 } else { 744 // Set file type when writing. 745 switch (Ctx->FileKind) { 746 default: 747 llvm_unreachable("unexpected file type"); 748 case FileType::TBD_V4: 749 mapKeysToValuesV4(IO, File); 750 return; 751 case FileType::TBD_V3: 752 IO.mapTag("!tapi-tbd-v3", true); 753 break; 754 case FileType::TBD_V2: 755 IO.mapTag("!tapi-tbd-v2", true); 756 break; 757 case FileType::TBD_V1: 758 // Don't write the tag into the .tbd file for TBD v1 759 break; 760 } 761 } 762 mapKeysToValues(Ctx->FileKind, IO, File); 763 } 764 765 using SectionList = std::vector<SymbolSection>; 766 struct NormalizedTBD_V4 { 767 explicit NormalizedTBD_V4(IO &IO) {} 768 NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) { 769 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 770 assert(Ctx); 771 TBDVersion = Ctx->FileKind >> 4; 772 Targets.insert(Targets.begin(), File->targets().begin(), 773 File->targets().end()); 774 InstallName = File->getInstallName(); 775 CurrentVersion = File->getCurrentVersion(); 776 CompatibilityVersion = File->getCompatibilityVersion(); 777 SwiftABIVersion = File->getSwiftABIVersion(); 778 779 Flags = TBDFlags::None; 780 if (!File->isApplicationExtensionSafe()) 781 Flags |= TBDFlags::NotApplicationExtensionSafe; 782 783 if (!File->isTwoLevelNamespace()) 784 Flags |= TBDFlags::FlatNamespace; 785 786 if (File->isOSLibNotForSharedCache()) 787 Flags |= TBDFlags::OSLibNotForSharedCache; 788 789 { 790 std::map<std::string, TargetList> valueToTargetList; 791 for (const auto &it : File->umbrellas()) 792 valueToTargetList[it.second].emplace_back(it.first); 793 794 for (const auto &it : valueToTargetList) { 795 UmbrellaSection CurrentSection; 796 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 797 it.second.begin(), it.second.end()); 798 CurrentSection.Umbrella = it.first; 799 ParentUmbrellas.emplace_back(std::move(CurrentSection)); 800 } 801 } 802 803 assignTargetsToLibrary(File->allowableClients(), AllowableClients); 804 assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries); 805 806 auto handleSymbols = 807 [](SectionList &CurrentSections, 808 InterfaceFile::const_filtered_symbol_range Symbols) { 809 std::set<TargetList> TargetSet; 810 std::map<const Symbol *, TargetList> SymbolToTargetList; 811 for (const auto *Symbol : Symbols) { 812 TargetList Targets(Symbol->targets()); 813 SymbolToTargetList[Symbol] = Targets; 814 TargetSet.emplace(std::move(Targets)); 815 } 816 for (const auto &TargetIDs : TargetSet) { 817 SymbolSection CurrentSection; 818 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 819 TargetIDs.begin(), TargetIDs.end()); 820 821 for (const auto &IT : SymbolToTargetList) { 822 if (IT.second != TargetIDs) 823 continue; 824 825 const auto *Symbol = IT.first; 826 switch (Symbol->getKind()) { 827 case EncodeKind::GlobalSymbol: 828 if (Symbol->isWeakDefined()) 829 CurrentSection.WeakSymbols.emplace_back(Symbol->getName()); 830 else if (Symbol->isThreadLocalValue()) 831 CurrentSection.TlvSymbols.emplace_back(Symbol->getName()); 832 else 833 CurrentSection.Symbols.emplace_back(Symbol->getName()); 834 break; 835 case EncodeKind::ObjectiveCClass: 836 CurrentSection.Classes.emplace_back(Symbol->getName()); 837 break; 838 case EncodeKind::ObjectiveCClassEHType: 839 CurrentSection.ClassEHs.emplace_back(Symbol->getName()); 840 break; 841 case EncodeKind::ObjectiveCInstanceVariable: 842 CurrentSection.Ivars.emplace_back(Symbol->getName()); 843 break; 844 } 845 } 846 sort(CurrentSection.Symbols); 847 sort(CurrentSection.Classes); 848 sort(CurrentSection.ClassEHs); 849 sort(CurrentSection.Ivars); 850 sort(CurrentSection.WeakSymbols); 851 sort(CurrentSection.TlvSymbols); 852 CurrentSections.emplace_back(std::move(CurrentSection)); 853 } 854 }; 855 856 handleSymbols(Exports, File->exports()); 857 handleSymbols(Reexports, File->reexports()); 858 handleSymbols(Undefineds, File->undefineds()); 859 } 860 861 const InterfaceFile *denormalize(IO &IO) { 862 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 863 assert(Ctx); 864 865 auto *File = new InterfaceFile; 866 File->setPath(Ctx->Path); 867 File->setFileType(Ctx->FileKind); 868 File->addTargets(Targets); 869 File->setInstallName(InstallName); 870 File->setCurrentVersion(CurrentVersion); 871 File->setCompatibilityVersion(CompatibilityVersion); 872 File->setSwiftABIVersion(SwiftABIVersion); 873 for (const auto &CurrentSection : ParentUmbrellas) 874 for (const auto &target : CurrentSection.Targets) 875 File->addParentUmbrella(target, CurrentSection.Umbrella); 876 File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); 877 File->setApplicationExtensionSafe( 878 !(Flags & TBDFlags::NotApplicationExtensionSafe)); 879 File->setOSLibNotForSharedCache( 880 (Flags & TBDFlags::OSLibNotForSharedCache)); 881 882 for (const auto &CurrentSection : AllowableClients) { 883 for (const auto &lib : CurrentSection.Values) 884 for (const auto &Target : CurrentSection.Targets) 885 File->addAllowableClient(lib, Target); 886 } 887 888 for (const auto &CurrentSection : ReexportedLibraries) { 889 for (const auto &Lib : CurrentSection.Values) 890 for (const auto &Target : CurrentSection.Targets) 891 File->addReexportedLibrary(Lib, Target); 892 } 893 894 auto handleSymbols = [File](const SectionList &CurrentSections, 895 SymbolFlags InputFlag = SymbolFlags::None) { 896 // For older file formats, the segment where the symbol 897 // comes from is unknown, treat all symbols as Data 898 // in these cases. 899 const SymbolFlags Flag = InputFlag | SymbolFlags::Data; 900 901 for (const auto &CurrentSection : CurrentSections) { 902 for (auto &sym : CurrentSection.Symbols) 903 File->addSymbol(EncodeKind::GlobalSymbol, sym, 904 CurrentSection.Targets, Flag); 905 906 for (auto &sym : CurrentSection.Classes) 907 File->addSymbol(EncodeKind::ObjectiveCClass, sym, 908 CurrentSection.Targets, Flag); 909 910 for (auto &sym : CurrentSection.ClassEHs) 911 File->addSymbol(EncodeKind::ObjectiveCClassEHType, sym, 912 CurrentSection.Targets, Flag); 913 914 for (auto &sym : CurrentSection.Ivars) 915 File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, sym, 916 CurrentSection.Targets, Flag); 917 918 SymbolFlags SymFlag = 919 ((Flag & SymbolFlags::Undefined) == SymbolFlags::Undefined) 920 ? SymbolFlags::WeakReferenced 921 : SymbolFlags::WeakDefined; 922 for (auto &sym : CurrentSection.WeakSymbols) { 923 File->addSymbol(EncodeKind::GlobalSymbol, sym, 924 CurrentSection.Targets, Flag | SymFlag); 925 } 926 927 for (auto &sym : CurrentSection.TlvSymbols) 928 File->addSymbol(EncodeKind::GlobalSymbol, sym, 929 CurrentSection.Targets, 930 Flag | SymbolFlags::ThreadLocalValue); 931 } 932 }; 933 934 handleSymbols(Exports); 935 handleSymbols(Reexports, SymbolFlags::Rexported); 936 handleSymbols(Undefineds, SymbolFlags::Undefined); 937 938 return File; 939 } 940 941 unsigned TBDVersion; 942 std::vector<UUIDv4> UUIDs; 943 TargetList Targets; 944 StringRef InstallName; 945 PackedVersion CurrentVersion; 946 PackedVersion CompatibilityVersion; 947 SwiftVersion SwiftABIVersion{0}; 948 std::vector<MetadataSection> AllowableClients; 949 std::vector<MetadataSection> ReexportedLibraries; 950 TBDFlags Flags{TBDFlags::None}; 951 std::vector<UmbrellaSection> ParentUmbrellas; 952 SectionList Exports; 953 SectionList Reexports; 954 SectionList Undefineds; 955 956 private: 957 void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries, 958 std::vector<MetadataSection> &Section) { 959 std::set<TargetList> targetSet; 960 std::map<const InterfaceFileRef *, TargetList> valueToTargetList; 961 for (const auto &library : Libraries) { 962 TargetList targets(library.targets()); 963 valueToTargetList[&library] = targets; 964 targetSet.emplace(std::move(targets)); 965 } 966 967 for (const auto &targets : targetSet) { 968 MetadataSection CurrentSection; 969 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 970 targets.begin(), targets.end()); 971 972 for (const auto &it : valueToTargetList) { 973 if (it.second != targets) 974 continue; 975 976 CurrentSection.Values.emplace_back(it.first->getInstallName()); 977 } 978 llvm::sort(CurrentSection.Values); 979 Section.emplace_back(std::move(CurrentSection)); 980 } 981 } 982 }; 983 984 static void mapKeysToValues(FileType FileKind, IO &IO, 985 const InterfaceFile *&File) { 986 MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File); 987 std::vector<UUID> EmptyUUID; 988 IO.mapRequired("archs", Keys->Architectures); 989 if (FileKind != FileType::TBD_V1) 990 IO.mapOptional("uuids", EmptyUUID); 991 IO.mapRequired("platform", Keys->Platforms); 992 if (FileKind != FileType::TBD_V1) 993 IO.mapOptional("flags", Keys->Flags, TBDFlags::None); 994 IO.mapRequired("install-name", Keys->InstallName); 995 IO.mapOptional("current-version", Keys->CurrentVersion, 996 PackedVersion(1, 0, 0)); 997 IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, 998 PackedVersion(1, 0, 0)); 999 if (FileKind != FileType::TBD_V3) 1000 IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0)); 1001 else 1002 IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, 1003 SwiftVersion(0)); 1004 IO.mapOptional("objc-constraint", Keys->ObjCConstraint, 1005 (FileKind == FileType::TBD_V1) 1006 ? ObjCConstraintType::None 1007 : ObjCConstraintType::Retain_Release); 1008 if (FileKind != FileType::TBD_V1) 1009 IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef()); 1010 IO.mapOptional("exports", Keys->Exports); 1011 if (FileKind != FileType::TBD_V1) 1012 IO.mapOptional("undefineds", Keys->Undefineds); 1013 } 1014 1015 static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) { 1016 MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO, 1017 File); 1018 std::vector<UUIDv4> EmptyUUID; 1019 IO.mapTag("!tapi-tbd", true); 1020 IO.mapRequired("tbd-version", Keys->TBDVersion); 1021 IO.mapRequired("targets", Keys->Targets); 1022 IO.mapOptional("uuids", EmptyUUID); 1023 IO.mapOptional("flags", Keys->Flags, TBDFlags::None); 1024 IO.mapRequired("install-name", Keys->InstallName); 1025 IO.mapOptional("current-version", Keys->CurrentVersion, 1026 PackedVersion(1, 0, 0)); 1027 IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, 1028 PackedVersion(1, 0, 0)); 1029 IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0)); 1030 IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas); 1031 auto OptionKind = MetadataSection::Option::Clients; 1032 IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients, 1033 OptionKind); 1034 OptionKind = MetadataSection::Option::Libraries; 1035 IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries, 1036 OptionKind); 1037 IO.mapOptional("exports", Keys->Exports); 1038 IO.mapOptional("reexports", Keys->Reexports); 1039 IO.mapOptional("undefineds", Keys->Undefineds); 1040 } 1041 }; 1042 1043 template <> 1044 struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> { 1045 static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) { 1046 return Seq.size(); 1047 } 1048 static const InterfaceFile *& 1049 element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) { 1050 if (Index >= Seq.size()) 1051 Seq.resize(Index + 1); 1052 return Seq[Index]; 1053 } 1054 }; 1055 1056 } // end namespace yaml. 1057 } // namespace llvm 1058 1059 static void DiagHandler(const SMDiagnostic &Diag, void *Context) { 1060 auto *File = static_cast<TextAPIContext *>(Context); 1061 SmallString<1024> Message; 1062 raw_svector_ostream S(Message); 1063 1064 SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path, 1065 Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(), 1066 Diag.getMessage(), Diag.getLineContents(), 1067 Diag.getRanges(), Diag.getFixIts()); 1068 1069 NewDiag.print(nullptr, S); 1070 File->ErrorMessage = ("malformed file\n" + Message).str(); 1071 } 1072 1073 Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) { 1074 auto TAPIFile = InputBuffer.getBuffer().trim(); 1075 if (TAPIFile.starts_with("{") && TAPIFile.ends_with("}")) 1076 return FileType::TBD_V5; 1077 1078 if (!TAPIFile.ends_with("...")) 1079 return createStringError(std::errc::not_supported, "unsupported file type"); 1080 1081 if (TAPIFile.starts_with("--- !tapi-tbd")) 1082 return FileType::TBD_V4; 1083 1084 if (TAPIFile.starts_with("--- !tapi-tbd-v3")) 1085 return FileType::TBD_V3; 1086 1087 if (TAPIFile.starts_with("--- !tapi-tbd-v2")) 1088 return FileType::TBD_V2; 1089 1090 if (TAPIFile.starts_with("--- !tapi-tbd-v1") || 1091 TAPIFile.starts_with("---\narchs:")) 1092 return FileType::TBD_V1; 1093 1094 return createStringError(std::errc::not_supported, "unsupported file type"); 1095 } 1096 1097 Expected<std::unique_ptr<InterfaceFile>> 1098 TextAPIReader::get(MemoryBufferRef InputBuffer) { 1099 TextAPIContext Ctx; 1100 Ctx.Path = std::string(InputBuffer.getBufferIdentifier()); 1101 if (auto FTOrErr = canRead(InputBuffer)) 1102 Ctx.FileKind = *FTOrErr; 1103 else 1104 return FTOrErr.takeError(); 1105 1106 // Handle JSON Format. 1107 if (Ctx.FileKind >= FileType::TBD_V5) { 1108 auto FileOrErr = getInterfaceFileFromJSON(InputBuffer.getBuffer()); 1109 if (!FileOrErr) 1110 return FileOrErr.takeError(); 1111 1112 (*FileOrErr)->setPath(Ctx.Path); 1113 return std::move(*FileOrErr); 1114 } 1115 yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx); 1116 1117 // Fill vector with interface file objects created by parsing the YAML file. 1118 std::vector<const InterfaceFile *> Files; 1119 YAMLIn >> Files; 1120 1121 // YAMLIn dynamically allocates for Interface file and in case of error, 1122 // memory leak will occur unless wrapped around unique_ptr 1123 auto File = std::unique_ptr<InterfaceFile>( 1124 const_cast<InterfaceFile *>(Files.front())); 1125 1126 for (const InterfaceFile *FI : llvm::drop_begin(Files)) 1127 File->addDocument( 1128 std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI))); 1129 1130 if (YAMLIn.error()) 1131 return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error()); 1132 1133 return std::move(File); 1134 } 1135 1136 Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File, 1137 const FileType FileKind, bool Compact) { 1138 TextAPIContext Ctx; 1139 Ctx.Path = std::string(File.getPath()); 1140 1141 // Prefer parameter for format if passed, otherwise fallback to the File 1142 // FileType. 1143 Ctx.FileKind = 1144 (FileKind == FileType::Invalid) ? File.getFileType() : FileKind; 1145 1146 // Write out in JSON format. 1147 if (Ctx.FileKind >= FileType::TBD_V5) { 1148 return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact); 1149 } 1150 1151 llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80); 1152 1153 std::vector<const InterfaceFile *> Files; 1154 Files.emplace_back(&File); 1155 1156 for (const auto &Document : File.documents()) 1157 Files.emplace_back(Document.get()); 1158 1159 // Stream out yaml. 1160 YAMLOut << Files; 1161 1162 return Error::success(); 1163 } 1164