xref: /freebsd/contrib/llvm-project/llvm/lib/TextAPI/TextStub.cpp (revision ec0ea6efa1ad229d75c394c1a9b9cac33af2b1d3)
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 PlatformKind::macOS:
384       OS << "macos";
385       break;
386     case PlatformKind::iOS:
387       OS << "ios";
388       break;
389     case PlatformKind::tvOS:
390       OS << "tvos";
391       break;
392     case PlatformKind::watchOS:
393       OS << "watchos";
394       break;
395     case PlatformKind::bridgeOS:
396       OS << "bridgeos";
397       break;
398     case PlatformKind::macCatalyst:
399       OS << "maccatalyst";
400       break;
401     case PlatformKind::iOSSimulator:
402       OS << "ios-simulator";
403       break;
404     case PlatformKind::tvOSSimulator:
405       OS << "tvos-simulator";
406       break;
407     case PlatformKind::watchOSSimulator:
408       OS << "watchos-simulator";
409       break;
410     case PlatformKind::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 == PlatformKind::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 = mapToPlatformKind(Platform, Architectures.hasX86());
601 
602         for (const auto &&Architecture : Architectures) {
603           if ((Architecture == AK_i386) &&
604               (Platform == PlatformKind::macCatalyst))
605             continue;
606 
607           Targets.emplace_back(Architecture, Platform);
608         }
609       }
610       return Targets;
611     }
612 
613     const InterfaceFile *denormalize(IO &IO) {
614       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
615       assert(Ctx);
616 
617       auto *File = new InterfaceFile;
618       File->setPath(Ctx->Path);
619       File->setFileType(Ctx->FileKind);
620       File->addTargets(synthesizeTargets(Architectures, Platforms));
621       for (auto &ID : UUIDs)
622         File->addUUID(ID.first, ID.second);
623       File->setInstallName(InstallName);
624       File->setCurrentVersion(CurrentVersion);
625       File->setCompatibilityVersion(CompatibilityVersion);
626       File->setSwiftABIVersion(SwiftABIVersion);
627       File->setObjCConstraint(ObjCConstraint);
628       for (const auto &Target : File->targets())
629         File->addParentUmbrella(Target, ParentUmbrella);
630 
631       if (Ctx->FileKind == FileType::TBD_V1) {
632         File->setTwoLevelNamespace();
633         File->setApplicationExtensionSafe();
634       } else {
635         File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
636         File->setApplicationExtensionSafe(
637             !(Flags & TBDFlags::NotApplicationExtensionSafe));
638         File->setInstallAPI(Flags & TBDFlags::InstallAPI);
639       }
640 
641       for (const auto &Section : Exports) {
642         const auto Targets =
643             synthesizeTargets(Section.Architectures, Platforms);
644 
645         for (const auto &Lib : Section.AllowableClients)
646           for (const auto &Target : Targets)
647             File->addAllowableClient(Lib, Target);
648 
649         for (const auto &Lib : Section.ReexportedLibraries)
650           for (const auto &Target : Targets)
651             File->addReexportedLibrary(Lib, Target);
652 
653         for (const auto &Symbol : Section.Symbols) {
654           if (Ctx->FileKind != FileType::TBD_V3 &&
655               Symbol.value.startswith("_OBJC_EHTYPE_$_"))
656             File->addSymbol(SymbolKind::ObjectiveCClassEHType,
657                             Symbol.value.drop_front(15), Targets);
658           else
659             File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets);
660         }
661         for (auto &Symbol : Section.Classes) {
662           auto Name = Symbol.value;
663           if (Ctx->FileKind != FileType::TBD_V3)
664             Name = Name.drop_front();
665           File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets);
666         }
667         for (auto &Symbol : Section.ClassEHs)
668           File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets);
669         for (auto &Symbol : Section.IVars) {
670           auto Name = Symbol.value;
671           if (Ctx->FileKind != FileType::TBD_V3)
672             Name = Name.drop_front();
673           File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name,
674                           Targets);
675         }
676         for (auto &Symbol : Section.WeakDefSymbols)
677           File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
678                           SymbolFlags::WeakDefined);
679         for (auto &Symbol : Section.TLVSymbols)
680           File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
681                           SymbolFlags::ThreadLocalValue);
682       }
683 
684       for (const auto &Section : Undefineds) {
685         const auto Targets =
686             synthesizeTargets(Section.Architectures, Platforms);
687         for (auto &Symbol : Section.Symbols) {
688           if (Ctx->FileKind != FileType::TBD_V3 &&
689               Symbol.value.startswith("_OBJC_EHTYPE_$_"))
690             File->addSymbol(SymbolKind::ObjectiveCClassEHType,
691                             Symbol.value.drop_front(15), Targets,
692                             SymbolFlags::Undefined);
693           else
694             File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
695                             SymbolFlags::Undefined);
696         }
697         for (auto &Symbol : Section.Classes) {
698           auto Name = Symbol.value;
699           if (Ctx->FileKind != FileType::TBD_V3)
700             Name = Name.drop_front();
701           File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets,
702                           SymbolFlags::Undefined);
703         }
704         for (auto &Symbol : Section.ClassEHs)
705           File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets,
706                           SymbolFlags::Undefined);
707         for (auto &Symbol : Section.IVars) {
708           auto Name = Symbol.value;
709           if (Ctx->FileKind != FileType::TBD_V3)
710             Name = Name.drop_front();
711           File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets,
712                           SymbolFlags::Undefined);
713         }
714         for (auto &Symbol : Section.WeakRefSymbols)
715           File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
716                           SymbolFlags::Undefined | SymbolFlags::WeakReferenced);
717       }
718 
719       return File;
720     }
721 
722     llvm::BumpPtrAllocator Allocator;
723     StringRef copyString(StringRef String) {
724       if (String.empty())
725         return {};
726 
727       void *Ptr = Allocator.Allocate(String.size(), 1);
728       memcpy(Ptr, String.data(), String.size());
729       return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
730     }
731 
732     std::vector<Architecture> Architectures;
733     std::vector<UUID> UUIDs;
734     PlatformSet Platforms;
735     StringRef InstallName;
736     PackedVersion CurrentVersion;
737     PackedVersion CompatibilityVersion;
738     SwiftVersion SwiftABIVersion{0};
739     ObjCConstraintType ObjCConstraint{ObjCConstraintType::None};
740     TBDFlags Flags{TBDFlags::None};
741     StringRef ParentUmbrella;
742     std::vector<ExportSection> Exports;
743     std::vector<UndefinedSection> Undefineds;
744   };
745 
746   static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) {
747     if (IO.mapTag("!tapi-tbd", false))
748       Ctx->FileKind = FileType::TBD_V4;
749     else if (IO.mapTag("!tapi-tbd-v3", false))
750       Ctx->FileKind = FileType::TBD_V3;
751     else if (IO.mapTag("!tapi-tbd-v2", false))
752       Ctx->FileKind = FileType::TBD_V2;
753     else if (IO.mapTag("!tapi-tbd-v1", false) ||
754              IO.mapTag("tag:yaml.org,2002:map", false))
755       Ctx->FileKind = FileType::TBD_V1;
756     else {
757       Ctx->FileKind = FileType::Invalid;
758       return;
759     }
760   }
761 
762   static void mapping(IO &IO, const InterfaceFile *&File) {
763     auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
764     assert((!Ctx || !IO.outputting() ||
765             (Ctx && Ctx->FileKind != FileType::Invalid)) &&
766            "File type is not set in YAML context");
767 
768     if (!IO.outputting()) {
769       setFileTypeForInput(Ctx, IO);
770       switch (Ctx->FileKind) {
771       default:
772         break;
773       case FileType::TBD_V4:
774         mapKeysToValuesV4(IO, File);
775         return;
776       case FileType::Invalid:
777         IO.setError("unsupported file type");
778         return;
779       }
780     } else {
781       // Set file type when writing.
782       switch (Ctx->FileKind) {
783       default:
784         llvm_unreachable("unexpected file type");
785       case FileType::TBD_V4:
786         mapKeysToValuesV4(IO, File);
787         return;
788       case FileType::TBD_V3:
789         IO.mapTag("!tapi-tbd-v3", true);
790         break;
791       case FileType::TBD_V2:
792         IO.mapTag("!tapi-tbd-v2", true);
793         break;
794       case FileType::TBD_V1:
795         // Don't write the tag into the .tbd file for TBD v1
796         break;
797       }
798     }
799     mapKeysToValues(Ctx->FileKind, IO, File);
800   }
801 
802   using SectionList = std::vector<SymbolSection>;
803   struct NormalizedTBD_V4 {
804     explicit NormalizedTBD_V4(IO &IO) {}
805     NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) {
806       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
807       assert(Ctx);
808       TBDVersion = Ctx->FileKind >> 1;
809       Targets.insert(Targets.begin(), File->targets().begin(),
810                      File->targets().end());
811       for (const auto &IT : File->uuids())
812         UUIDs.emplace_back(IT.first, IT.second);
813       InstallName = File->getInstallName();
814       CurrentVersion = File->getCurrentVersion();
815       CompatibilityVersion = File->getCompatibilityVersion();
816       SwiftABIVersion = File->getSwiftABIVersion();
817 
818       Flags = TBDFlags::None;
819       if (!File->isApplicationExtensionSafe())
820         Flags |= TBDFlags::NotApplicationExtensionSafe;
821 
822       if (!File->isTwoLevelNamespace())
823         Flags |= TBDFlags::FlatNamespace;
824 
825       if (File->isInstallAPI())
826         Flags |= TBDFlags::InstallAPI;
827 
828       {
829         std::map<std::string, TargetList> valueToTargetList;
830         for (const auto &it : File->umbrellas())
831           valueToTargetList[it.second].emplace_back(it.first);
832 
833         for (const auto &it : valueToTargetList) {
834           UmbrellaSection CurrentSection;
835           CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
836                                         it.second.begin(), it.second.end());
837           CurrentSection.Umbrella = it.first;
838           ParentUmbrellas.emplace_back(std::move(CurrentSection));
839         }
840       }
841 
842       assignTargetsToLibrary(File->allowableClients(), AllowableClients);
843       assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries);
844 
845       auto handleSymbols =
846           [](SectionList &CurrentSections,
847              InterfaceFile::const_filtered_symbol_range Symbols,
848              std::function<bool(const Symbol *)> Pred) {
849             std::set<TargetList> TargetSet;
850             std::map<const Symbol *, TargetList> SymbolToTargetList;
851             for (const auto *Symbol : Symbols) {
852               if (!Pred(Symbol))
853                 continue;
854               TargetList Targets(Symbol->targets());
855               SymbolToTargetList[Symbol] = Targets;
856               TargetSet.emplace(std::move(Targets));
857             }
858             for (const auto &TargetIDs : TargetSet) {
859               SymbolSection CurrentSection;
860               CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
861                                             TargetIDs.begin(), TargetIDs.end());
862 
863               for (const auto &IT : SymbolToTargetList) {
864                 if (IT.second != TargetIDs)
865                   continue;
866 
867                 const auto *Symbol = IT.first;
868                 switch (Symbol->getKind()) {
869                 case SymbolKind::GlobalSymbol:
870                   if (Symbol->isWeakDefined())
871                     CurrentSection.WeakSymbols.emplace_back(Symbol->getName());
872                   else if (Symbol->isThreadLocalValue())
873                     CurrentSection.TlvSymbols.emplace_back(Symbol->getName());
874                   else
875                     CurrentSection.Symbols.emplace_back(Symbol->getName());
876                   break;
877                 case SymbolKind::ObjectiveCClass:
878                   CurrentSection.Classes.emplace_back(Symbol->getName());
879                   break;
880                 case SymbolKind::ObjectiveCClassEHType:
881                   CurrentSection.ClassEHs.emplace_back(Symbol->getName());
882                   break;
883                 case SymbolKind::ObjectiveCInstanceVariable:
884                   CurrentSection.Ivars.emplace_back(Symbol->getName());
885                   break;
886                 }
887               }
888               sort(CurrentSection.Symbols);
889               sort(CurrentSection.Classes);
890               sort(CurrentSection.ClassEHs);
891               sort(CurrentSection.Ivars);
892               sort(CurrentSection.WeakSymbols);
893               sort(CurrentSection.TlvSymbols);
894               CurrentSections.emplace_back(std::move(CurrentSection));
895             }
896           };
897 
898       handleSymbols(Exports, File->exports(), [](const Symbol *Symbol) {
899         return !Symbol->isReexported();
900       });
901       handleSymbols(Reexports, File->exports(), [](const Symbol *Symbol) {
902         return Symbol->isReexported();
903       });
904       handleSymbols(Undefineds, File->undefineds(),
905                     [](const Symbol *Symbol) { return true; });
906     }
907 
908     const InterfaceFile *denormalize(IO &IO) {
909       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
910       assert(Ctx);
911 
912       auto *File = new InterfaceFile;
913       File->setPath(Ctx->Path);
914       File->setFileType(Ctx->FileKind);
915       for (auto &id : UUIDs)
916         File->addUUID(id.TargetID, id.Value);
917       File->addTargets(Targets);
918       File->setInstallName(InstallName);
919       File->setCurrentVersion(CurrentVersion);
920       File->setCompatibilityVersion(CompatibilityVersion);
921       File->setSwiftABIVersion(SwiftABIVersion);
922       for (const auto &CurrentSection : ParentUmbrellas)
923         for (const auto &target : CurrentSection.Targets)
924           File->addParentUmbrella(target, CurrentSection.Umbrella);
925       File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
926       File->setApplicationExtensionSafe(
927           !(Flags & TBDFlags::NotApplicationExtensionSafe));
928       File->setInstallAPI(Flags & TBDFlags::InstallAPI);
929 
930       for (const auto &CurrentSection : AllowableClients) {
931         for (const auto &lib : CurrentSection.Values)
932           for (const auto &Target : CurrentSection.Targets)
933             File->addAllowableClient(lib, Target);
934       }
935 
936       for (const auto &CurrentSection : ReexportedLibraries) {
937         for (const auto &Lib : CurrentSection.Values)
938           for (const auto &Target : CurrentSection.Targets)
939             File->addReexportedLibrary(Lib, Target);
940       }
941 
942       auto handleSymbols = [File](const SectionList &CurrentSections,
943                                   SymbolFlags Flag = SymbolFlags::None) {
944         for (const auto &CurrentSection : CurrentSections) {
945           for (auto &sym : CurrentSection.Symbols)
946             File->addSymbol(SymbolKind::GlobalSymbol, sym,
947                             CurrentSection.Targets, Flag);
948 
949           for (auto &sym : CurrentSection.Classes)
950             File->addSymbol(SymbolKind::ObjectiveCClass, sym,
951                             CurrentSection.Targets);
952 
953           for (auto &sym : CurrentSection.ClassEHs)
954             File->addSymbol(SymbolKind::ObjectiveCClassEHType, sym,
955                             CurrentSection.Targets);
956 
957           for (auto &sym : CurrentSection.Ivars)
958             File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, sym,
959                             CurrentSection.Targets);
960 
961           for (auto &sym : CurrentSection.WeakSymbols)
962             File->addSymbol(SymbolKind::GlobalSymbol, sym,
963                             CurrentSection.Targets, SymbolFlags::WeakDefined);
964 
965           for (auto &sym : CurrentSection.TlvSymbols)
966             File->addSymbol(SymbolKind::GlobalSymbol, sym,
967                             CurrentSection.Targets,
968                             SymbolFlags::ThreadLocalValue);
969         }
970       };
971 
972       handleSymbols(Exports);
973       handleSymbols(Reexports, SymbolFlags::Rexported);
974       handleSymbols(Undefineds, SymbolFlags::Undefined);
975 
976       return File;
977     }
978 
979     unsigned TBDVersion;
980     std::vector<UUIDv4> UUIDs;
981     TargetList Targets;
982     StringRef InstallName;
983     PackedVersion CurrentVersion;
984     PackedVersion CompatibilityVersion;
985     SwiftVersion SwiftABIVersion{0};
986     std::vector<MetadataSection> AllowableClients;
987     std::vector<MetadataSection> ReexportedLibraries;
988     TBDFlags Flags{TBDFlags::None};
989     std::vector<UmbrellaSection> ParentUmbrellas;
990     SectionList Exports;
991     SectionList Reexports;
992     SectionList Undefineds;
993 
994   private:
995     void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries,
996                                 std::vector<MetadataSection> &Section) {
997       std::set<TargetList> targetSet;
998       std::map<const InterfaceFileRef *, TargetList> valueToTargetList;
999       for (const auto &library : Libraries) {
1000         TargetList targets(library.targets());
1001         valueToTargetList[&library] = targets;
1002         targetSet.emplace(std::move(targets));
1003       }
1004 
1005       for (const auto &targets : targetSet) {
1006         MetadataSection CurrentSection;
1007         CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
1008                                       targets.begin(), targets.end());
1009 
1010         for (const auto &it : valueToTargetList) {
1011           if (it.second != targets)
1012             continue;
1013 
1014           CurrentSection.Values.emplace_back(it.first->getInstallName());
1015         }
1016         llvm::sort(CurrentSection.Values);
1017         Section.emplace_back(std::move(CurrentSection));
1018       }
1019     }
1020   };
1021 
1022   static void mapKeysToValues(FileType FileKind, IO &IO,
1023                               const InterfaceFile *&File) {
1024     MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File);
1025     IO.mapRequired("archs", Keys->Architectures);
1026     if (FileKind != FileType::TBD_V1)
1027       IO.mapOptional("uuids", Keys->UUIDs);
1028     IO.mapRequired("platform", Keys->Platforms);
1029     if (FileKind != FileType::TBD_V1)
1030       IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
1031     IO.mapRequired("install-name", Keys->InstallName);
1032     IO.mapOptional("current-version", Keys->CurrentVersion,
1033                    PackedVersion(1, 0, 0));
1034     IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,
1035                    PackedVersion(1, 0, 0));
1036     if (FileKind != FileType::TBD_V3)
1037       IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0));
1038     else
1039       IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion,
1040                      SwiftVersion(0));
1041     IO.mapOptional("objc-constraint", Keys->ObjCConstraint,
1042                    (FileKind == FileType::TBD_V1)
1043                        ? ObjCConstraintType::None
1044                        : ObjCConstraintType::Retain_Release);
1045     if (FileKind != FileType::TBD_V1)
1046       IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef());
1047     IO.mapOptional("exports", Keys->Exports);
1048     if (FileKind != FileType::TBD_V1)
1049       IO.mapOptional("undefineds", Keys->Undefineds);
1050   }
1051 
1052   static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) {
1053     MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO,
1054                                                                        File);
1055     IO.mapTag("!tapi-tbd", true);
1056     IO.mapRequired("tbd-version", Keys->TBDVersion);
1057     IO.mapRequired("targets", Keys->Targets);
1058     IO.mapOptional("uuids", Keys->UUIDs);
1059     IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
1060     IO.mapRequired("install-name", Keys->InstallName);
1061     IO.mapOptional("current-version", Keys->CurrentVersion,
1062                    PackedVersion(1, 0, 0));
1063     IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,
1064                    PackedVersion(1, 0, 0));
1065     IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0));
1066     IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas);
1067     auto OptionKind = MetadataSection::Option::Clients;
1068     IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients,
1069                               OptionKind);
1070     OptionKind = MetadataSection::Option::Libraries;
1071     IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries,
1072                               OptionKind);
1073     IO.mapOptional("exports", Keys->Exports);
1074     IO.mapOptional("reexports", Keys->Reexports);
1075     IO.mapOptional("undefineds", Keys->Undefineds);
1076   }
1077 };
1078 
1079 template <>
1080 struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> {
1081   static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) {
1082     return Seq.size();
1083   }
1084   static const InterfaceFile *&
1085   element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) {
1086     if (Index >= Seq.size())
1087       Seq.resize(Index + 1);
1088     return Seq[Index];
1089   }
1090 };
1091 
1092 } // end namespace yaml.
1093 } // namespace llvm
1094 
1095 static void DiagHandler(const SMDiagnostic &Diag, void *Context) {
1096   auto *File = static_cast<TextAPIContext *>(Context);
1097   SmallString<1024> Message;
1098   raw_svector_ostream S(Message);
1099 
1100   SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path,
1101                        Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(),
1102                        Diag.getMessage(), Diag.getLineContents(),
1103                        Diag.getRanges(), Diag.getFixIts());
1104 
1105   NewDiag.print(nullptr, S);
1106   File->ErrorMessage = ("malformed file\n" + Message).str();
1107 }
1108 
1109 Expected<std::unique_ptr<InterfaceFile>>
1110 TextAPIReader::get(MemoryBufferRef InputBuffer) {
1111   TextAPIContext Ctx;
1112   Ctx.Path = std::string(InputBuffer.getBufferIdentifier());
1113   yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx);
1114 
1115   // Fill vector with interface file objects created by parsing the YAML file.
1116   std::vector<const InterfaceFile *> Files;
1117   YAMLIn >> Files;
1118 
1119   // YAMLIn dynamically allocates for Interface file and in case of error,
1120   // memory leak will occur unless wrapped around unique_ptr
1121   auto File = std::unique_ptr<InterfaceFile>(
1122       const_cast<InterfaceFile *>(Files.front()));
1123 
1124   for (auto Iter = std::next(Files.begin()); Iter != Files.end(); ++Iter)
1125     File->addDocument(
1126         std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(*Iter)));
1127 
1128   if (YAMLIn.error())
1129     return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error());
1130 
1131   return std::move(File);
1132 }
1133 
1134 Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File) {
1135   TextAPIContext Ctx;
1136   Ctx.Path = std::string(File.getPath());
1137   Ctx.FileKind = File.getFileType();
1138   llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80);
1139 
1140   std::vector<const InterfaceFile *> Files;
1141   Files.emplace_back(&File);
1142 
1143   for (auto Document : File.documents())
1144     Files.emplace_back(Document.get());
1145 
1146   // Stream out yaml.
1147   YAMLOut << Files;
1148 
1149   return Error::success();
1150 }
1151