xref: /freebsd/contrib/llvm-project/llvm/lib/TextAPI/TextStub.cpp (revision 942e52f776e6bbe016a3e920c96a1cd4dbddf7e3)
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