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