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