|  | //===- TextStub.cpp -------------------------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // Implements the text stub file reader/writer. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "TextAPIContext.h" | 
|  | #include "TextStubCommon.h" | 
|  | #include "llvm/ADT/BitmaskEnum.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  | #include "llvm/Support/Allocator.h" | 
|  | #include "llvm/Support/SourceMgr.h" | 
|  | #include "llvm/Support/YAMLTraits.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include "llvm/TextAPI/Architecture.h" | 
|  | #include "llvm/TextAPI/ArchitectureSet.h" | 
|  | #include "llvm/TextAPI/InterfaceFile.h" | 
|  | #include "llvm/TextAPI/PackedVersion.h" | 
|  | #include "llvm/TextAPI/TextAPIReader.h" | 
|  | #include "llvm/TextAPI/TextAPIWriter.h" | 
|  | #include <algorithm> | 
|  | #include <set> | 
|  |  | 
|  | // clang-format off | 
|  | /* | 
|  |  | 
|  | YAML Format specification. | 
|  |  | 
|  | The TBD v1 format only support two level address libraries and is per | 
|  | definition application extension safe. | 
|  |  | 
|  | ---                              # the tag !tapi-tbd-v1 is optional and | 
|  | # shouldn't be emitted to support older linker. | 
|  | archs: [ armv7, armv7s, arm64 ]  # the list of architecture slices that are | 
|  | # supported by this file. | 
|  | platform: ios                    # Specifies the platform (macosx, ios, etc) | 
|  | install-name: /u/l/libfoo.dylib  # | 
|  | current-version: 1.2.3           # Optional: defaults to 1.0 | 
|  | compatibility-version: 1.0       # Optional: defaults to 1.0 | 
|  | swift-version: 0                 # Optional: defaults to 0 | 
|  | objc-constraint: none            # Optional: defaults to none | 
|  | exports:                         # List of export sections | 
|  | ... | 
|  |  | 
|  | Each export section is defined as following: | 
|  |  | 
|  | - archs: [ arm64 ]                   # the list of architecture slices | 
|  | allowed-clients: [ client ]        # Optional: List of clients | 
|  | re-exports: [ ]                    # Optional: List of re-exports | 
|  | symbols: [ _sym ]                  # Optional: List of symbols | 
|  | objc-classes: []                   # Optional: List of Objective-C classes | 
|  | objc-ivars: []                     # Optional: List of Objective C Instance | 
|  | #           Variables | 
|  | weak-def-symbols: []               # Optional: List of weak defined symbols | 
|  | thread-local-symbols: []           # Optional: List of thread local symbols | 
|  | */ | 
|  |  | 
|  | /* | 
|  |  | 
|  | YAML Format specification. | 
|  |  | 
|  | --- !tapi-tbd-v2 | 
|  | archs: [ armv7, armv7s, arm64 ]  # the list of architecture slices that are | 
|  | # supported by this file. | 
|  | uuids: [ armv7:... ]             # Optional: List of architecture and UUID pairs. | 
|  | platform: ios                    # Specifies the platform (macosx, ios, etc) | 
|  | flags: []                        # Optional: | 
|  | install-name: /u/l/libfoo.dylib  # | 
|  | current-version: 1.2.3           # Optional: defaults to 1.0 | 
|  | compatibility-version: 1.0       # Optional: defaults to 1.0 | 
|  | swift-version: 0                 # Optional: defaults to 0 | 
|  | objc-constraint: retain_release  # Optional: defaults to retain_release | 
|  | parent-umbrella:                 # Optional: | 
|  | exports:                         # List of export sections | 
|  | ... | 
|  | undefineds:                      # List of undefineds sections | 
|  | ... | 
|  |  | 
|  | Each export section is defined as following: | 
|  |  | 
|  | - archs: [ arm64 ]                   # the list of architecture slices | 
|  | allowed-clients: [ client ]        # Optional: List of clients | 
|  | re-exports: [ ]                    # Optional: List of re-exports | 
|  | symbols: [ _sym ]                  # Optional: List of symbols | 
|  | objc-classes: []                   # Optional: List of Objective-C classes | 
|  | objc-ivars: []                     # Optional: List of Objective C Instance | 
|  | #           Variables | 
|  | weak-def-symbols: []               # Optional: List of weak defined symbols | 
|  | thread-local-symbols: []           # Optional: List of thread local symbols | 
|  |  | 
|  | Each undefineds section is defined as following: | 
|  | - archs: [ arm64 ]     # the list of architecture slices | 
|  | symbols: [ _sym ]    # Optional: List of symbols | 
|  | objc-classes: []     # Optional: List of Objective-C classes | 
|  | objc-ivars: []       # Optional: List of Objective C Instance Variables | 
|  | weak-ref-symbols: [] # Optional: List of weak defined symbols | 
|  | */ | 
|  |  | 
|  | /* | 
|  |  | 
|  | YAML Format specification. | 
|  |  | 
|  | --- !tapi-tbd-v3 | 
|  | archs: [ armv7, armv7s, arm64 ]  # the list of architecture slices that are | 
|  | # supported by this file. | 
|  | uuids: [ armv7:... ]             # Optional: List of architecture and UUID pairs. | 
|  | platform: ios                    # Specifies the platform (macosx, ios, etc) | 
|  | flags: []                        # Optional: | 
|  | install-name: /u/l/libfoo.dylib  # | 
|  | current-version: 1.2.3           # Optional: defaults to 1.0 | 
|  | compatibility-version: 1.0       # Optional: defaults to 1.0 | 
|  | swift-abi-version: 0             # Optional: defaults to 0 | 
|  | objc-constraint: retain_release  # Optional: defaults to retain_release | 
|  | parent-umbrella:                 # Optional: | 
|  | exports:                         # List of export sections | 
|  | ... | 
|  | undefineds:                      # List of undefineds sections | 
|  | ... | 
|  |  | 
|  | Each export section is defined as following: | 
|  |  | 
|  | - archs: [ arm64 ]                   # the list of architecture slices | 
|  | allowed-clients: [ client ]        # Optional: List of clients | 
|  | re-exports: [ ]                    # Optional: List of re-exports | 
|  | symbols: [ _sym ]                  # Optional: List of symbols | 
|  | objc-classes: []                   # Optional: List of Objective-C classes | 
|  | objc-eh-types: []                  # Optional: List of Objective-C classes | 
|  | #           with EH | 
|  | objc-ivars: []                     # Optional: List of Objective C Instance | 
|  | #           Variables | 
|  | weak-def-symbols: []               # Optional: List of weak defined symbols | 
|  | thread-local-symbols: []           # Optional: List of thread local symbols | 
|  |  | 
|  | Each undefineds section is defined as following: | 
|  | - archs: [ arm64 ]     # the list of architecture slices | 
|  | symbols: [ _sym ]    # Optional: List of symbols | 
|  | objc-classes: []     # Optional: List of Objective-C classes | 
|  | objc-eh-types: []                  # Optional: List of Objective-C classes | 
|  | #           with EH | 
|  | objc-ivars: []       # Optional: List of Objective C Instance Variables | 
|  | weak-ref-symbols: [] # Optional: List of weak defined symbols | 
|  | */ | 
|  |  | 
|  | /* | 
|  |  | 
|  | YAML Format specification. | 
|  |  | 
|  | --- !tapi-tbd | 
|  | tbd-version: 4                              # The tbd version for format | 
|  | targets: [ armv7-ios, x86_64-maccatalyst ]  # The list of applicable tapi supported target triples | 
|  | uuids:                                      # Optional: List of target and UUID pairs. | 
|  | - target: armv7-ios | 
|  | value: ... | 
|  | - target: x86_64-maccatalyst | 
|  | value: ... | 
|  | flags: []                        # Optional: | 
|  | install-name: /u/l/libfoo.dylib  # | 
|  | current-version: 1.2.3           # Optional: defaults to 1.0 | 
|  | compatibility-version: 1.0       # Optional: defaults to 1.0 | 
|  | swift-abi-version: 0             # Optional: defaults to 0 | 
|  | parent-umbrella:                 # Optional: | 
|  | allowable-clients: | 
|  | - targets: [ armv7-ios ]       # Optional: | 
|  | clients: [ clientA ] | 
|  | exports:                         # List of export sections | 
|  | ... | 
|  | re-exports:                      # List of reexport sections | 
|  | ... | 
|  | undefineds:                      # List of undefineds sections | 
|  | ... | 
|  |  | 
|  | Each export and reexport  section is defined as following: | 
|  |  | 
|  | - targets: [ arm64-macos ]                        # The list of target triples associated with symbols | 
|  | symbols: [ _symA ]                              # Optional: List of symbols | 
|  | objc-classes: []                                # Optional: List of Objective-C classes | 
|  | objc-eh-types: []                               # Optional: List of Objective-C classes | 
|  | #           with EH | 
|  | objc-ivars: []                                  # Optional: List of Objective C Instance | 
|  | #           Variables | 
|  | weak-symbols: []                                # Optional: List of weak defined symbols | 
|  | thread-local-symbols: []                        # Optional: List of thread local symbols | 
|  | - targets: [ arm64-macos, x86_64-maccatalyst ]    # Optional: Targets for applicable additional symbols | 
|  | symbols: [ _symB ]                              # Optional: List of symbols | 
|  |  | 
|  | Each undefineds section is defined as following: | 
|  | - targets: [ arm64-macos ]    # The list of target triples associated with symbols | 
|  | symbols: [ _symC ]          # Optional: List of symbols | 
|  | objc-classes: []            # Optional: List of Objective-C classes | 
|  | objc-eh-types: []           # Optional: List of Objective-C classes | 
|  | #           with EH | 
|  | objc-ivars: []              # Optional: List of Objective C Instance Variables | 
|  | weak-symbols: []            # Optional: List of weak defined symbols | 
|  | */ | 
|  | // clang-format on | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::yaml; | 
|  | using namespace llvm::MachO; | 
|  |  | 
|  | namespace { | 
|  | struct ExportSection { | 
|  | std::vector<Architecture> Architectures; | 
|  | std::vector<FlowStringRef> AllowableClients; | 
|  | std::vector<FlowStringRef> ReexportedLibraries; | 
|  | std::vector<FlowStringRef> Symbols; | 
|  | std::vector<FlowStringRef> Classes; | 
|  | std::vector<FlowStringRef> ClassEHs; | 
|  | std::vector<FlowStringRef> IVars; | 
|  | std::vector<FlowStringRef> WeakDefSymbols; | 
|  | std::vector<FlowStringRef> TLVSymbols; | 
|  | }; | 
|  |  | 
|  | struct UndefinedSection { | 
|  | std::vector<Architecture> Architectures; | 
|  | std::vector<FlowStringRef> Symbols; | 
|  | std::vector<FlowStringRef> Classes; | 
|  | std::vector<FlowStringRef> ClassEHs; | 
|  | std::vector<FlowStringRef> IVars; | 
|  | std::vector<FlowStringRef> WeakRefSymbols; | 
|  | }; | 
|  |  | 
|  | // Sections for direct target mapping in TBDv4 | 
|  | struct SymbolSection { | 
|  | TargetList Targets; | 
|  | std::vector<FlowStringRef> Symbols; | 
|  | std::vector<FlowStringRef> Classes; | 
|  | std::vector<FlowStringRef> ClassEHs; | 
|  | std::vector<FlowStringRef> Ivars; | 
|  | std::vector<FlowStringRef> WeakSymbols; | 
|  | std::vector<FlowStringRef> TlvSymbols; | 
|  | }; | 
|  |  | 
|  | struct MetadataSection { | 
|  | enum Option { Clients, Libraries }; | 
|  | std::vector<Target> Targets; | 
|  | std::vector<FlowStringRef> Values; | 
|  | }; | 
|  |  | 
|  | struct UmbrellaSection { | 
|  | std::vector<Target> Targets; | 
|  | std::string Umbrella; | 
|  | }; | 
|  |  | 
|  | // UUID's for TBDv4 are mapped to target not arch | 
|  | struct UUIDv4 { | 
|  | Target TargetID; | 
|  | std::string Value; | 
|  |  | 
|  | UUIDv4() = default; | 
|  | UUIDv4(const Target &TargetID, const std::string &Value) | 
|  | : TargetID(TargetID), Value(Value) {} | 
|  | }; | 
|  | } // end anonymous namespace. | 
|  |  | 
|  | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture) | 
|  | LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection) | 
|  | LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection) | 
|  | // Specific to TBDv4 | 
|  | LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection) | 
|  | LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection) | 
|  | LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection) | 
|  | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target) | 
|  | LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4) | 
|  |  | 
|  | namespace llvm { | 
|  | namespace yaml { | 
|  |  | 
|  | template <> struct MappingTraits<ExportSection> { | 
|  | static void mapping(IO &IO, ExportSection &Section) { | 
|  | const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); | 
|  | assert((!Ctx || Ctx->FileKind != FileType::Invalid) && | 
|  | "File type is not set in YAML context"); | 
|  |  | 
|  | IO.mapRequired("archs", Section.Architectures); | 
|  | if (Ctx->FileKind == FileType::TBD_V1) | 
|  | IO.mapOptional("allowed-clients", Section.AllowableClients); | 
|  | else | 
|  | IO.mapOptional("allowable-clients", Section.AllowableClients); | 
|  | IO.mapOptional("re-exports", Section.ReexportedLibraries); | 
|  | IO.mapOptional("symbols", Section.Symbols); | 
|  | IO.mapOptional("objc-classes", Section.Classes); | 
|  | if (Ctx->FileKind == FileType::TBD_V3) | 
|  | IO.mapOptional("objc-eh-types", Section.ClassEHs); | 
|  | IO.mapOptional("objc-ivars", Section.IVars); | 
|  | IO.mapOptional("weak-def-symbols", Section.WeakDefSymbols); | 
|  | IO.mapOptional("thread-local-symbols", Section.TLVSymbols); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <> struct MappingTraits<UndefinedSection> { | 
|  | static void mapping(IO &IO, UndefinedSection &Section) { | 
|  | const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); | 
|  | assert((!Ctx || Ctx->FileKind != FileType::Invalid) && | 
|  | "File type is not set in YAML context"); | 
|  |  | 
|  | IO.mapRequired("archs", Section.Architectures); | 
|  | IO.mapOptional("symbols", Section.Symbols); | 
|  | IO.mapOptional("objc-classes", Section.Classes); | 
|  | if (Ctx->FileKind == FileType::TBD_V3) | 
|  | IO.mapOptional("objc-eh-types", Section.ClassEHs); | 
|  | IO.mapOptional("objc-ivars", Section.IVars); | 
|  | IO.mapOptional("weak-ref-symbols", Section.WeakRefSymbols); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <> struct MappingTraits<SymbolSection> { | 
|  | static void mapping(IO &IO, SymbolSection &Section) { | 
|  | IO.mapRequired("targets", Section.Targets); | 
|  | IO.mapOptional("symbols", Section.Symbols); | 
|  | IO.mapOptional("objc-classes", Section.Classes); | 
|  | IO.mapOptional("objc-eh-types", Section.ClassEHs); | 
|  | IO.mapOptional("objc-ivars", Section.Ivars); | 
|  | IO.mapOptional("weak-symbols", Section.WeakSymbols); | 
|  | IO.mapOptional("thread-local-symbols", Section.TlvSymbols); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <> struct MappingTraits<UmbrellaSection> { | 
|  | static void mapping(IO &IO, UmbrellaSection &Section) { | 
|  | IO.mapRequired("targets", Section.Targets); | 
|  | IO.mapRequired("umbrella", Section.Umbrella); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <> struct MappingTraits<UUIDv4> { | 
|  | static void mapping(IO &IO, UUIDv4 &UUID) { | 
|  | IO.mapRequired("target", UUID.TargetID); | 
|  | IO.mapRequired("value", UUID.Value); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <> | 
|  | struct MappingContextTraits<MetadataSection, MetadataSection::Option> { | 
|  | static void mapping(IO &IO, MetadataSection &Section, | 
|  | MetadataSection::Option &OptionKind) { | 
|  | IO.mapRequired("targets", Section.Targets); | 
|  | switch (OptionKind) { | 
|  | case MetadataSection::Option::Clients: | 
|  | IO.mapRequired("clients", Section.Values); | 
|  | return; | 
|  | case MetadataSection::Option::Libraries: | 
|  | IO.mapRequired("libraries", Section.Values); | 
|  | return; | 
|  | } | 
|  | llvm_unreachable("unexpected option for metadata"); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <> struct ScalarBitSetTraits<TBDFlags> { | 
|  | static void bitset(IO &IO, TBDFlags &Flags) { | 
|  | IO.bitSetCase(Flags, "flat_namespace", TBDFlags::FlatNamespace); | 
|  | IO.bitSetCase(Flags, "not_app_extension_safe", | 
|  | TBDFlags::NotApplicationExtensionSafe); | 
|  | IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI); | 
|  | IO.bitSetCase(Flags, "not_for_dyld_shared_cache", | 
|  | TBDFlags::OSLibNotForSharedCache); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <> struct ScalarTraits<Target> { | 
|  | static void output(const Target &Value, void *, raw_ostream &OS) { | 
|  | OS << Value.Arch << "-"; | 
|  | switch (Value.Platform) { | 
|  | #define PLATFORM(platform, id, name, build_name, target, tapi_target,          \ | 
|  | marketing)                                                    \ | 
|  | case PLATFORM_##platform:                                                    \ | 
|  | OS << #tapi_target;                                                        \ | 
|  | break; | 
|  | #include "llvm/BinaryFormat/MachO.def" | 
|  | } | 
|  | } | 
|  |  | 
|  | static StringRef input(StringRef Scalar, void *, Target &Value) { | 
|  | auto Result = Target::create(Scalar); | 
|  | if (!Result) { | 
|  | consumeError(Result.takeError()); | 
|  | return "unparsable target"; | 
|  | } | 
|  |  | 
|  | Value = *Result; | 
|  | if (Value.Arch == AK_unknown) | 
|  | return "unknown architecture"; | 
|  | if (Value.Platform == PLATFORM_UNKNOWN) | 
|  | return "unknown platform"; | 
|  |  | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | static QuotingType mustQuote(StringRef) { return QuotingType::None; } | 
|  | }; | 
|  |  | 
|  | template <> struct MappingTraits<const InterfaceFile *> { | 
|  | struct NormalizedTBD { | 
|  | explicit NormalizedTBD(IO &IO) {} | 
|  | NormalizedTBD(IO &IO, const InterfaceFile *&File) { | 
|  | Architectures = File->getArchitectures(); | 
|  | Platforms = File->getPlatforms(); | 
|  | InstallName = File->getInstallName(); | 
|  | CurrentVersion = PackedVersion(File->getCurrentVersion()); | 
|  | CompatibilityVersion = PackedVersion(File->getCompatibilityVersion()); | 
|  | SwiftABIVersion = File->getSwiftABIVersion(); | 
|  | ObjCConstraint = File->getObjCConstraint(); | 
|  |  | 
|  | Flags = TBDFlags::None; | 
|  | if (!File->isApplicationExtensionSafe()) | 
|  | Flags |= TBDFlags::NotApplicationExtensionSafe; | 
|  |  | 
|  | if (!File->isTwoLevelNamespace()) | 
|  | Flags |= TBDFlags::FlatNamespace; | 
|  |  | 
|  | if (!File->umbrellas().empty()) | 
|  | ParentUmbrella = File->umbrellas().begin()->second; | 
|  |  | 
|  | std::set<ArchitectureSet> ArchSet; | 
|  | for (const auto &Library : File->allowableClients()) | 
|  | ArchSet.insert(Library.getArchitectures()); | 
|  |  | 
|  | for (const auto &Library : File->reexportedLibraries()) | 
|  | ArchSet.insert(Library.getArchitectures()); | 
|  |  | 
|  | std::map<const Symbol *, ArchitectureSet> SymbolToArchSet; | 
|  | for (const auto *Symbol : File->symbols()) { | 
|  | auto Architectures = Symbol->getArchitectures(); | 
|  | SymbolToArchSet[Symbol] = Architectures; | 
|  | ArchSet.insert(Architectures); | 
|  | } | 
|  |  | 
|  | for (auto Architectures : ArchSet) { | 
|  | ExportSection Section; | 
|  | Section.Architectures = Architectures; | 
|  |  | 
|  | for (const auto &Library : File->allowableClients()) | 
|  | if (Library.getArchitectures() == Architectures) | 
|  | Section.AllowableClients.emplace_back(Library.getInstallName()); | 
|  |  | 
|  | for (const auto &Library : File->reexportedLibraries()) | 
|  | if (Library.getArchitectures() == Architectures) | 
|  | Section.ReexportedLibraries.emplace_back(Library.getInstallName()); | 
|  |  | 
|  | for (const auto &SymArch : SymbolToArchSet) { | 
|  | if (SymArch.second != Architectures) | 
|  | continue; | 
|  |  | 
|  | const auto *Symbol = SymArch.first; | 
|  | switch (Symbol->getKind()) { | 
|  | case EncodeKind::GlobalSymbol: | 
|  | if (Symbol->isWeakDefined()) | 
|  | Section.WeakDefSymbols.emplace_back(Symbol->getName()); | 
|  | else if (Symbol->isThreadLocalValue()) | 
|  | Section.TLVSymbols.emplace_back(Symbol->getName()); | 
|  | else | 
|  | Section.Symbols.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | case EncodeKind::ObjectiveCClass: | 
|  | if (File->getFileType() != FileType::TBD_V3) | 
|  | Section.Classes.emplace_back( | 
|  | copyString("_" + Symbol->getName().str())); | 
|  | else | 
|  | Section.Classes.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | case EncodeKind::ObjectiveCClassEHType: | 
|  | if (File->getFileType() != FileType::TBD_V3) | 
|  | Section.Symbols.emplace_back( | 
|  | copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); | 
|  | else | 
|  | Section.ClassEHs.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | case EncodeKind::ObjectiveCInstanceVariable: | 
|  | if (File->getFileType() != FileType::TBD_V3) | 
|  | Section.IVars.emplace_back( | 
|  | copyString("_" + Symbol->getName().str())); | 
|  | else | 
|  | Section.IVars.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | } | 
|  | } | 
|  | llvm::sort(Section.Symbols); | 
|  | llvm::sort(Section.Classes); | 
|  | llvm::sort(Section.ClassEHs); | 
|  | llvm::sort(Section.IVars); | 
|  | llvm::sort(Section.WeakDefSymbols); | 
|  | llvm::sort(Section.TLVSymbols); | 
|  | Exports.emplace_back(std::move(Section)); | 
|  | } | 
|  |  | 
|  | ArchSet.clear(); | 
|  | SymbolToArchSet.clear(); | 
|  |  | 
|  | for (const auto *Symbol : File->undefineds()) { | 
|  | auto Architectures = Symbol->getArchitectures(); | 
|  | SymbolToArchSet[Symbol] = Architectures; | 
|  | ArchSet.insert(Architectures); | 
|  | } | 
|  |  | 
|  | for (auto Architectures : ArchSet) { | 
|  | UndefinedSection Section; | 
|  | Section.Architectures = Architectures; | 
|  |  | 
|  | for (const auto &SymArch : SymbolToArchSet) { | 
|  | if (SymArch.second != Architectures) | 
|  | continue; | 
|  |  | 
|  | const auto *Symbol = SymArch.first; | 
|  | switch (Symbol->getKind()) { | 
|  | case EncodeKind::GlobalSymbol: | 
|  | if (Symbol->isWeakReferenced()) | 
|  | Section.WeakRefSymbols.emplace_back(Symbol->getName()); | 
|  | else | 
|  | Section.Symbols.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | case EncodeKind::ObjectiveCClass: | 
|  | if (File->getFileType() != FileType::TBD_V3) | 
|  | Section.Classes.emplace_back( | 
|  | copyString("_" + Symbol->getName().str())); | 
|  | else | 
|  | Section.Classes.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | case EncodeKind::ObjectiveCClassEHType: | 
|  | if (File->getFileType() != FileType::TBD_V3) | 
|  | Section.Symbols.emplace_back( | 
|  | copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); | 
|  | else | 
|  | Section.ClassEHs.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | case EncodeKind::ObjectiveCInstanceVariable: | 
|  | if (File->getFileType() != FileType::TBD_V3) | 
|  | Section.IVars.emplace_back( | 
|  | copyString("_" + Symbol->getName().str())); | 
|  | else | 
|  | Section.IVars.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | } | 
|  | } | 
|  | llvm::sort(Section.Symbols); | 
|  | llvm::sort(Section.Classes); | 
|  | llvm::sort(Section.ClassEHs); | 
|  | llvm::sort(Section.IVars); | 
|  | llvm::sort(Section.WeakRefSymbols); | 
|  | Undefineds.emplace_back(std::move(Section)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // TBD v1 - TBD v3 files only support one platform and several | 
|  | // architectures. It is possible to have more than one platform for TBD v3 | 
|  | // files, but the architectures don't apply to all | 
|  | // platforms, specifically to filter out the i386 slice from | 
|  | // platform macCatalyst. | 
|  | TargetList synthesizeTargets(ArchitectureSet Architectures, | 
|  | const PlatformSet &Platforms) { | 
|  | TargetList Targets; | 
|  |  | 
|  | for (auto Platform : Platforms) { | 
|  | Platform = mapToPlatformType(Platform, Architectures.hasX86()); | 
|  |  | 
|  | for (const auto &&Architecture : Architectures) { | 
|  | if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST)) | 
|  | continue; | 
|  |  | 
|  | Targets.emplace_back(Architecture, Platform); | 
|  | } | 
|  | } | 
|  | return Targets; | 
|  | } | 
|  |  | 
|  | const InterfaceFile *denormalize(IO &IO) { | 
|  | auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); | 
|  | assert(Ctx); | 
|  |  | 
|  | auto *File = new InterfaceFile; | 
|  | File->setPath(Ctx->Path); | 
|  | File->setFileType(Ctx->FileKind); | 
|  | File->addTargets(synthesizeTargets(Architectures, Platforms)); | 
|  | File->setInstallName(InstallName); | 
|  | File->setCurrentVersion(CurrentVersion); | 
|  | File->setCompatibilityVersion(CompatibilityVersion); | 
|  | File->setSwiftABIVersion(SwiftABIVersion); | 
|  | File->setObjCConstraint(ObjCConstraint); | 
|  | for (const auto &Target : File->targets()) | 
|  | File->addParentUmbrella(Target, ParentUmbrella); | 
|  |  | 
|  | if (Ctx->FileKind == FileType::TBD_V1) { | 
|  | File->setTwoLevelNamespace(); | 
|  | File->setApplicationExtensionSafe(); | 
|  | } else { | 
|  | File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); | 
|  | File->setApplicationExtensionSafe( | 
|  | !(Flags & TBDFlags::NotApplicationExtensionSafe)); | 
|  | } | 
|  |  | 
|  | // For older file formats, the segment where the symbol | 
|  | // comes from is unknown, treat all symbols as Data | 
|  | // in these cases. | 
|  | const auto Flags = SymbolFlags::Data; | 
|  |  | 
|  | for (const auto &Section : Exports) { | 
|  | const auto Targets = | 
|  | synthesizeTargets(Section.Architectures, Platforms); | 
|  |  | 
|  | for (const auto &Lib : Section.AllowableClients) | 
|  | for (const auto &Target : Targets) | 
|  | File->addAllowableClient(Lib, Target); | 
|  |  | 
|  | for (const auto &Lib : Section.ReexportedLibraries) | 
|  | for (const auto &Target : Targets) | 
|  | File->addReexportedLibrary(Lib, Target); | 
|  |  | 
|  | for (const auto &Symbol : Section.Symbols) { | 
|  | if (Ctx->FileKind != FileType::TBD_V3 && | 
|  | Symbol.value.starts_with(ObjC2EHTypePrefix)) | 
|  | File->addSymbol(EncodeKind::ObjectiveCClassEHType, | 
|  | Symbol.value.drop_front(15), Targets, Flags); | 
|  | else | 
|  | File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, Flags); | 
|  | } | 
|  | for (auto &Symbol : Section.Classes) { | 
|  | auto Name = Symbol.value; | 
|  | if (Ctx->FileKind != FileType::TBD_V3) | 
|  | Name = Name.drop_front(); | 
|  | File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets, Flags); | 
|  | } | 
|  | for (auto &Symbol : Section.ClassEHs) | 
|  | File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets, | 
|  | Flags); | 
|  | for (auto &Symbol : Section.IVars) { | 
|  | auto Name = Symbol.value; | 
|  | if (Ctx->FileKind != FileType::TBD_V3) | 
|  | Name = Name.drop_front(); | 
|  | File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets, | 
|  | Flags); | 
|  | } | 
|  | for (auto &Symbol : Section.WeakDefSymbols) | 
|  | File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, | 
|  | SymbolFlags::WeakDefined | Flags); | 
|  | for (auto &Symbol : Section.TLVSymbols) | 
|  | File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, | 
|  | SymbolFlags::ThreadLocalValue | Flags); | 
|  | } | 
|  |  | 
|  | for (const auto &Section : Undefineds) { | 
|  | const auto Targets = | 
|  | synthesizeTargets(Section.Architectures, Platforms); | 
|  | for (auto &Symbol : Section.Symbols) { | 
|  | if (Ctx->FileKind != FileType::TBD_V3 && | 
|  | Symbol.value.starts_with(ObjC2EHTypePrefix)) | 
|  | File->addSymbol(EncodeKind::ObjectiveCClassEHType, | 
|  | Symbol.value.drop_front(15), Targets, | 
|  | SymbolFlags::Undefined | Flags); | 
|  | else | 
|  | File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, | 
|  | SymbolFlags::Undefined | Flags); | 
|  | } | 
|  | for (auto &Symbol : Section.Classes) { | 
|  | auto Name = Symbol.value; | 
|  | if (Ctx->FileKind != FileType::TBD_V3) | 
|  | Name = Name.drop_front(); | 
|  | File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets, | 
|  | SymbolFlags::Undefined | Flags); | 
|  | } | 
|  | for (auto &Symbol : Section.ClassEHs) | 
|  | File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets, | 
|  | SymbolFlags::Undefined | Flags); | 
|  | for (auto &Symbol : Section.IVars) { | 
|  | auto Name = Symbol.value; | 
|  | if (Ctx->FileKind != FileType::TBD_V3) | 
|  | Name = Name.drop_front(); | 
|  | File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets, | 
|  | SymbolFlags::Undefined | Flags); | 
|  | } | 
|  | for (auto &Symbol : Section.WeakRefSymbols) | 
|  | File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, | 
|  | SymbolFlags::Undefined | SymbolFlags::WeakReferenced | | 
|  | Flags); | 
|  | } | 
|  |  | 
|  | return File; | 
|  | } | 
|  |  | 
|  | llvm::BumpPtrAllocator Allocator; | 
|  | StringRef copyString(StringRef String) { | 
|  | if (String.empty()) | 
|  | return {}; | 
|  |  | 
|  | void *Ptr = Allocator.Allocate(String.size(), 1); | 
|  | memcpy(Ptr, String.data(), String.size()); | 
|  | return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); | 
|  | } | 
|  |  | 
|  | std::vector<Architecture> Architectures; | 
|  | std::vector<UUID> UUIDs; | 
|  | PlatformSet Platforms; | 
|  | StringRef InstallName; | 
|  | PackedVersion CurrentVersion; | 
|  | PackedVersion CompatibilityVersion; | 
|  | SwiftVersion SwiftABIVersion{0}; | 
|  | ObjCConstraintType ObjCConstraint{ObjCConstraintType::None}; | 
|  | TBDFlags Flags{TBDFlags::None}; | 
|  | StringRef ParentUmbrella; | 
|  | std::vector<ExportSection> Exports; | 
|  | std::vector<UndefinedSection> Undefineds; | 
|  | }; | 
|  |  | 
|  | static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) { | 
|  | if (IO.mapTag("!tapi-tbd", false)) | 
|  | Ctx->FileKind = FileType::TBD_V4; | 
|  | else if (IO.mapTag("!tapi-tbd-v3", false)) | 
|  | Ctx->FileKind = FileType::TBD_V3; | 
|  | else if (IO.mapTag("!tapi-tbd-v2", false)) | 
|  | Ctx->FileKind = FileType::TBD_V2; | 
|  | else if (IO.mapTag("!tapi-tbd-v1", false) || | 
|  | IO.mapTag("tag:yaml.org,2002:map", false)) | 
|  | Ctx->FileKind = FileType::TBD_V1; | 
|  | else { | 
|  | Ctx->FileKind = FileType::Invalid; | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void mapping(IO &IO, const InterfaceFile *&File) { | 
|  | auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); | 
|  | assert((!Ctx || !IO.outputting() || | 
|  | (Ctx && Ctx->FileKind != FileType::Invalid)) && | 
|  | "File type is not set in YAML context"); | 
|  |  | 
|  | if (!IO.outputting()) { | 
|  | setFileTypeForInput(Ctx, IO); | 
|  | switch (Ctx->FileKind) { | 
|  | default: | 
|  | break; | 
|  | case FileType::TBD_V4: | 
|  | mapKeysToValuesV4(IO, File); | 
|  | return; | 
|  | case FileType::Invalid: | 
|  | IO.setError("unsupported file type"); | 
|  | return; | 
|  | } | 
|  | } else { | 
|  | // Set file type when writing. | 
|  | switch (Ctx->FileKind) { | 
|  | default: | 
|  | llvm_unreachable("unexpected file type"); | 
|  | case FileType::TBD_V4: | 
|  | mapKeysToValuesV4(IO, File); | 
|  | return; | 
|  | case FileType::TBD_V3: | 
|  | IO.mapTag("!tapi-tbd-v3", true); | 
|  | break; | 
|  | case FileType::TBD_V2: | 
|  | IO.mapTag("!tapi-tbd-v2", true); | 
|  | break; | 
|  | case FileType::TBD_V1: | 
|  | // Don't write the tag into the .tbd file for TBD v1 | 
|  | break; | 
|  | } | 
|  | } | 
|  | mapKeysToValues(Ctx->FileKind, IO, File); | 
|  | } | 
|  |  | 
|  | using SectionList = std::vector<SymbolSection>; | 
|  | struct NormalizedTBD_V4 { | 
|  | explicit NormalizedTBD_V4(IO &IO) {} | 
|  | NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) { | 
|  | auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); | 
|  | assert(Ctx); | 
|  | TBDVersion = Ctx->FileKind >> 4; | 
|  | Targets.insert(Targets.begin(), File->targets().begin(), | 
|  | File->targets().end()); | 
|  | InstallName = File->getInstallName(); | 
|  | CurrentVersion = File->getCurrentVersion(); | 
|  | CompatibilityVersion = File->getCompatibilityVersion(); | 
|  | SwiftABIVersion = File->getSwiftABIVersion(); | 
|  |  | 
|  | Flags = TBDFlags::None; | 
|  | if (!File->isApplicationExtensionSafe()) | 
|  | Flags |= TBDFlags::NotApplicationExtensionSafe; | 
|  |  | 
|  | if (!File->isTwoLevelNamespace()) | 
|  | Flags |= TBDFlags::FlatNamespace; | 
|  |  | 
|  | if (File->isOSLibNotForSharedCache()) | 
|  | Flags |= TBDFlags::OSLibNotForSharedCache; | 
|  |  | 
|  | { | 
|  | std::map<std::string, TargetList> valueToTargetList; | 
|  | for (const auto &it : File->umbrellas()) | 
|  | valueToTargetList[it.second].emplace_back(it.first); | 
|  |  | 
|  | for (const auto &it : valueToTargetList) { | 
|  | UmbrellaSection CurrentSection; | 
|  | CurrentSection.Targets.insert(CurrentSection.Targets.begin(), | 
|  | it.second.begin(), it.second.end()); | 
|  | CurrentSection.Umbrella = it.first; | 
|  | ParentUmbrellas.emplace_back(std::move(CurrentSection)); | 
|  | } | 
|  | } | 
|  |  | 
|  | assignTargetsToLibrary(File->allowableClients(), AllowableClients); | 
|  | assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries); | 
|  |  | 
|  | auto handleSymbols = | 
|  | [](SectionList &CurrentSections, | 
|  | InterfaceFile::const_filtered_symbol_range Symbols) { | 
|  | std::set<TargetList> TargetSet; | 
|  | std::map<const Symbol *, TargetList> SymbolToTargetList; | 
|  | for (const auto *Symbol : Symbols) { | 
|  | TargetList Targets(Symbol->targets()); | 
|  | SymbolToTargetList[Symbol] = Targets; | 
|  | TargetSet.emplace(std::move(Targets)); | 
|  | } | 
|  | for (const auto &TargetIDs : TargetSet) { | 
|  | SymbolSection CurrentSection; | 
|  | CurrentSection.Targets.insert(CurrentSection.Targets.begin(), | 
|  | TargetIDs.begin(), TargetIDs.end()); | 
|  |  | 
|  | for (const auto &IT : SymbolToTargetList) { | 
|  | if (IT.second != TargetIDs) | 
|  | continue; | 
|  |  | 
|  | const auto *Symbol = IT.first; | 
|  | switch (Symbol->getKind()) { | 
|  | case EncodeKind::GlobalSymbol: | 
|  | if (Symbol->isWeakDefined()) | 
|  | CurrentSection.WeakSymbols.emplace_back(Symbol->getName()); | 
|  | else if (Symbol->isThreadLocalValue()) | 
|  | CurrentSection.TlvSymbols.emplace_back(Symbol->getName()); | 
|  | else | 
|  | CurrentSection.Symbols.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | case EncodeKind::ObjectiveCClass: | 
|  | CurrentSection.Classes.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | case EncodeKind::ObjectiveCClassEHType: | 
|  | CurrentSection.ClassEHs.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | case EncodeKind::ObjectiveCInstanceVariable: | 
|  | CurrentSection.Ivars.emplace_back(Symbol->getName()); | 
|  | break; | 
|  | } | 
|  | } | 
|  | sort(CurrentSection.Symbols); | 
|  | sort(CurrentSection.Classes); | 
|  | sort(CurrentSection.ClassEHs); | 
|  | sort(CurrentSection.Ivars); | 
|  | sort(CurrentSection.WeakSymbols); | 
|  | sort(CurrentSection.TlvSymbols); | 
|  | CurrentSections.emplace_back(std::move(CurrentSection)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | handleSymbols(Exports, File->exports()); | 
|  | handleSymbols(Reexports, File->reexports()); | 
|  | handleSymbols(Undefineds, File->undefineds()); | 
|  | } | 
|  |  | 
|  | const InterfaceFile *denormalize(IO &IO) { | 
|  | auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); | 
|  | assert(Ctx); | 
|  |  | 
|  | auto *File = new InterfaceFile; | 
|  | File->setPath(Ctx->Path); | 
|  | File->setFileType(Ctx->FileKind); | 
|  | File->addTargets(Targets); | 
|  | File->setInstallName(InstallName); | 
|  | File->setCurrentVersion(CurrentVersion); | 
|  | File->setCompatibilityVersion(CompatibilityVersion); | 
|  | File->setSwiftABIVersion(SwiftABIVersion); | 
|  | for (const auto &CurrentSection : ParentUmbrellas) | 
|  | for (const auto &target : CurrentSection.Targets) | 
|  | File->addParentUmbrella(target, CurrentSection.Umbrella); | 
|  | File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); | 
|  | File->setApplicationExtensionSafe( | 
|  | !(Flags & TBDFlags::NotApplicationExtensionSafe)); | 
|  | File->setOSLibNotForSharedCache( | 
|  | (Flags & TBDFlags::OSLibNotForSharedCache)); | 
|  |  | 
|  | for (const auto &CurrentSection : AllowableClients) { | 
|  | for (const auto &lib : CurrentSection.Values) | 
|  | for (const auto &Target : CurrentSection.Targets) | 
|  | File->addAllowableClient(lib, Target); | 
|  | } | 
|  |  | 
|  | for (const auto &CurrentSection : ReexportedLibraries) { | 
|  | for (const auto &Lib : CurrentSection.Values) | 
|  | for (const auto &Target : CurrentSection.Targets) | 
|  | File->addReexportedLibrary(Lib, Target); | 
|  | } | 
|  |  | 
|  | auto handleSymbols = [File](const SectionList &CurrentSections, | 
|  | SymbolFlags InputFlag = SymbolFlags::None) { | 
|  | // For older file formats, the segment where the symbol | 
|  | // comes from is unknown, treat all symbols as Data | 
|  | // in these cases. | 
|  | const SymbolFlags Flag = InputFlag | SymbolFlags::Data; | 
|  |  | 
|  | for (const auto &CurrentSection : CurrentSections) { | 
|  | for (auto &sym : CurrentSection.Symbols) | 
|  | File->addSymbol(EncodeKind::GlobalSymbol, sym, | 
|  | CurrentSection.Targets, Flag); | 
|  |  | 
|  | for (auto &sym : CurrentSection.Classes) | 
|  | File->addSymbol(EncodeKind::ObjectiveCClass, sym, | 
|  | CurrentSection.Targets, Flag); | 
|  |  | 
|  | for (auto &sym : CurrentSection.ClassEHs) | 
|  | File->addSymbol(EncodeKind::ObjectiveCClassEHType, sym, | 
|  | CurrentSection.Targets, Flag); | 
|  |  | 
|  | for (auto &sym : CurrentSection.Ivars) | 
|  | File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, sym, | 
|  | CurrentSection.Targets, Flag); | 
|  |  | 
|  | SymbolFlags SymFlag = | 
|  | ((Flag & SymbolFlags::Undefined) == SymbolFlags::Undefined) | 
|  | ? SymbolFlags::WeakReferenced | 
|  | : SymbolFlags::WeakDefined; | 
|  | for (auto &sym : CurrentSection.WeakSymbols) { | 
|  | File->addSymbol(EncodeKind::GlobalSymbol, sym, | 
|  | CurrentSection.Targets, Flag | SymFlag); | 
|  | } | 
|  |  | 
|  | for (auto &sym : CurrentSection.TlvSymbols) | 
|  | File->addSymbol(EncodeKind::GlobalSymbol, sym, | 
|  | CurrentSection.Targets, | 
|  | Flag | SymbolFlags::ThreadLocalValue); | 
|  | } | 
|  | }; | 
|  |  | 
|  | handleSymbols(Exports); | 
|  | handleSymbols(Reexports, SymbolFlags::Rexported); | 
|  | handleSymbols(Undefineds, SymbolFlags::Undefined); | 
|  |  | 
|  | return File; | 
|  | } | 
|  |  | 
|  | unsigned TBDVersion; | 
|  | std::vector<UUIDv4> UUIDs; | 
|  | TargetList Targets; | 
|  | StringRef InstallName; | 
|  | PackedVersion CurrentVersion; | 
|  | PackedVersion CompatibilityVersion; | 
|  | SwiftVersion SwiftABIVersion{0}; | 
|  | std::vector<MetadataSection> AllowableClients; | 
|  | std::vector<MetadataSection> ReexportedLibraries; | 
|  | TBDFlags Flags{TBDFlags::None}; | 
|  | std::vector<UmbrellaSection> ParentUmbrellas; | 
|  | SectionList Exports; | 
|  | SectionList Reexports; | 
|  | SectionList Undefineds; | 
|  |  | 
|  | private: | 
|  | void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries, | 
|  | std::vector<MetadataSection> &Section) { | 
|  | std::set<TargetList> targetSet; | 
|  | std::map<const InterfaceFileRef *, TargetList> valueToTargetList; | 
|  | for (const auto &library : Libraries) { | 
|  | TargetList targets(library.targets()); | 
|  | valueToTargetList[&library] = targets; | 
|  | targetSet.emplace(std::move(targets)); | 
|  | } | 
|  |  | 
|  | for (const auto &targets : targetSet) { | 
|  | MetadataSection CurrentSection; | 
|  | CurrentSection.Targets.insert(CurrentSection.Targets.begin(), | 
|  | targets.begin(), targets.end()); | 
|  |  | 
|  | for (const auto &it : valueToTargetList) { | 
|  | if (it.second != targets) | 
|  | continue; | 
|  |  | 
|  | CurrentSection.Values.emplace_back(it.first->getInstallName()); | 
|  | } | 
|  | llvm::sort(CurrentSection.Values); | 
|  | Section.emplace_back(std::move(CurrentSection)); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | static void mapKeysToValues(FileType FileKind, IO &IO, | 
|  | const InterfaceFile *&File) { | 
|  | MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File); | 
|  | std::vector<UUID> EmptyUUID; | 
|  | IO.mapRequired("archs", Keys->Architectures); | 
|  | if (FileKind != FileType::TBD_V1) | 
|  | IO.mapOptional("uuids", EmptyUUID); | 
|  | IO.mapRequired("platform", Keys->Platforms); | 
|  | if (FileKind != FileType::TBD_V1) | 
|  | IO.mapOptional("flags", Keys->Flags, TBDFlags::None); | 
|  | IO.mapRequired("install-name", Keys->InstallName); | 
|  | IO.mapOptional("current-version", Keys->CurrentVersion, | 
|  | PackedVersion(1, 0, 0)); | 
|  | IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, | 
|  | PackedVersion(1, 0, 0)); | 
|  | if (FileKind != FileType::TBD_V3) | 
|  | IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0)); | 
|  | else | 
|  | IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, | 
|  | SwiftVersion(0)); | 
|  | IO.mapOptional("objc-constraint", Keys->ObjCConstraint, | 
|  | (FileKind == FileType::TBD_V1) | 
|  | ? ObjCConstraintType::None | 
|  | : ObjCConstraintType::Retain_Release); | 
|  | if (FileKind != FileType::TBD_V1) | 
|  | IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef()); | 
|  | IO.mapOptional("exports", Keys->Exports); | 
|  | if (FileKind != FileType::TBD_V1) | 
|  | IO.mapOptional("undefineds", Keys->Undefineds); | 
|  | } | 
|  |  | 
|  | static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) { | 
|  | MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO, | 
|  | File); | 
|  | std::vector<UUIDv4> EmptyUUID; | 
|  | IO.mapTag("!tapi-tbd", true); | 
|  | IO.mapRequired("tbd-version", Keys->TBDVersion); | 
|  | IO.mapRequired("targets", Keys->Targets); | 
|  | IO.mapOptional("uuids", EmptyUUID); | 
|  | IO.mapOptional("flags", Keys->Flags, TBDFlags::None); | 
|  | IO.mapRequired("install-name", Keys->InstallName); | 
|  | IO.mapOptional("current-version", Keys->CurrentVersion, | 
|  | PackedVersion(1, 0, 0)); | 
|  | IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, | 
|  | PackedVersion(1, 0, 0)); | 
|  | IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0)); | 
|  | IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas); | 
|  | auto OptionKind = MetadataSection::Option::Clients; | 
|  | IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients, | 
|  | OptionKind); | 
|  | OptionKind = MetadataSection::Option::Libraries; | 
|  | IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries, | 
|  | OptionKind); | 
|  | IO.mapOptional("exports", Keys->Exports); | 
|  | IO.mapOptional("reexports", Keys->Reexports); | 
|  | IO.mapOptional("undefineds", Keys->Undefineds); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <> | 
|  | struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> { | 
|  | static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) { | 
|  | return Seq.size(); | 
|  | } | 
|  | static const InterfaceFile *& | 
|  | element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) { | 
|  | if (Index >= Seq.size()) | 
|  | Seq.resize(Index + 1); | 
|  | return Seq[Index]; | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // end namespace yaml. | 
|  | } // namespace llvm | 
|  |  | 
|  | static void DiagHandler(const SMDiagnostic &Diag, void *Context) { | 
|  | auto *File = static_cast<TextAPIContext *>(Context); | 
|  | SmallString<1024> Message; | 
|  | raw_svector_ostream S(Message); | 
|  |  | 
|  | SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path, | 
|  | Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(), | 
|  | Diag.getMessage(), Diag.getLineContents(), | 
|  | Diag.getRanges(), Diag.getFixIts()); | 
|  |  | 
|  | NewDiag.print(nullptr, S); | 
|  | File->ErrorMessage = ("malformed file\n" + Message).str(); | 
|  | } | 
|  |  | 
|  | Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) { | 
|  | auto TAPIFile = InputBuffer.getBuffer().trim(); | 
|  | if (TAPIFile.starts_with("{") && TAPIFile.ends_with("}")) | 
|  | return FileType::TBD_V5; | 
|  |  | 
|  | if (!TAPIFile.ends_with("...")) | 
|  | return createStringError(std::errc::not_supported, "unsupported file type"); | 
|  |  | 
|  | if (TAPIFile.starts_with("--- !tapi-tbd")) | 
|  | return FileType::TBD_V4; | 
|  |  | 
|  | if (TAPIFile.starts_with("--- !tapi-tbd-v3")) | 
|  | return FileType::TBD_V3; | 
|  |  | 
|  | if (TAPIFile.starts_with("--- !tapi-tbd-v2")) | 
|  | return FileType::TBD_V2; | 
|  |  | 
|  | if (TAPIFile.starts_with("--- !tapi-tbd-v1") || | 
|  | TAPIFile.starts_with("---\narchs:")) | 
|  | return FileType::TBD_V1; | 
|  |  | 
|  | return createStringError(std::errc::not_supported, "unsupported file type"); | 
|  | } | 
|  |  | 
|  | Expected<std::unique_ptr<InterfaceFile>> | 
|  | TextAPIReader::get(MemoryBufferRef InputBuffer) { | 
|  | TextAPIContext Ctx; | 
|  | Ctx.Path = std::string(InputBuffer.getBufferIdentifier()); | 
|  | if (auto FTOrErr = canRead(InputBuffer)) | 
|  | Ctx.FileKind = *FTOrErr; | 
|  | else | 
|  | return FTOrErr.takeError(); | 
|  |  | 
|  | // Handle JSON Format. | 
|  | if (Ctx.FileKind >= FileType::TBD_V5) { | 
|  | auto FileOrErr = getInterfaceFileFromJSON(InputBuffer.getBuffer()); | 
|  | if (!FileOrErr) | 
|  | return FileOrErr.takeError(); | 
|  |  | 
|  | (*FileOrErr)->setPath(Ctx.Path); | 
|  | return std::move(*FileOrErr); | 
|  | } | 
|  | yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx); | 
|  |  | 
|  | // Fill vector with interface file objects created by parsing the YAML file. | 
|  | std::vector<const InterfaceFile *> Files; | 
|  | YAMLIn >> Files; | 
|  |  | 
|  | // YAMLIn dynamically allocates for Interface file and in case of error, | 
|  | // memory leak will occur unless wrapped around unique_ptr | 
|  | auto File = std::unique_ptr<InterfaceFile>( | 
|  | const_cast<InterfaceFile *>(Files.front())); | 
|  |  | 
|  | for (const InterfaceFile *FI : llvm::drop_begin(Files)) | 
|  | File->addDocument( | 
|  | std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI))); | 
|  |  | 
|  | if (YAMLIn.error()) | 
|  | return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error()); | 
|  |  | 
|  | return std::move(File); | 
|  | } | 
|  |  | 
|  | Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File, | 
|  | const FileType FileKind, bool Compact) { | 
|  | TextAPIContext Ctx; | 
|  | Ctx.Path = std::string(File.getPath()); | 
|  |  | 
|  | // Prefer parameter for format if passed, otherwise fallback to the File | 
|  | // FileType. | 
|  | Ctx.FileKind = | 
|  | (FileKind == FileType::Invalid) ? File.getFileType() : FileKind; | 
|  |  | 
|  | // Write out in JSON format. | 
|  | if (Ctx.FileKind >= FileType::TBD_V5) { | 
|  | return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact); | 
|  | } | 
|  |  | 
|  | llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80); | 
|  |  | 
|  | std::vector<const InterfaceFile *> Files; | 
|  | Files.emplace_back(&File); | 
|  |  | 
|  | for (const auto &Document : File.documents()) | 
|  | Files.emplace_back(Document.get()); | 
|  |  | 
|  | // Stream out yaml. | 
|  | YAMLOut << Files; | 
|  |  | 
|  | return Error::success(); | 
|  | } |