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