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 
262 // clang-format off
263 enum TBDFlags : unsigned {
264   None                         = 0U,
265   FlatNamespace                = 1U << 0,
266   NotApplicationExtensionSafe  = 1U << 1,
267   InstallAPI                   = 1U << 2,
268   LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/InstallAPI),
269 };
270 // clang-format on
271 } // end anonymous namespace.
272 
273 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture)
274 LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection)
275 LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection)
276 // Specific to TBDv4
277 LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection)
278 LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection)
279 LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection)
280 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target)
281 LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4)
282 
283 namespace llvm {
284 namespace yaml {
285 
286 template <> struct MappingTraits<ExportSection> {
287   static void mapping(IO &IO, ExportSection &Section) {
288     const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
289     assert((!Ctx || (Ctx && Ctx->FileKind != FileType::Invalid)) &&
290            "File type is not set in YAML context");
291 
292     IO.mapRequired("archs", Section.Architectures);
293     if (Ctx->FileKind == FileType::TBD_V1)
294       IO.mapOptional("allowed-clients", Section.AllowableClients);
295     else
296       IO.mapOptional("allowable-clients", Section.AllowableClients);
297     IO.mapOptional("re-exports", Section.ReexportedLibraries);
298     IO.mapOptional("symbols", Section.Symbols);
299     IO.mapOptional("objc-classes", Section.Classes);
300     if (Ctx->FileKind == FileType::TBD_V3)
301       IO.mapOptional("objc-eh-types", Section.ClassEHs);
302     IO.mapOptional("objc-ivars", Section.IVars);
303     IO.mapOptional("weak-def-symbols", Section.WeakDefSymbols);
304     IO.mapOptional("thread-local-symbols", Section.TLVSymbols);
305   }
306 };
307 
308 template <> struct MappingTraits<UndefinedSection> {
309   static void mapping(IO &IO, UndefinedSection &Section) {
310     const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
311     assert((!Ctx || (Ctx && Ctx->FileKind != FileType::Invalid)) &&
312            "File type is not set in YAML context");
313 
314     IO.mapRequired("archs", Section.Architectures);
315     IO.mapOptional("symbols", Section.Symbols);
316     IO.mapOptional("objc-classes", Section.Classes);
317     if (Ctx->FileKind == FileType::TBD_V3)
318       IO.mapOptional("objc-eh-types", Section.ClassEHs);
319     IO.mapOptional("objc-ivars", Section.IVars);
320     IO.mapOptional("weak-ref-symbols", Section.WeakRefSymbols);
321   }
322 };
323 
324 template <> struct MappingTraits<SymbolSection> {
325   static void mapping(IO &IO, SymbolSection &Section) {
326     IO.mapRequired("targets", Section.Targets);
327     IO.mapOptional("symbols", Section.Symbols);
328     IO.mapOptional("objc-classes", Section.Classes);
329     IO.mapOptional("objc-eh-types", Section.ClassEHs);
330     IO.mapOptional("objc-ivars", Section.Ivars);
331     IO.mapOptional("weak-symbols", Section.WeakSymbols);
332     IO.mapOptional("thread-local-symbols", Section.TlvSymbols);
333   }
334 };
335 
336 template <> struct MappingTraits<UmbrellaSection> {
337   static void mapping(IO &IO, UmbrellaSection &Section) {
338     IO.mapRequired("targets", Section.Targets);
339     IO.mapRequired("umbrella", Section.Umbrella);
340   }
341 };
342 
343 template <> struct MappingTraits<UUIDv4> {
344   static void mapping(IO &IO, UUIDv4 &UUID) {
345     IO.mapRequired("target", UUID.TargetID);
346     IO.mapRequired("value", UUID.Value);
347   }
348 };
349 
350 template <>
351 struct MappingContextTraits<MetadataSection, MetadataSection::Option> {
352   static void mapping(IO &IO, MetadataSection &Section,
353                       MetadataSection::Option &OptionKind) {
354     IO.mapRequired("targets", Section.Targets);
355     switch (OptionKind) {
356     case MetadataSection::Option::Clients:
357       IO.mapRequired("clients", Section.Values);
358       return;
359     case MetadataSection::Option::Libraries:
360       IO.mapRequired("libraries", Section.Values);
361       return;
362     }
363     llvm_unreachable("unexpected option for metadata");
364   }
365 };
366 
367 template <> struct ScalarBitSetTraits<TBDFlags> {
368   static void bitset(IO &IO, TBDFlags &Flags) {
369     IO.bitSetCase(Flags, "flat_namespace", TBDFlags::FlatNamespace);
370     IO.bitSetCase(Flags, "not_app_extension_safe",
371                   TBDFlags::NotApplicationExtensionSafe);
372     IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI);
373   }
374 };
375 
376 template <> struct ScalarTraits<Target> {
377   static void output(const Target &Value, void *, raw_ostream &OS) {
378     OS << Value.Arch << "-";
379     switch (Value.Platform) {
380     default:
381       OS << "unknown";
382       break;
383     case PLATFORM_MACOS:
384       OS << "macos";
385       break;
386     case PLATFORM_IOS:
387       OS << "ios";
388       break;
389     case PLATFORM_TVOS:
390       OS << "tvos";
391       break;
392     case PLATFORM_WATCHOS:
393       OS << "watchos";
394       break;
395     case PLATFORM_BRIDGEOS:
396       OS << "bridgeos";
397       break;
398     case PLATFORM_MACCATALYST:
399       OS << "maccatalyst";
400       break;
401     case PLATFORM_IOSSIMULATOR:
402       OS << "ios-simulator";
403       break;
404     case PLATFORM_TVOSSIMULATOR:
405       OS << "tvos-simulator";
406       break;
407     case PLATFORM_WATCHOSSIMULATOR:
408       OS << "watchos-simulator";
409       break;
410     case PLATFORM_DRIVERKIT:
411       OS << "driverkit";
412       break;
413     }
414   }
415 
416   static StringRef input(StringRef Scalar, void *, Target &Value) {
417     auto Result = Target::create(Scalar);
418     if (!Result) {
419       consumeError(Result.takeError());
420       return "unparsable target";
421     }
422 
423     Value = *Result;
424     if (Value.Arch == AK_unknown)
425       return "unknown architecture";
426     if (Value.Platform == PLATFORM_UNKNOWN)
427       return "unknown platform";
428 
429     return {};
430   }
431 
432   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
433 };
434 
435 template <> struct MappingTraits<const InterfaceFile *> {
436   struct NormalizedTBD {
437     explicit NormalizedTBD(IO &IO) {}
438     NormalizedTBD(IO &IO, const InterfaceFile *&File) {
439       Architectures = File->getArchitectures();
440       UUIDs = File->uuids();
441       Platforms = File->getPlatforms();
442       InstallName = File->getInstallName();
443       CurrentVersion = PackedVersion(File->getCurrentVersion());
444       CompatibilityVersion = PackedVersion(File->getCompatibilityVersion());
445       SwiftABIVersion = File->getSwiftABIVersion();
446       ObjCConstraint = File->getObjCConstraint();
447 
448       Flags = TBDFlags::None;
449       if (!File->isApplicationExtensionSafe())
450         Flags |= TBDFlags::NotApplicationExtensionSafe;
451 
452       if (!File->isTwoLevelNamespace())
453         Flags |= TBDFlags::FlatNamespace;
454 
455       if (File->isInstallAPI())
456         Flags |= TBDFlags::InstallAPI;
457 
458       if (!File->umbrellas().empty())
459         ParentUmbrella = File->umbrellas().begin()->second;
460 
461       std::set<ArchitectureSet> ArchSet;
462       for (const auto &Library : File->allowableClients())
463         ArchSet.insert(Library.getArchitectures());
464 
465       for (const auto &Library : File->reexportedLibraries())
466         ArchSet.insert(Library.getArchitectures());
467 
468       std::map<const Symbol *, ArchitectureSet> SymbolToArchSet;
469       for (const auto *Symbol : File->exports()) {
470         auto Architectures = Symbol->getArchitectures();
471         SymbolToArchSet[Symbol] = Architectures;
472         ArchSet.insert(Architectures);
473       }
474 
475       for (auto Architectures : ArchSet) {
476         ExportSection Section;
477         Section.Architectures = Architectures;
478 
479         for (const auto &Library : File->allowableClients())
480           if (Library.getArchitectures() == Architectures)
481             Section.AllowableClients.emplace_back(Library.getInstallName());
482 
483         for (const auto &Library : File->reexportedLibraries())
484           if (Library.getArchitectures() == Architectures)
485             Section.ReexportedLibraries.emplace_back(Library.getInstallName());
486 
487         for (const auto &SymArch : SymbolToArchSet) {
488           if (SymArch.second != Architectures)
489             continue;
490 
491           const auto *Symbol = SymArch.first;
492           switch (Symbol->getKind()) {
493           case SymbolKind::GlobalSymbol:
494             if (Symbol->isWeakDefined())
495               Section.WeakDefSymbols.emplace_back(Symbol->getName());
496             else if (Symbol->isThreadLocalValue())
497               Section.TLVSymbols.emplace_back(Symbol->getName());
498             else
499               Section.Symbols.emplace_back(Symbol->getName());
500             break;
501           case SymbolKind::ObjectiveCClass:
502             if (File->getFileType() != FileType::TBD_V3)
503               Section.Classes.emplace_back(
504                   copyString("_" + Symbol->getName().str()));
505             else
506               Section.Classes.emplace_back(Symbol->getName());
507             break;
508           case SymbolKind::ObjectiveCClassEHType:
509             if (File->getFileType() != FileType::TBD_V3)
510               Section.Symbols.emplace_back(
511                   copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));
512             else
513               Section.ClassEHs.emplace_back(Symbol->getName());
514             break;
515           case SymbolKind::ObjectiveCInstanceVariable:
516             if (File->getFileType() != FileType::TBD_V3)
517               Section.IVars.emplace_back(
518                   copyString("_" + Symbol->getName().str()));
519             else
520               Section.IVars.emplace_back(Symbol->getName());
521             break;
522           }
523         }
524         llvm::sort(Section.Symbols);
525         llvm::sort(Section.Classes);
526         llvm::sort(Section.ClassEHs);
527         llvm::sort(Section.IVars);
528         llvm::sort(Section.WeakDefSymbols);
529         llvm::sort(Section.TLVSymbols);
530         Exports.emplace_back(std::move(Section));
531       }
532 
533       ArchSet.clear();
534       SymbolToArchSet.clear();
535 
536       for (const auto *Symbol : File->undefineds()) {
537         auto Architectures = Symbol->getArchitectures();
538         SymbolToArchSet[Symbol] = Architectures;
539         ArchSet.insert(Architectures);
540       }
541 
542       for (auto Architectures : ArchSet) {
543         UndefinedSection Section;
544         Section.Architectures = Architectures;
545 
546         for (const auto &SymArch : SymbolToArchSet) {
547           if (SymArch.second != Architectures)
548             continue;
549 
550           const auto *Symbol = SymArch.first;
551           switch (Symbol->getKind()) {
552           case SymbolKind::GlobalSymbol:
553             if (Symbol->isWeakReferenced())
554               Section.WeakRefSymbols.emplace_back(Symbol->getName());
555             else
556               Section.Symbols.emplace_back(Symbol->getName());
557             break;
558           case SymbolKind::ObjectiveCClass:
559             if (File->getFileType() != FileType::TBD_V3)
560               Section.Classes.emplace_back(
561                   copyString("_" + Symbol->getName().str()));
562             else
563               Section.Classes.emplace_back(Symbol->getName());
564             break;
565           case SymbolKind::ObjectiveCClassEHType:
566             if (File->getFileType() != FileType::TBD_V3)
567               Section.Symbols.emplace_back(
568                   copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));
569             else
570               Section.ClassEHs.emplace_back(Symbol->getName());
571             break;
572           case SymbolKind::ObjectiveCInstanceVariable:
573             if (File->getFileType() != FileType::TBD_V3)
574               Section.IVars.emplace_back(
575                   copyString("_" + Symbol->getName().str()));
576             else
577               Section.IVars.emplace_back(Symbol->getName());
578             break;
579           }
580         }
581         llvm::sort(Section.Symbols);
582         llvm::sort(Section.Classes);
583         llvm::sort(Section.ClassEHs);
584         llvm::sort(Section.IVars);
585         llvm::sort(Section.WeakRefSymbols);
586         Undefineds.emplace_back(std::move(Section));
587       }
588     }
589 
590     // TBD v1 - TBD v3 files only support one platform and several
591     // architectures. It is possible to have more than one platform for TBD v3
592     // files, but the architectures don't apply to all
593     // platforms, specifically to filter out the i386 slice from
594     // platform macCatalyst.
595     TargetList synthesizeTargets(ArchitectureSet Architectures,
596                                  const PlatformSet &Platforms) {
597       TargetList Targets;
598 
599       for (auto Platform : Platforms) {
600         Platform = mapToPlatformType(Platform, Architectures.hasX86());
601 
602         for (const auto &&Architecture : Architectures) {
603           if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST))
604             continue;
605 
606           Targets.emplace_back(Architecture, Platform);
607         }
608       }
609       return Targets;
610     }
611 
612     const InterfaceFile *denormalize(IO &IO) {
613       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
614       assert(Ctx);
615 
616       auto *File = new InterfaceFile;
617       File->setPath(Ctx->Path);
618       File->setFileType(Ctx->FileKind);
619       File->addTargets(synthesizeTargets(Architectures, Platforms));
620       for (auto &ID : UUIDs)
621         File->addUUID(ID.first, ID.second);
622       File->setInstallName(InstallName);
623       File->setCurrentVersion(CurrentVersion);
624       File->setCompatibilityVersion(CompatibilityVersion);
625       File->setSwiftABIVersion(SwiftABIVersion);
626       File->setObjCConstraint(ObjCConstraint);
627       for (const auto &Target : File->targets())
628         File->addParentUmbrella(Target, ParentUmbrella);
629 
630       if (Ctx->FileKind == FileType::TBD_V1) {
631         File->setTwoLevelNamespace();
632         File->setApplicationExtensionSafe();
633       } else {
634         File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
635         File->setApplicationExtensionSafe(
636             !(Flags & TBDFlags::NotApplicationExtensionSafe));
637         File->setInstallAPI(Flags & TBDFlags::InstallAPI);
638       }
639 
640       for (const auto &Section : Exports) {
641         const auto Targets =
642             synthesizeTargets(Section.Architectures, Platforms);
643 
644         for (const auto &Lib : Section.AllowableClients)
645           for (const auto &Target : Targets)
646             File->addAllowableClient(Lib, Target);
647 
648         for (const auto &Lib : Section.ReexportedLibraries)
649           for (const auto &Target : Targets)
650             File->addReexportedLibrary(Lib, Target);
651 
652         for (const auto &Symbol : Section.Symbols) {
653           if (Ctx->FileKind != FileType::TBD_V3 &&
654               Symbol.value.startswith("_OBJC_EHTYPE_$_"))
655             File->addSymbol(SymbolKind::ObjectiveCClassEHType,
656                             Symbol.value.drop_front(15), Targets);
657           else
658             File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets);
659         }
660         for (auto &Symbol : Section.Classes) {
661           auto Name = Symbol.value;
662           if (Ctx->FileKind != FileType::TBD_V3)
663             Name = Name.drop_front();
664           File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets);
665         }
666         for (auto &Symbol : Section.ClassEHs)
667           File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets);
668         for (auto &Symbol : Section.IVars) {
669           auto Name = Symbol.value;
670           if (Ctx->FileKind != FileType::TBD_V3)
671             Name = Name.drop_front();
672           File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name,
673                           Targets);
674         }
675         for (auto &Symbol : Section.WeakDefSymbols)
676           File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
677                           SymbolFlags::WeakDefined);
678         for (auto &Symbol : Section.TLVSymbols)
679           File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
680                           SymbolFlags::ThreadLocalValue);
681       }
682 
683       for (const auto &Section : Undefineds) {
684         const auto Targets =
685             synthesizeTargets(Section.Architectures, Platforms);
686         for (auto &Symbol : Section.Symbols) {
687           if (Ctx->FileKind != FileType::TBD_V3 &&
688               Symbol.value.startswith("_OBJC_EHTYPE_$_"))
689             File->addSymbol(SymbolKind::ObjectiveCClassEHType,
690                             Symbol.value.drop_front(15), Targets,
691                             SymbolFlags::Undefined);
692           else
693             File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
694                             SymbolFlags::Undefined);
695         }
696         for (auto &Symbol : Section.Classes) {
697           auto Name = Symbol.value;
698           if (Ctx->FileKind != FileType::TBD_V3)
699             Name = Name.drop_front();
700           File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets,
701                           SymbolFlags::Undefined);
702         }
703         for (auto &Symbol : Section.ClassEHs)
704           File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets,
705                           SymbolFlags::Undefined);
706         for (auto &Symbol : Section.IVars) {
707           auto Name = Symbol.value;
708           if (Ctx->FileKind != FileType::TBD_V3)
709             Name = Name.drop_front();
710           File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets,
711                           SymbolFlags::Undefined);
712         }
713         for (auto &Symbol : Section.WeakRefSymbols)
714           File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
715                           SymbolFlags::Undefined | SymbolFlags::WeakReferenced);
716       }
717 
718       return File;
719     }
720 
721     llvm::BumpPtrAllocator Allocator;
722     StringRef copyString(StringRef String) {
723       if (String.empty())
724         return {};
725 
726       void *Ptr = Allocator.Allocate(String.size(), 1);
727       memcpy(Ptr, String.data(), String.size());
728       return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
729     }
730 
731     std::vector<Architecture> Architectures;
732     std::vector<UUID> UUIDs;
733     PlatformSet Platforms;
734     StringRef InstallName;
735     PackedVersion CurrentVersion;
736     PackedVersion CompatibilityVersion;
737     SwiftVersion SwiftABIVersion{0};
738     ObjCConstraintType ObjCConstraint{ObjCConstraintType::None};
739     TBDFlags Flags{TBDFlags::None};
740     StringRef ParentUmbrella;
741     std::vector<ExportSection> Exports;
742     std::vector<UndefinedSection> Undefineds;
743   };
744 
745   static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) {
746     if (IO.mapTag("!tapi-tbd", false))
747       Ctx->FileKind = FileType::TBD_V4;
748     else if (IO.mapTag("!tapi-tbd-v3", false))
749       Ctx->FileKind = FileType::TBD_V3;
750     else if (IO.mapTag("!tapi-tbd-v2", false))
751       Ctx->FileKind = FileType::TBD_V2;
752     else if (IO.mapTag("!tapi-tbd-v1", false) ||
753              IO.mapTag("tag:yaml.org,2002:map", false))
754       Ctx->FileKind = FileType::TBD_V1;
755     else {
756       Ctx->FileKind = FileType::Invalid;
757       return;
758     }
759   }
760 
761   static void mapping(IO &IO, const InterfaceFile *&File) {
762     auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
763     assert((!Ctx || !IO.outputting() ||
764             (Ctx && Ctx->FileKind != FileType::Invalid)) &&
765            "File type is not set in YAML context");
766 
767     if (!IO.outputting()) {
768       setFileTypeForInput(Ctx, IO);
769       switch (Ctx->FileKind) {
770       default:
771         break;
772       case FileType::TBD_V4:
773         mapKeysToValuesV4(IO, File);
774         return;
775       case FileType::Invalid:
776         IO.setError("unsupported file type");
777         return;
778       }
779     } else {
780       // Set file type when writing.
781       switch (Ctx->FileKind) {
782       default:
783         llvm_unreachable("unexpected file type");
784       case FileType::TBD_V4:
785         mapKeysToValuesV4(IO, File);
786         return;
787       case FileType::TBD_V3:
788         IO.mapTag("!tapi-tbd-v3", true);
789         break;
790       case FileType::TBD_V2:
791         IO.mapTag("!tapi-tbd-v2", true);
792         break;
793       case FileType::TBD_V1:
794         // Don't write the tag into the .tbd file for TBD v1
795         break;
796       }
797     }
798     mapKeysToValues(Ctx->FileKind, IO, File);
799   }
800 
801   using SectionList = std::vector<SymbolSection>;
802   struct NormalizedTBD_V4 {
803     explicit NormalizedTBD_V4(IO &IO) {}
804     NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) {
805       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
806       assert(Ctx);
807       TBDVersion = Ctx->FileKind >> 1;
808       Targets.insert(Targets.begin(), File->targets().begin(),
809                      File->targets().end());
810       for (const auto &IT : File->uuids())
811         UUIDs.emplace_back(IT.first, IT.second);
812       InstallName = File->getInstallName();
813       CurrentVersion = File->getCurrentVersion();
814       CompatibilityVersion = File->getCompatibilityVersion();
815       SwiftABIVersion = File->getSwiftABIVersion();
816 
817       Flags = TBDFlags::None;
818       if (!File->isApplicationExtensionSafe())
819         Flags |= TBDFlags::NotApplicationExtensionSafe;
820 
821       if (!File->isTwoLevelNamespace())
822         Flags |= TBDFlags::FlatNamespace;
823 
824       if (File->isInstallAPI())
825         Flags |= TBDFlags::InstallAPI;
826 
827       {
828         std::map<std::string, TargetList> valueToTargetList;
829         for (const auto &it : File->umbrellas())
830           valueToTargetList[it.second].emplace_back(it.first);
831 
832         for (const auto &it : valueToTargetList) {
833           UmbrellaSection CurrentSection;
834           CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
835                                         it.second.begin(), it.second.end());
836           CurrentSection.Umbrella = it.first;
837           ParentUmbrellas.emplace_back(std::move(CurrentSection));
838         }
839       }
840 
841       assignTargetsToLibrary(File->allowableClients(), AllowableClients);
842       assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries);
843 
844       auto handleSymbols =
845           [](SectionList &CurrentSections,
846              InterfaceFile::const_filtered_symbol_range Symbols,
847              std::function<bool(const Symbol *)> Pred) {
848             std::set<TargetList> TargetSet;
849             std::map<const Symbol *, TargetList> SymbolToTargetList;
850             for (const auto *Symbol : Symbols) {
851               if (!Pred(Symbol))
852                 continue;
853               TargetList Targets(Symbol->targets());
854               SymbolToTargetList[Symbol] = Targets;
855               TargetSet.emplace(std::move(Targets));
856             }
857             for (const auto &TargetIDs : TargetSet) {
858               SymbolSection CurrentSection;
859               CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
860                                             TargetIDs.begin(), TargetIDs.end());
861 
862               for (const auto &IT : SymbolToTargetList) {
863                 if (IT.second != TargetIDs)
864                   continue;
865 
866                 const auto *Symbol = IT.first;
867                 switch (Symbol->getKind()) {
868                 case SymbolKind::GlobalSymbol:
869                   if (Symbol->isWeakDefined())
870                     CurrentSection.WeakSymbols.emplace_back(Symbol->getName());
871                   else if (Symbol->isThreadLocalValue())
872                     CurrentSection.TlvSymbols.emplace_back(Symbol->getName());
873                   else
874                     CurrentSection.Symbols.emplace_back(Symbol->getName());
875                   break;
876                 case SymbolKind::ObjectiveCClass:
877                   CurrentSection.Classes.emplace_back(Symbol->getName());
878                   break;
879                 case SymbolKind::ObjectiveCClassEHType:
880                   CurrentSection.ClassEHs.emplace_back(Symbol->getName());
881                   break;
882                 case SymbolKind::ObjectiveCInstanceVariable:
883                   CurrentSection.Ivars.emplace_back(Symbol->getName());
884                   break;
885                 }
886               }
887               sort(CurrentSection.Symbols);
888               sort(CurrentSection.Classes);
889               sort(CurrentSection.ClassEHs);
890               sort(CurrentSection.Ivars);
891               sort(CurrentSection.WeakSymbols);
892               sort(CurrentSection.TlvSymbols);
893               CurrentSections.emplace_back(std::move(CurrentSection));
894             }
895           };
896 
897       handleSymbols(Exports, File->exports(), [](const Symbol *Symbol) {
898         return !Symbol->isReexported();
899       });
900       handleSymbols(Reexports, File->exports(), [](const Symbol *Symbol) {
901         return Symbol->isReexported();
902       });
903       handleSymbols(Undefineds, File->undefineds(),
904                     [](const Symbol *Symbol) { return true; });
905     }
906 
907     const InterfaceFile *denormalize(IO &IO) {
908       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
909       assert(Ctx);
910 
911       auto *File = new InterfaceFile;
912       File->setPath(Ctx->Path);
913       File->setFileType(Ctx->FileKind);
914       for (auto &id : UUIDs)
915         File->addUUID(id.TargetID, id.Value);
916       File->addTargets(Targets);
917       File->setInstallName(InstallName);
918       File->setCurrentVersion(CurrentVersion);
919       File->setCompatibilityVersion(CompatibilityVersion);
920       File->setSwiftABIVersion(SwiftABIVersion);
921       for (const auto &CurrentSection : ParentUmbrellas)
922         for (const auto &target : CurrentSection.Targets)
923           File->addParentUmbrella(target, CurrentSection.Umbrella);
924       File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
925       File->setApplicationExtensionSafe(
926           !(Flags & TBDFlags::NotApplicationExtensionSafe));
927       File->setInstallAPI(Flags & TBDFlags::InstallAPI);
928 
929       for (const auto &CurrentSection : AllowableClients) {
930         for (const auto &lib : CurrentSection.Values)
931           for (const auto &Target : CurrentSection.Targets)
932             File->addAllowableClient(lib, Target);
933       }
934 
935       for (const auto &CurrentSection : ReexportedLibraries) {
936         for (const auto &Lib : CurrentSection.Values)
937           for (const auto &Target : CurrentSection.Targets)
938             File->addReexportedLibrary(Lib, Target);
939       }
940 
941       auto handleSymbols = [File](const SectionList &CurrentSections,
942                                   SymbolFlags Flag = SymbolFlags::None) {
943         for (const auto &CurrentSection : CurrentSections) {
944           for (auto &sym : CurrentSection.Symbols)
945             File->addSymbol(SymbolKind::GlobalSymbol, sym,
946                             CurrentSection.Targets, Flag);
947 
948           for (auto &sym : CurrentSection.Classes)
949             File->addSymbol(SymbolKind::ObjectiveCClass, sym,
950                             CurrentSection.Targets);
951 
952           for (auto &sym : CurrentSection.ClassEHs)
953             File->addSymbol(SymbolKind::ObjectiveCClassEHType, sym,
954                             CurrentSection.Targets);
955 
956           for (auto &sym : CurrentSection.Ivars)
957             File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, sym,
958                             CurrentSection.Targets);
959 
960           for (auto &sym : CurrentSection.WeakSymbols)
961             File->addSymbol(SymbolKind::GlobalSymbol, sym,
962                             CurrentSection.Targets, SymbolFlags::WeakDefined);
963 
964           for (auto &sym : CurrentSection.TlvSymbols)
965             File->addSymbol(SymbolKind::GlobalSymbol, sym,
966                             CurrentSection.Targets,
967                             SymbolFlags::ThreadLocalValue);
968         }
969       };
970 
971       handleSymbols(Exports);
972       handleSymbols(Reexports, SymbolFlags::Rexported);
973       handleSymbols(Undefineds, SymbolFlags::Undefined);
974 
975       return File;
976     }
977 
978     unsigned TBDVersion;
979     std::vector<UUIDv4> UUIDs;
980     TargetList Targets;
981     StringRef InstallName;
982     PackedVersion CurrentVersion;
983     PackedVersion CompatibilityVersion;
984     SwiftVersion SwiftABIVersion{0};
985     std::vector<MetadataSection> AllowableClients;
986     std::vector<MetadataSection> ReexportedLibraries;
987     TBDFlags Flags{TBDFlags::None};
988     std::vector<UmbrellaSection> ParentUmbrellas;
989     SectionList Exports;
990     SectionList Reexports;
991     SectionList Undefineds;
992 
993   private:
994     void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries,
995                                 std::vector<MetadataSection> &Section) {
996       std::set<TargetList> targetSet;
997       std::map<const InterfaceFileRef *, TargetList> valueToTargetList;
998       for (const auto &library : Libraries) {
999         TargetList targets(library.targets());
1000         valueToTargetList[&library] = targets;
1001         targetSet.emplace(std::move(targets));
1002       }
1003 
1004       for (const auto &targets : targetSet) {
1005         MetadataSection CurrentSection;
1006         CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
1007                                       targets.begin(), targets.end());
1008 
1009         for (const auto &it : valueToTargetList) {
1010           if (it.second != targets)
1011             continue;
1012 
1013           CurrentSection.Values.emplace_back(it.first->getInstallName());
1014         }
1015         llvm::sort(CurrentSection.Values);
1016         Section.emplace_back(std::move(CurrentSection));
1017       }
1018     }
1019   };
1020 
1021   static void mapKeysToValues(FileType FileKind, IO &IO,
1022                               const InterfaceFile *&File) {
1023     MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File);
1024     IO.mapRequired("archs", Keys->Architectures);
1025     if (FileKind != FileType::TBD_V1)
1026       IO.mapOptional("uuids", Keys->UUIDs);
1027     IO.mapRequired("platform", Keys->Platforms);
1028     if (FileKind != FileType::TBD_V1)
1029       IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
1030     IO.mapRequired("install-name", Keys->InstallName);
1031     IO.mapOptional("current-version", Keys->CurrentVersion,
1032                    PackedVersion(1, 0, 0));
1033     IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,
1034                    PackedVersion(1, 0, 0));
1035     if (FileKind != FileType::TBD_V3)
1036       IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0));
1037     else
1038       IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion,
1039                      SwiftVersion(0));
1040     IO.mapOptional("objc-constraint", Keys->ObjCConstraint,
1041                    (FileKind == FileType::TBD_V1)
1042                        ? ObjCConstraintType::None
1043                        : ObjCConstraintType::Retain_Release);
1044     if (FileKind != FileType::TBD_V1)
1045       IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef());
1046     IO.mapOptional("exports", Keys->Exports);
1047     if (FileKind != FileType::TBD_V1)
1048       IO.mapOptional("undefineds", Keys->Undefineds);
1049   }
1050 
1051   static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) {
1052     MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO,
1053                                                                        File);
1054     IO.mapTag("!tapi-tbd", true);
1055     IO.mapRequired("tbd-version", Keys->TBDVersion);
1056     IO.mapRequired("targets", Keys->Targets);
1057     IO.mapOptional("uuids", Keys->UUIDs);
1058     IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
1059     IO.mapRequired("install-name", Keys->InstallName);
1060     IO.mapOptional("current-version", Keys->CurrentVersion,
1061                    PackedVersion(1, 0, 0));
1062     IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,
1063                    PackedVersion(1, 0, 0));
1064     IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0));
1065     IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas);
1066     auto OptionKind = MetadataSection::Option::Clients;
1067     IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients,
1068                               OptionKind);
1069     OptionKind = MetadataSection::Option::Libraries;
1070     IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries,
1071                               OptionKind);
1072     IO.mapOptional("exports", Keys->Exports);
1073     IO.mapOptional("reexports", Keys->Reexports);
1074     IO.mapOptional("undefineds", Keys->Undefineds);
1075   }
1076 };
1077 
1078 template <>
1079 struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> {
1080   static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) {
1081     return Seq.size();
1082   }
1083   static const InterfaceFile *&
1084   element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) {
1085     if (Index >= Seq.size())
1086       Seq.resize(Index + 1);
1087     return Seq[Index];
1088   }
1089 };
1090 
1091 } // end namespace yaml.
1092 } // namespace llvm
1093 
1094 static void DiagHandler(const SMDiagnostic &Diag, void *Context) {
1095   auto *File = static_cast<TextAPIContext *>(Context);
1096   SmallString<1024> Message;
1097   raw_svector_ostream S(Message);
1098 
1099   SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path,
1100                        Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(),
1101                        Diag.getMessage(), Diag.getLineContents(),
1102                        Diag.getRanges(), Diag.getFixIts());
1103 
1104   NewDiag.print(nullptr, S);
1105   File->ErrorMessage = ("malformed file\n" + Message).str();
1106 }
1107 
1108 Expected<std::unique_ptr<InterfaceFile>>
1109 TextAPIReader::get(MemoryBufferRef InputBuffer) {
1110   TextAPIContext Ctx;
1111   Ctx.Path = std::string(InputBuffer.getBufferIdentifier());
1112   yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx);
1113 
1114   // Fill vector with interface file objects created by parsing the YAML file.
1115   std::vector<const InterfaceFile *> Files;
1116   YAMLIn >> Files;
1117 
1118   // YAMLIn dynamically allocates for Interface file and in case of error,
1119   // memory leak will occur unless wrapped around unique_ptr
1120   auto File = std::unique_ptr<InterfaceFile>(
1121       const_cast<InterfaceFile *>(Files.front()));
1122 
1123   for (const InterfaceFile *FI : llvm::drop_begin(Files))
1124     File->addDocument(
1125         std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI)));
1126 
1127   if (YAMLIn.error())
1128     return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error());
1129 
1130   return std::move(File);
1131 }
1132 
1133 Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File) {
1134   TextAPIContext Ctx;
1135   Ctx.Path = std::string(File.getPath());
1136   Ctx.FileKind = File.getFileType();
1137   llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80);
1138 
1139   std::vector<const InterfaceFile *> Files;
1140   Files.emplace_back(&File);
1141 
1142   for (auto Document : File.documents())
1143     Files.emplace_back(Document.get());
1144 
1145   // Stream out yaml.
1146   YAMLOut << Files;
1147 
1148   return Error::success();
1149 }
1150