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/MachO/Architecture.h"
23 #include "llvm/TextAPI/MachO/ArchitectureSet.h"
24 #include "llvm/TextAPI/MachO/InterfaceFile.h"
25 #include "llvm/TextAPI/MachO/PackedVersion.h"
26 #include "llvm/TextAPI/MachO/TextAPIReader.h"
27 #include "llvm/TextAPI/MachO/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 // clang-format on
151 
152 using namespace llvm;
153 using namespace llvm::yaml;
154 using namespace llvm::MachO;
155 
156 namespace {
157 struct ExportSection {
158   std::vector<Architecture> Architectures;
159   std::vector<FlowStringRef> AllowableClients;
160   std::vector<FlowStringRef> ReexportedLibraries;
161   std::vector<FlowStringRef> Symbols;
162   std::vector<FlowStringRef> Classes;
163   std::vector<FlowStringRef> ClassEHs;
164   std::vector<FlowStringRef> IVars;
165   std::vector<FlowStringRef> WeakDefSymbols;
166   std::vector<FlowStringRef> TLVSymbols;
167 };
168 
169 struct UndefinedSection {
170   std::vector<Architecture> Architectures;
171   std::vector<FlowStringRef> Symbols;
172   std::vector<FlowStringRef> Classes;
173   std::vector<FlowStringRef> ClassEHs;
174   std::vector<FlowStringRef> IVars;
175   std::vector<FlowStringRef> WeakRefSymbols;
176 };
177 
178 // clang-format off
179 enum TBDFlags : unsigned {
180   None                         = 0U,
181   FlatNamespace                = 1U << 0,
182   NotApplicationExtensionSafe  = 1U << 1,
183   InstallAPI                   = 1U << 2,
184   LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/InstallAPI),
185 };
186 // clang-format on
187 } // end anonymous namespace.
188 
189 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture)
190 LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection)
191 LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection)
192 
193 namespace llvm {
194 namespace yaml {
195 
196 template <> struct MappingTraits<ExportSection> {
mappingllvm::yaml::MappingTraits197   static void mapping(IO &IO, ExportSection &Section) {
198     const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
199     assert((!Ctx || (Ctx && Ctx->FileKind != FileType::Invalid)) &&
200            "File type is not set in YAML context");
201 
202     IO.mapRequired("archs", Section.Architectures);
203     if (Ctx->FileKind == FileType::TBD_V1)
204       IO.mapOptional("allowed-clients", Section.AllowableClients);
205     else
206       IO.mapOptional("allowable-clients", Section.AllowableClients);
207     IO.mapOptional("re-exports", Section.ReexportedLibraries);
208     IO.mapOptional("symbols", Section.Symbols);
209     IO.mapOptional("objc-classes", Section.Classes);
210     if (Ctx->FileKind == FileType::TBD_V3)
211       IO.mapOptional("objc-eh-types", Section.ClassEHs);
212     IO.mapOptional("objc-ivars", Section.IVars);
213     IO.mapOptional("weak-def-symbols", Section.WeakDefSymbols);
214     IO.mapOptional("thread-local-symbols", Section.TLVSymbols);
215   }
216 };
217 
218 template <> struct MappingTraits<UndefinedSection> {
mappingllvm::yaml::MappingTraits219   static void mapping(IO &IO, UndefinedSection &Section) {
220     const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
221     assert((!Ctx || (Ctx && Ctx->FileKind != FileType::Invalid)) &&
222            "File type is not set in YAML context");
223 
224     IO.mapRequired("archs", Section.Architectures);
225     IO.mapOptional("symbols", Section.Symbols);
226     IO.mapOptional("objc-classes", Section.Classes);
227     if (Ctx->FileKind == FileType::TBD_V3)
228       IO.mapOptional("objc-eh-types", Section.ClassEHs);
229     IO.mapOptional("objc-ivars", Section.IVars);
230     IO.mapOptional("weak-ref-symbols", Section.WeakRefSymbols);
231   }
232 };
233 
234 template <> struct ScalarBitSetTraits<TBDFlags> {
bitsetllvm::yaml::ScalarBitSetTraits235   static void bitset(IO &IO, TBDFlags &Flags) {
236     IO.bitSetCase(Flags, "flat_namespace", TBDFlags::FlatNamespace);
237     IO.bitSetCase(Flags, "not_app_extension_safe",
238                   TBDFlags::NotApplicationExtensionSafe);
239     IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI);
240   }
241 };
242 
243 template <> struct MappingTraits<const InterfaceFile *> {
244   struct NormalizedTBD {
NormalizedTBDllvm::yaml::MappingTraits::NormalizedTBD245     explicit NormalizedTBD(IO &IO) {}
NormalizedTBDllvm::yaml::MappingTraits::NormalizedTBD246     NormalizedTBD(IO &IO, const InterfaceFile *&File) {
247       Architectures = File->getArchitectures();
248       UUIDs = File->uuids();
249       Platform = File->getPlatform();
250       InstallName = File->getInstallName();
251       CurrentVersion = PackedVersion(File->getCurrentVersion());
252       CompatibilityVersion = PackedVersion(File->getCompatibilityVersion());
253       SwiftABIVersion = File->getSwiftABIVersion();
254       ObjCConstraint = File->getObjCConstraint();
255 
256       Flags = TBDFlags::None;
257       if (!File->isApplicationExtensionSafe())
258         Flags |= TBDFlags::NotApplicationExtensionSafe;
259 
260       if (!File->isTwoLevelNamespace())
261         Flags |= TBDFlags::FlatNamespace;
262 
263       if (File->isInstallAPI())
264         Flags |= TBDFlags::InstallAPI;
265 
266       ParentUmbrella = File->getParentUmbrella();
267 
268       std::set<ArchitectureSet> ArchSet;
269       for (const auto &Library : File->allowableClients())
270         ArchSet.insert(Library.getArchitectures());
271 
272       for (const auto &Library : File->reexportedLibraries())
273         ArchSet.insert(Library.getArchitectures());
274 
275       std::map<const Symbol *, ArchitectureSet> SymbolToArchSet;
276       for (const auto *Symbol : File->exports()) {
277         auto Architectures = Symbol->getArchitectures();
278         SymbolToArchSet[Symbol] = Architectures;
279         ArchSet.insert(Architectures);
280       }
281 
282       for (auto Architectures : ArchSet) {
283         ExportSection Section;
284         Section.Architectures = Architectures;
285 
286         for (const auto &Library : File->allowableClients())
287           if (Library.getArchitectures() == Architectures)
288             Section.AllowableClients.emplace_back(Library.getInstallName());
289 
290         for (const auto &Library : File->reexportedLibraries())
291           if (Library.getArchitectures() == Architectures)
292             Section.ReexportedLibraries.emplace_back(Library.getInstallName());
293 
294         for (const auto &SymArch : SymbolToArchSet) {
295           if (SymArch.second != Architectures)
296             continue;
297 
298           const auto *Symbol = SymArch.first;
299           switch (Symbol->getKind()) {
300           case SymbolKind::GlobalSymbol:
301             if (Symbol->isWeakDefined())
302               Section.WeakDefSymbols.emplace_back(Symbol->getName());
303             else if (Symbol->isThreadLocalValue())
304               Section.TLVSymbols.emplace_back(Symbol->getName());
305             else
306               Section.Symbols.emplace_back(Symbol->getName());
307             break;
308           case SymbolKind::ObjectiveCClass:
309             if (File->getFileType() != FileType::TBD_V3)
310               Section.Classes.emplace_back(
311                   copyString("_" + Symbol->getName().str()));
312             else
313               Section.Classes.emplace_back(Symbol->getName());
314             break;
315           case SymbolKind::ObjectiveCClassEHType:
316             if (File->getFileType() != FileType::TBD_V3)
317               Section.Symbols.emplace_back(
318                   copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));
319             else
320               Section.ClassEHs.emplace_back(Symbol->getName());
321             break;
322           case SymbolKind::ObjectiveCInstanceVariable:
323             if (File->getFileType() != FileType::TBD_V3)
324               Section.IVars.emplace_back(
325                   copyString("_" + Symbol->getName().str()));
326             else
327               Section.IVars.emplace_back(Symbol->getName());
328             break;
329           }
330         }
331         llvm::sort(Section.Symbols.begin(), Section.Symbols.end());
332         llvm::sort(Section.Classes.begin(), Section.Classes.end());
333         llvm::sort(Section.ClassEHs.begin(), Section.ClassEHs.end());
334         llvm::sort(Section.IVars.begin(), Section.IVars.end());
335         llvm::sort(Section.WeakDefSymbols.begin(),
336                    Section.WeakDefSymbols.end());
337         llvm::sort(Section.TLVSymbols.begin(), Section.TLVSymbols.end());
338         Exports.emplace_back(std::move(Section));
339       }
340 
341       ArchSet.clear();
342       SymbolToArchSet.clear();
343 
344       for (const auto *Symbol : File->undefineds()) {
345         auto Architectures = Symbol->getArchitectures();
346         SymbolToArchSet[Symbol] = Architectures;
347         ArchSet.insert(Architectures);
348       }
349 
350       for (auto Architectures : ArchSet) {
351         UndefinedSection Section;
352         Section.Architectures = Architectures;
353 
354         for (const auto &SymArch : SymbolToArchSet) {
355           if (SymArch.second != Architectures)
356             continue;
357 
358           const auto *Symbol = SymArch.first;
359           switch (Symbol->getKind()) {
360           case SymbolKind::GlobalSymbol:
361             if (Symbol->isWeakReferenced())
362               Section.WeakRefSymbols.emplace_back(Symbol->getName());
363             else
364               Section.Symbols.emplace_back(Symbol->getName());
365             break;
366           case SymbolKind::ObjectiveCClass:
367             if (File->getFileType() != FileType::TBD_V3)
368               Section.Classes.emplace_back(
369                   copyString("_" + Symbol->getName().str()));
370             else
371               Section.Classes.emplace_back(Symbol->getName());
372             break;
373           case SymbolKind::ObjectiveCClassEHType:
374             if (File->getFileType() != FileType::TBD_V3)
375               Section.Symbols.emplace_back(
376                   copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));
377             else
378               Section.ClassEHs.emplace_back(Symbol->getName());
379             break;
380           case SymbolKind::ObjectiveCInstanceVariable:
381             if (File->getFileType() != FileType::TBD_V3)
382               Section.IVars.emplace_back(
383                   copyString("_" + Symbol->getName().str()));
384             else
385               Section.IVars.emplace_back(Symbol->getName());
386             break;
387           }
388         }
389         llvm::sort(Section.Symbols.begin(), Section.Symbols.end());
390         llvm::sort(Section.Classes.begin(), Section.Classes.end());
391         llvm::sort(Section.ClassEHs.begin(), Section.ClassEHs.end());
392         llvm::sort(Section.IVars.begin(), Section.IVars.end());
393         llvm::sort(Section.WeakRefSymbols.begin(),
394                    Section.WeakRefSymbols.end());
395         Undefineds.emplace_back(std::move(Section));
396       }
397     }
398 
denormalizellvm::yaml::MappingTraits::NormalizedTBD399     const InterfaceFile *denormalize(IO &IO) {
400       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
401       assert(Ctx);
402 
403       auto *File = new InterfaceFile;
404       File->setPath(Ctx->Path);
405       File->setFileType(Ctx->FileKind);
406       for (auto &ID : UUIDs)
407         File->addUUID(ID.first, ID.second);
408       File->setPlatform(Platform);
409       File->setArchitectures(Architectures);
410       File->setInstallName(InstallName);
411       File->setCurrentVersion(CurrentVersion);
412       File->setCompatibilityVersion(CompatibilityVersion);
413       File->setSwiftABIVersion(SwiftABIVersion);
414       File->setObjCConstraint(ObjCConstraint);
415       File->setParentUmbrella(ParentUmbrella);
416 
417       if (Ctx->FileKind == FileType::TBD_V1) {
418         File->setTwoLevelNamespace();
419         File->setApplicationExtensionSafe();
420       } else {
421         File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
422         File->setApplicationExtensionSafe(
423             !(Flags & TBDFlags::NotApplicationExtensionSafe));
424         File->setInstallAPI(Flags & TBDFlags::InstallAPI);
425       }
426 
427       for (const auto &Section : Exports) {
428         for (const auto &Library : Section.AllowableClients)
429           File->addAllowableClient(Library, Section.Architectures);
430         for (const auto &Library : Section.ReexportedLibraries)
431           File->addReexportedLibrary(Library, Section.Architectures);
432 
433         for (const auto &Symbol : Section.Symbols) {
434           if (Ctx->FileKind != FileType::TBD_V3 &&
435               Symbol.value.startswith("_OBJC_EHTYPE_$_"))
436             File->addSymbol(SymbolKind::ObjectiveCClassEHType,
437                             Symbol.value.drop_front(15), Section.Architectures);
438           else
439             File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
440                             Section.Architectures);
441         }
442         for (auto &Symbol : Section.Classes) {
443           auto Name = Symbol.value;
444           if (Ctx->FileKind != FileType::TBD_V3)
445             Name = Name.drop_front();
446           File->addSymbol(SymbolKind::ObjectiveCClass, Name,
447                           Section.Architectures);
448         }
449         for (auto &Symbol : Section.ClassEHs)
450           File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol,
451                           Section.Architectures);
452         for (auto &Symbol : Section.IVars) {
453           auto Name = Symbol.value;
454           if (Ctx->FileKind != FileType::TBD_V3)
455             Name = Name.drop_front();
456           File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name,
457                           Section.Architectures);
458         }
459         for (auto &Symbol : Section.WeakDefSymbols)
460           File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
461                           Section.Architectures, SymbolFlags::WeakDefined);
462         for (auto &Symbol : Section.TLVSymbols)
463           File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
464                           Section.Architectures, SymbolFlags::ThreadLocalValue);
465       }
466 
467       for (const auto &Section : Undefineds) {
468         for (auto &Symbol : Section.Symbols) {
469           if (Ctx->FileKind != FileType::TBD_V3 &&
470               Symbol.value.startswith("_OBJC_EHTYPE_$_"))
471             File->addSymbol(SymbolKind::ObjectiveCClassEHType,
472                             Symbol.value.drop_front(15), Section.Architectures,
473                             SymbolFlags::Undefined);
474           else
475             File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
476                             Section.Architectures, SymbolFlags::Undefined);
477         }
478         for (auto &Symbol : Section.Classes) {
479           auto Name = Symbol.value;
480           if (Ctx->FileKind != FileType::TBD_V3)
481             Name = Name.drop_front();
482           File->addSymbol(SymbolKind::ObjectiveCClass, Name,
483                           Section.Architectures, SymbolFlags::Undefined);
484         }
485         for (auto &Symbol : Section.ClassEHs)
486           File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol,
487                           Section.Architectures, SymbolFlags::Undefined);
488         for (auto &Symbol : Section.IVars) {
489           auto Name = Symbol.value;
490           if (Ctx->FileKind != FileType::TBD_V3)
491             Name = Name.drop_front();
492           File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name,
493                           Section.Architectures, SymbolFlags::Undefined);
494         }
495         for (auto &Symbol : Section.WeakRefSymbols)
496           File->addSymbol(SymbolKind::GlobalSymbol, Symbol,
497                           Section.Architectures,
498                           SymbolFlags::Undefined | SymbolFlags::WeakReferenced);
499       }
500 
501       return File;
502     }
503 
504     llvm::BumpPtrAllocator Allocator;
copyStringllvm::yaml::MappingTraits::NormalizedTBD505     StringRef copyString(StringRef String) {
506       if (String.empty())
507         return {};
508 
509       void *Ptr = Allocator.Allocate(String.size(), 1);
510       memcpy(Ptr, String.data(), String.size());
511       return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
512     }
513 
514     std::vector<Architecture> Architectures;
515     std::vector<UUID> UUIDs;
516     PlatformKind Platform{PlatformKind::unknown};
517     StringRef InstallName;
518     PackedVersion CurrentVersion;
519     PackedVersion CompatibilityVersion;
520     SwiftVersion SwiftABIVersion{0};
521     ObjCConstraintType ObjCConstraint{ObjCConstraintType::None};
522     TBDFlags Flags{TBDFlags::None};
523     StringRef ParentUmbrella;
524     std::vector<ExportSection> Exports;
525     std::vector<UndefinedSection> Undefineds;
526   };
527 
mappingllvm::yaml::MappingTraits528   static void mapping(IO &IO, const InterfaceFile *&File) {
529     auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
530     assert((!Ctx || !IO.outputting() ||
531             (Ctx && Ctx->FileKind != FileType::Invalid)) &&
532            "File type is not set in YAML context");
533     MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File);
534 
535     // prope file type when reading.
536     if (!IO.outputting()) {
537       if (IO.mapTag("!tapi-tbd-v2", false))
538         Ctx->FileKind = FileType::TBD_V2;
539       else if (IO.mapTag("!tapi-tbd-v3", false))
540         Ctx->FileKind = FileType::TBD_V2;
541       else if (IO.mapTag("!tapi-tbd-v1", false) ||
542                IO.mapTag("tag:yaml.org,2002:map", false))
543         Ctx->FileKind = FileType::TBD_V1;
544       else {
545         IO.setError("unsupported file type");
546         return;
547       }
548     }
549 
550     // Set file tyoe when writing.
551     if (IO.outputting()) {
552       switch (Ctx->FileKind) {
553       default:
554         llvm_unreachable("unexpected file type");
555       case FileType::TBD_V1:
556         // Don't write the tag into the .tbd file for TBD v1.
557         break;
558       case FileType::TBD_V2:
559         IO.mapTag("!tapi-tbd-v2", true);
560         break;
561       case FileType::TBD_V3:
562         IO.mapTag("!tapi-tbd-v3", true);
563         break;
564       }
565     }
566 
567     IO.mapRequired("archs", Keys->Architectures);
568     if (Ctx->FileKind != FileType::TBD_V1)
569       IO.mapOptional("uuids", Keys->UUIDs);
570     IO.mapRequired("platform", Keys->Platform);
571     if (Ctx->FileKind != FileType::TBD_V1)
572       IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
573     IO.mapRequired("install-name", Keys->InstallName);
574     IO.mapOptional("current-version", Keys->CurrentVersion,
575                    PackedVersion(1, 0, 0));
576     IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,
577                    PackedVersion(1, 0, 0));
578     if (Ctx->FileKind != FileType::TBD_V3)
579       IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0));
580     else
581       IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion,
582                      SwiftVersion(0));
583     IO.mapOptional("objc-constraint", Keys->ObjCConstraint,
584                    (Ctx->FileKind == FileType::TBD_V1)
585                        ? ObjCConstraintType::None
586                        : ObjCConstraintType::Retain_Release);
587     if (Ctx->FileKind != FileType::TBD_V1)
588       IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef());
589     IO.mapOptional("exports", Keys->Exports);
590     if (Ctx->FileKind != FileType::TBD_V1)
591       IO.mapOptional("undefineds", Keys->Undefineds);
592   }
593 };
594 
595 template <>
596 struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> {
sizellvm::yaml::DocumentListTraits597   static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) {
598     return Seq.size();
599   }
600   static const InterfaceFile *&
elementllvm::yaml::DocumentListTraits601   element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) {
602     if (Index >= Seq.size())
603       Seq.resize(Index + 1);
604     return Seq[Index];
605   }
606 };
607 
608 } // end namespace yaml.
609 
610 namespace MachO {
DiagHandler(const SMDiagnostic & Diag,void * Context)611 static void DiagHandler(const SMDiagnostic &Diag, void *Context) {
612   auto *File = static_cast<TextAPIContext *>(Context);
613   SmallString<1024> Message;
614   raw_svector_ostream S(Message);
615 
616   SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path,
617                        Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(),
618                        Diag.getMessage(), Diag.getLineContents(),
619                        Diag.getRanges(), Diag.getFixIts());
620 
621   NewDiag.print(nullptr, S);
622   File->ErrorMessage = ("malformed file\n" + Message).str();
623 }
624 
625 Expected<std::unique_ptr<InterfaceFile>>
get(std::unique_ptr<MemoryBuffer> InputBuffer)626 TextAPIReader::get(std::unique_ptr<MemoryBuffer> InputBuffer) {
627   TextAPIContext Ctx;
628   Ctx.Path = InputBuffer->getBufferIdentifier();
629   yaml::Input YAMLIn(InputBuffer->getBuffer(), &Ctx, DiagHandler, &Ctx);
630 
631   // Fill vector with interface file objects created by parsing the YAML file.
632   std::vector<const InterfaceFile *> Files;
633   YAMLIn >> Files;
634 
635   auto File = std::unique_ptr<InterfaceFile>(
636       const_cast<InterfaceFile *>(Files.front()));
637 
638   if (YAMLIn.error())
639     return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error());
640 
641   return std::move(File);
642 }
643 
writeToStream(raw_ostream & OS,const InterfaceFile & File)644 Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File) {
645   TextAPIContext Ctx;
646   Ctx.Path = File.getPath();
647   Ctx.FileKind = File.getFileType();
648   llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80);
649 
650   std::vector<const InterfaceFile *> Files;
651   Files.emplace_back(&File);
652 
653   // Stream out yaml.
654   YAMLOut << Files;
655 
656   return Error::success();
657 }
658 
659 } // end namespace MachO.
660 } // end namespace llvm.
661