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 Platforms = File->getPlatforms(); 431 InstallName = File->getInstallName(); 432 CurrentVersion = PackedVersion(File->getCurrentVersion()); 433 CompatibilityVersion = PackedVersion(File->getCompatibilityVersion()); 434 SwiftABIVersion = File->getSwiftABIVersion(); 435 ObjCConstraint = File->getObjCConstraint(); 436 437 Flags = TBDFlags::None; 438 if (!File->isApplicationExtensionSafe()) 439 Flags |= TBDFlags::NotApplicationExtensionSafe; 440 441 if (!File->isTwoLevelNamespace()) 442 Flags |= TBDFlags::FlatNamespace; 443 444 if (!File->umbrellas().empty()) 445 ParentUmbrella = File->umbrellas().begin()->second; 446 447 std::set<ArchitectureSet> ArchSet; 448 for (const auto &Library : File->allowableClients()) 449 ArchSet.insert(Library.getArchitectures()); 450 451 for (const auto &Library : File->reexportedLibraries()) 452 ArchSet.insert(Library.getArchitectures()); 453 454 std::map<const Symbol *, ArchitectureSet> SymbolToArchSet; 455 for (const auto *Symbol : File->symbols()) { 456 auto Architectures = Symbol->getArchitectures(); 457 SymbolToArchSet[Symbol] = Architectures; 458 ArchSet.insert(Architectures); 459 } 460 461 for (auto Architectures : ArchSet) { 462 ExportSection Section; 463 Section.Architectures = Architectures; 464 465 for (const auto &Library : File->allowableClients()) 466 if (Library.getArchitectures() == Architectures) 467 Section.AllowableClients.emplace_back(Library.getInstallName()); 468 469 for (const auto &Library : File->reexportedLibraries()) 470 if (Library.getArchitectures() == Architectures) 471 Section.ReexportedLibraries.emplace_back(Library.getInstallName()); 472 473 for (const auto &SymArch : SymbolToArchSet) { 474 if (SymArch.second != Architectures) 475 continue; 476 477 const auto *Symbol = SymArch.first; 478 switch (Symbol->getKind()) { 479 case SymbolKind::GlobalSymbol: 480 if (Symbol->isWeakDefined()) 481 Section.WeakDefSymbols.emplace_back(Symbol->getName()); 482 else if (Symbol->isThreadLocalValue()) 483 Section.TLVSymbols.emplace_back(Symbol->getName()); 484 else 485 Section.Symbols.emplace_back(Symbol->getName()); 486 break; 487 case SymbolKind::ObjectiveCClass: 488 if (File->getFileType() != FileType::TBD_V3) 489 Section.Classes.emplace_back( 490 copyString("_" + Symbol->getName().str())); 491 else 492 Section.Classes.emplace_back(Symbol->getName()); 493 break; 494 case SymbolKind::ObjectiveCClassEHType: 495 if (File->getFileType() != FileType::TBD_V3) 496 Section.Symbols.emplace_back( 497 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); 498 else 499 Section.ClassEHs.emplace_back(Symbol->getName()); 500 break; 501 case SymbolKind::ObjectiveCInstanceVariable: 502 if (File->getFileType() != FileType::TBD_V3) 503 Section.IVars.emplace_back( 504 copyString("_" + Symbol->getName().str())); 505 else 506 Section.IVars.emplace_back(Symbol->getName()); 507 break; 508 } 509 } 510 llvm::sort(Section.Symbols); 511 llvm::sort(Section.Classes); 512 llvm::sort(Section.ClassEHs); 513 llvm::sort(Section.IVars); 514 llvm::sort(Section.WeakDefSymbols); 515 llvm::sort(Section.TLVSymbols); 516 Exports.emplace_back(std::move(Section)); 517 } 518 519 ArchSet.clear(); 520 SymbolToArchSet.clear(); 521 522 for (const auto *Symbol : File->undefineds()) { 523 auto Architectures = Symbol->getArchitectures(); 524 SymbolToArchSet[Symbol] = Architectures; 525 ArchSet.insert(Architectures); 526 } 527 528 for (auto Architectures : ArchSet) { 529 UndefinedSection Section; 530 Section.Architectures = Architectures; 531 532 for (const auto &SymArch : SymbolToArchSet) { 533 if (SymArch.second != Architectures) 534 continue; 535 536 const auto *Symbol = SymArch.first; 537 switch (Symbol->getKind()) { 538 case SymbolKind::GlobalSymbol: 539 if (Symbol->isWeakReferenced()) 540 Section.WeakRefSymbols.emplace_back(Symbol->getName()); 541 else 542 Section.Symbols.emplace_back(Symbol->getName()); 543 break; 544 case SymbolKind::ObjectiveCClass: 545 if (File->getFileType() != FileType::TBD_V3) 546 Section.Classes.emplace_back( 547 copyString("_" + Symbol->getName().str())); 548 else 549 Section.Classes.emplace_back(Symbol->getName()); 550 break; 551 case SymbolKind::ObjectiveCClassEHType: 552 if (File->getFileType() != FileType::TBD_V3) 553 Section.Symbols.emplace_back( 554 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); 555 else 556 Section.ClassEHs.emplace_back(Symbol->getName()); 557 break; 558 case SymbolKind::ObjectiveCInstanceVariable: 559 if (File->getFileType() != FileType::TBD_V3) 560 Section.IVars.emplace_back( 561 copyString("_" + Symbol->getName().str())); 562 else 563 Section.IVars.emplace_back(Symbol->getName()); 564 break; 565 } 566 } 567 llvm::sort(Section.Symbols); 568 llvm::sort(Section.Classes); 569 llvm::sort(Section.ClassEHs); 570 llvm::sort(Section.IVars); 571 llvm::sort(Section.WeakRefSymbols); 572 Undefineds.emplace_back(std::move(Section)); 573 } 574 } 575 576 // TBD v1 - TBD v3 files only support one platform and several 577 // architectures. It is possible to have more than one platform for TBD v3 578 // files, but the architectures don't apply to all 579 // platforms, specifically to filter out the i386 slice from 580 // platform macCatalyst. 581 TargetList synthesizeTargets(ArchitectureSet Architectures, 582 const PlatformSet &Platforms) { 583 TargetList Targets; 584 585 for (auto Platform : Platforms) { 586 Platform = mapToPlatformType(Platform, Architectures.hasX86()); 587 588 for (const auto &&Architecture : Architectures) { 589 if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST)) 590 continue; 591 592 Targets.emplace_back(Architecture, Platform); 593 } 594 } 595 return Targets; 596 } 597 598 const InterfaceFile *denormalize(IO &IO) { 599 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 600 assert(Ctx); 601 602 auto *File = new InterfaceFile; 603 File->setPath(Ctx->Path); 604 File->setFileType(Ctx->FileKind); 605 File->addTargets(synthesizeTargets(Architectures, Platforms)); 606 File->setInstallName(InstallName); 607 File->setCurrentVersion(CurrentVersion); 608 File->setCompatibilityVersion(CompatibilityVersion); 609 File->setSwiftABIVersion(SwiftABIVersion); 610 File->setObjCConstraint(ObjCConstraint); 611 for (const auto &Target : File->targets()) 612 File->addParentUmbrella(Target, ParentUmbrella); 613 614 if (Ctx->FileKind == FileType::TBD_V1) { 615 File->setTwoLevelNamespace(); 616 File->setApplicationExtensionSafe(); 617 } else { 618 File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); 619 File->setApplicationExtensionSafe( 620 !(Flags & TBDFlags::NotApplicationExtensionSafe)); 621 } 622 623 // For older file formats, the segment where the symbol 624 // comes from is unknown, treat all symbols as Data 625 // in these cases. 626 const auto Flags = SymbolFlags::Data; 627 628 for (const auto &Section : Exports) { 629 const auto Targets = 630 synthesizeTargets(Section.Architectures, Platforms); 631 632 for (const auto &Lib : Section.AllowableClients) 633 for (const auto &Target : Targets) 634 File->addAllowableClient(Lib, Target); 635 636 for (const auto &Lib : Section.ReexportedLibraries) 637 for (const auto &Target : Targets) 638 File->addReexportedLibrary(Lib, Target); 639 640 for (const auto &Symbol : Section.Symbols) { 641 if (Ctx->FileKind != FileType::TBD_V3 && 642 Symbol.value.startswith(ObjC2EHTypePrefix)) 643 File->addSymbol(SymbolKind::ObjectiveCClassEHType, 644 Symbol.value.drop_front(15), Targets, Flags); 645 else 646 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, Flags); 647 } 648 for (auto &Symbol : Section.Classes) { 649 auto Name = Symbol.value; 650 if (Ctx->FileKind != FileType::TBD_V3) 651 Name = Name.drop_front(); 652 File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets, Flags); 653 } 654 for (auto &Symbol : Section.ClassEHs) 655 File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets, 656 Flags); 657 for (auto &Symbol : Section.IVars) { 658 auto Name = Symbol.value; 659 if (Ctx->FileKind != FileType::TBD_V3) 660 Name = Name.drop_front(); 661 File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets, 662 Flags); 663 } 664 for (auto &Symbol : Section.WeakDefSymbols) 665 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, 666 SymbolFlags::WeakDefined); 667 for (auto &Symbol : Section.TLVSymbols) 668 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, 669 SymbolFlags::ThreadLocalValue); 670 } 671 672 for (const auto &Section : Undefineds) { 673 const auto Targets = 674 synthesizeTargets(Section.Architectures, Platforms); 675 for (auto &Symbol : Section.Symbols) { 676 if (Ctx->FileKind != FileType::TBD_V3 && 677 Symbol.value.startswith(ObjC2EHTypePrefix)) 678 File->addSymbol(SymbolKind::ObjectiveCClassEHType, 679 Symbol.value.drop_front(15), Targets, 680 SymbolFlags::Undefined | Flags); 681 else 682 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, 683 SymbolFlags::Undefined | Flags); 684 } 685 for (auto &Symbol : Section.Classes) { 686 auto Name = Symbol.value; 687 if (Ctx->FileKind != FileType::TBD_V3) 688 Name = Name.drop_front(); 689 File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets, 690 SymbolFlags::Undefined | Flags); 691 } 692 for (auto &Symbol : Section.ClassEHs) 693 File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets, 694 SymbolFlags::Undefined | Flags); 695 for (auto &Symbol : Section.IVars) { 696 auto Name = Symbol.value; 697 if (Ctx->FileKind != FileType::TBD_V3) 698 Name = Name.drop_front(); 699 File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets, 700 SymbolFlags::Undefined | Flags); 701 } 702 for (auto &Symbol : Section.WeakRefSymbols) 703 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, 704 SymbolFlags::Undefined | SymbolFlags::WeakReferenced | 705 Flags); 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 >> 4; 798 Targets.insert(Targets.begin(), File->targets().begin(), 799 File->targets().end()); 800 InstallName = File->getInstallName(); 801 CurrentVersion = File->getCurrentVersion(); 802 CompatibilityVersion = File->getCompatibilityVersion(); 803 SwiftABIVersion = File->getSwiftABIVersion(); 804 805 Flags = TBDFlags::None; 806 if (!File->isApplicationExtensionSafe()) 807 Flags |= TBDFlags::NotApplicationExtensionSafe; 808 809 if (!File->isTwoLevelNamespace()) 810 Flags |= TBDFlags::FlatNamespace; 811 812 { 813 std::map<std::string, TargetList> valueToTargetList; 814 for (const auto &it : File->umbrellas()) 815 valueToTargetList[it.second].emplace_back(it.first); 816 817 for (const auto &it : valueToTargetList) { 818 UmbrellaSection CurrentSection; 819 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 820 it.second.begin(), it.second.end()); 821 CurrentSection.Umbrella = it.first; 822 ParentUmbrellas.emplace_back(std::move(CurrentSection)); 823 } 824 } 825 826 assignTargetsToLibrary(File->allowableClients(), AllowableClients); 827 assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries); 828 829 auto handleSymbols = 830 [](SectionList &CurrentSections, 831 InterfaceFile::const_filtered_symbol_range Symbols) { 832 std::set<TargetList> TargetSet; 833 std::map<const Symbol *, TargetList> SymbolToTargetList; 834 for (const auto *Symbol : Symbols) { 835 TargetList Targets(Symbol->targets()); 836 SymbolToTargetList[Symbol] = Targets; 837 TargetSet.emplace(std::move(Targets)); 838 } 839 for (const auto &TargetIDs : TargetSet) { 840 SymbolSection CurrentSection; 841 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 842 TargetIDs.begin(), TargetIDs.end()); 843 844 for (const auto &IT : SymbolToTargetList) { 845 if (IT.second != TargetIDs) 846 continue; 847 848 const auto *Symbol = IT.first; 849 switch (Symbol->getKind()) { 850 case SymbolKind::GlobalSymbol: 851 if (Symbol->isWeakDefined()) 852 CurrentSection.WeakSymbols.emplace_back(Symbol->getName()); 853 else if (Symbol->isThreadLocalValue()) 854 CurrentSection.TlvSymbols.emplace_back(Symbol->getName()); 855 else 856 CurrentSection.Symbols.emplace_back(Symbol->getName()); 857 break; 858 case SymbolKind::ObjectiveCClass: 859 CurrentSection.Classes.emplace_back(Symbol->getName()); 860 break; 861 case SymbolKind::ObjectiveCClassEHType: 862 CurrentSection.ClassEHs.emplace_back(Symbol->getName()); 863 break; 864 case SymbolKind::ObjectiveCInstanceVariable: 865 CurrentSection.Ivars.emplace_back(Symbol->getName()); 866 break; 867 } 868 } 869 sort(CurrentSection.Symbols); 870 sort(CurrentSection.Classes); 871 sort(CurrentSection.ClassEHs); 872 sort(CurrentSection.Ivars); 873 sort(CurrentSection.WeakSymbols); 874 sort(CurrentSection.TlvSymbols); 875 CurrentSections.emplace_back(std::move(CurrentSection)); 876 } 877 }; 878 879 handleSymbols(Exports, File->exports()); 880 handleSymbols(Reexports, File->reexports()); 881 handleSymbols(Undefineds, File->undefineds()); 882 } 883 884 const InterfaceFile *denormalize(IO &IO) { 885 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 886 assert(Ctx); 887 888 auto *File = new InterfaceFile; 889 File->setPath(Ctx->Path); 890 File->setFileType(Ctx->FileKind); 891 File->addTargets(Targets); 892 File->setInstallName(InstallName); 893 File->setCurrentVersion(CurrentVersion); 894 File->setCompatibilityVersion(CompatibilityVersion); 895 File->setSwiftABIVersion(SwiftABIVersion); 896 for (const auto &CurrentSection : ParentUmbrellas) 897 for (const auto &target : CurrentSection.Targets) 898 File->addParentUmbrella(target, CurrentSection.Umbrella); 899 File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); 900 File->setApplicationExtensionSafe( 901 !(Flags & TBDFlags::NotApplicationExtensionSafe)); 902 903 for (const auto &CurrentSection : AllowableClients) { 904 for (const auto &lib : CurrentSection.Values) 905 for (const auto &Target : CurrentSection.Targets) 906 File->addAllowableClient(lib, Target); 907 } 908 909 for (const auto &CurrentSection : ReexportedLibraries) { 910 for (const auto &Lib : CurrentSection.Values) 911 for (const auto &Target : CurrentSection.Targets) 912 File->addReexportedLibrary(Lib, Target); 913 } 914 915 auto handleSymbols = [File](const SectionList &CurrentSections, 916 SymbolFlags InputFlag = SymbolFlags::None) { 917 // For older file formats, the segment where the symbol 918 // comes from is unknown, treat all symbols as Data 919 // in these cases. 920 const SymbolFlags Flag = InputFlag | SymbolFlags::Data; 921 922 for (const auto &CurrentSection : CurrentSections) { 923 for (auto &sym : CurrentSection.Symbols) 924 File->addSymbol(SymbolKind::GlobalSymbol, sym, 925 CurrentSection.Targets, Flag); 926 927 for (auto &sym : CurrentSection.Classes) 928 File->addSymbol(SymbolKind::ObjectiveCClass, sym, 929 CurrentSection.Targets, Flag); 930 931 for (auto &sym : CurrentSection.ClassEHs) 932 File->addSymbol(SymbolKind::ObjectiveCClassEHType, sym, 933 CurrentSection.Targets, Flag); 934 935 for (auto &sym : CurrentSection.Ivars) 936 File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, sym, 937 CurrentSection.Targets, Flag); 938 939 SymbolFlags SymFlag = 940 ((Flag & SymbolFlags::Undefined) == SymbolFlags::Undefined) 941 ? SymbolFlags::WeakReferenced 942 : SymbolFlags::WeakDefined; 943 for (auto &sym : CurrentSection.WeakSymbols) { 944 File->addSymbol(SymbolKind::GlobalSymbol, sym, 945 CurrentSection.Targets, Flag | SymFlag); 946 } 947 948 for (auto &sym : CurrentSection.TlvSymbols) 949 File->addSymbol(SymbolKind::GlobalSymbol, sym, 950 CurrentSection.Targets, 951 Flag | SymbolFlags::ThreadLocalValue); 952 } 953 }; 954 955 handleSymbols(Exports); 956 handleSymbols(Reexports, SymbolFlags::Rexported); 957 handleSymbols(Undefineds, SymbolFlags::Undefined); 958 959 return File; 960 } 961 962 unsigned TBDVersion; 963 std::vector<UUIDv4> UUIDs; 964 TargetList Targets; 965 StringRef InstallName; 966 PackedVersion CurrentVersion; 967 PackedVersion CompatibilityVersion; 968 SwiftVersion SwiftABIVersion{0}; 969 std::vector<MetadataSection> AllowableClients; 970 std::vector<MetadataSection> ReexportedLibraries; 971 TBDFlags Flags{TBDFlags::None}; 972 std::vector<UmbrellaSection> ParentUmbrellas; 973 SectionList Exports; 974 SectionList Reexports; 975 SectionList Undefineds; 976 977 private: 978 void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries, 979 std::vector<MetadataSection> &Section) { 980 std::set<TargetList> targetSet; 981 std::map<const InterfaceFileRef *, TargetList> valueToTargetList; 982 for (const auto &library : Libraries) { 983 TargetList targets(library.targets()); 984 valueToTargetList[&library] = targets; 985 targetSet.emplace(std::move(targets)); 986 } 987 988 for (const auto &targets : targetSet) { 989 MetadataSection CurrentSection; 990 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 991 targets.begin(), targets.end()); 992 993 for (const auto &it : valueToTargetList) { 994 if (it.second != targets) 995 continue; 996 997 CurrentSection.Values.emplace_back(it.first->getInstallName()); 998 } 999 llvm::sort(CurrentSection.Values); 1000 Section.emplace_back(std::move(CurrentSection)); 1001 } 1002 } 1003 }; 1004 1005 static void mapKeysToValues(FileType FileKind, IO &IO, 1006 const InterfaceFile *&File) { 1007 MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File); 1008 std::vector<UUID> EmptyUUID; 1009 IO.mapRequired("archs", Keys->Architectures); 1010 if (FileKind != FileType::TBD_V1) 1011 IO.mapOptional("uuids", EmptyUUID); 1012 IO.mapRequired("platform", Keys->Platforms); 1013 if (FileKind != FileType::TBD_V1) 1014 IO.mapOptional("flags", Keys->Flags, TBDFlags::None); 1015 IO.mapRequired("install-name", Keys->InstallName); 1016 IO.mapOptional("current-version", Keys->CurrentVersion, 1017 PackedVersion(1, 0, 0)); 1018 IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, 1019 PackedVersion(1, 0, 0)); 1020 if (FileKind != FileType::TBD_V3) 1021 IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0)); 1022 else 1023 IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, 1024 SwiftVersion(0)); 1025 IO.mapOptional("objc-constraint", Keys->ObjCConstraint, 1026 (FileKind == FileType::TBD_V1) 1027 ? ObjCConstraintType::None 1028 : ObjCConstraintType::Retain_Release); 1029 if (FileKind != FileType::TBD_V1) 1030 IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef()); 1031 IO.mapOptional("exports", Keys->Exports); 1032 if (FileKind != FileType::TBD_V1) 1033 IO.mapOptional("undefineds", Keys->Undefineds); 1034 } 1035 1036 static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) { 1037 MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO, 1038 File); 1039 std::vector<UUIDv4> EmptyUUID; 1040 IO.mapTag("!tapi-tbd", true); 1041 IO.mapRequired("tbd-version", Keys->TBDVersion); 1042 IO.mapRequired("targets", Keys->Targets); 1043 IO.mapOptional("uuids", EmptyUUID); 1044 IO.mapOptional("flags", Keys->Flags, TBDFlags::None); 1045 IO.mapRequired("install-name", Keys->InstallName); 1046 IO.mapOptional("current-version", Keys->CurrentVersion, 1047 PackedVersion(1, 0, 0)); 1048 IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, 1049 PackedVersion(1, 0, 0)); 1050 IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0)); 1051 IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas); 1052 auto OptionKind = MetadataSection::Option::Clients; 1053 IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients, 1054 OptionKind); 1055 OptionKind = MetadataSection::Option::Libraries; 1056 IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries, 1057 OptionKind); 1058 IO.mapOptional("exports", Keys->Exports); 1059 IO.mapOptional("reexports", Keys->Reexports); 1060 IO.mapOptional("undefineds", Keys->Undefineds); 1061 } 1062 }; 1063 1064 template <> 1065 struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> { 1066 static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) { 1067 return Seq.size(); 1068 } 1069 static const InterfaceFile *& 1070 element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) { 1071 if (Index >= Seq.size()) 1072 Seq.resize(Index + 1); 1073 return Seq[Index]; 1074 } 1075 }; 1076 1077 } // end namespace yaml. 1078 } // namespace llvm 1079 1080 static void DiagHandler(const SMDiagnostic &Diag, void *Context) { 1081 auto *File = static_cast<TextAPIContext *>(Context); 1082 SmallString<1024> Message; 1083 raw_svector_ostream S(Message); 1084 1085 SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path, 1086 Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(), 1087 Diag.getMessage(), Diag.getLineContents(), 1088 Diag.getRanges(), Diag.getFixIts()); 1089 1090 NewDiag.print(nullptr, S); 1091 File->ErrorMessage = ("malformed file\n" + Message).str(); 1092 } 1093 1094 Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) { 1095 auto TAPIFile = InputBuffer.getBuffer().trim(); 1096 if (TAPIFile.startswith("{") && TAPIFile.endswith("}")) 1097 return FileType::TBD_V5; 1098 1099 if (!TAPIFile.endswith("...")) 1100 return createStringError(std::errc::not_supported, "unsupported file type"); 1101 1102 if (TAPIFile.startswith("--- !tapi-tbd\n")) 1103 return FileType::TBD_V4; 1104 1105 if (TAPIFile.startswith("--- !tapi-tbd-v3\n")) 1106 return FileType::TBD_V3; 1107 1108 if (TAPIFile.startswith("--- !tapi-tbd-v2\n")) 1109 return FileType::TBD_V2; 1110 1111 if (TAPIFile.startswith("--- !tapi-tbd-v1\n") || 1112 TAPIFile.startswith("---\narchs:")) 1113 return FileType::TBD_V1; 1114 1115 return createStringError(std::errc::not_supported, "unsupported file type"); 1116 } 1117 1118 Expected<std::unique_ptr<InterfaceFile>> 1119 TextAPIReader::get(MemoryBufferRef InputBuffer) { 1120 TextAPIContext Ctx; 1121 Ctx.Path = std::string(InputBuffer.getBufferIdentifier()); 1122 if (auto FTOrErr = canRead(InputBuffer)) 1123 Ctx.FileKind = *FTOrErr; 1124 else 1125 return FTOrErr.takeError(); 1126 1127 // Handle JSON Format. 1128 if (Ctx.FileKind >= FileType::TBD_V5) { 1129 auto FileOrErr = getInterfaceFileFromJSON(InputBuffer.getBuffer()); 1130 if (!FileOrErr) 1131 return FileOrErr.takeError(); 1132 1133 (*FileOrErr)->setPath(Ctx.Path); 1134 return std::move(*FileOrErr); 1135 } 1136 yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx); 1137 1138 // Fill vector with interface file objects created by parsing the YAML file. 1139 std::vector<const InterfaceFile *> Files; 1140 YAMLIn >> Files; 1141 1142 // YAMLIn dynamically allocates for Interface file and in case of error, 1143 // memory leak will occur unless wrapped around unique_ptr 1144 auto File = std::unique_ptr<InterfaceFile>( 1145 const_cast<InterfaceFile *>(Files.front())); 1146 1147 for (const InterfaceFile *FI : llvm::drop_begin(Files)) 1148 File->addDocument( 1149 std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI))); 1150 1151 if (YAMLIn.error()) 1152 return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error()); 1153 1154 return std::move(File); 1155 } 1156 1157 Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File, 1158 const FileType FileKind, bool Compact) { 1159 TextAPIContext Ctx; 1160 Ctx.Path = std::string(File.getPath()); 1161 1162 // Prefer parameter for format if passed, otherwise fallback to the File 1163 // FileType. 1164 Ctx.FileKind = 1165 (FileKind == FileType::Invalid) ? File.getFileType() : FileKind; 1166 1167 // Write out in JSON format. 1168 if (Ctx.FileKind >= FileType::TBD_V5) { 1169 return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact); 1170 } 1171 1172 llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80); 1173 1174 std::vector<const InterfaceFile *> Files; 1175 Files.emplace_back(&File); 1176 1177 for (auto Document : File.documents()) 1178 Files.emplace_back(Document.get()); 1179 1180 // Stream out yaml. 1181 YAMLOut << Files; 1182 1183 return Error::success(); 1184 } 1185