xref: /freebsd/contrib/llvm-project/llvm/lib/TextAPI/TextStub.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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 <set>
29 
30 // clang-format off
31 /*
32 
33  YAML Format specification.
34 
35  The TBD v1 format only support two level address libraries and is per
36  definition application extension safe.
37 
38 ---                              # the tag !tapi-tbd-v1 is optional and
39                                  # shouldn't be emitted to support older linker.
40 archs: [ armv7, armv7s, arm64 ]  # the list of architecture slices that are
41                                  # supported by this file.
42 platform: ios                    # Specifies the platform (macosx, ios, etc)
43 install-name: /u/l/libfoo.dylib  #
44 current-version: 1.2.3           # Optional: defaults to 1.0
45 compatibility-version: 1.0       # Optional: defaults to 1.0
46 swift-version: 0                 # Optional: defaults to 0
47 objc-constraint: none            # Optional: defaults to none
48 exports:                         # List of export sections
49 ...
50 
51 Each export section is defined as following:
52 
53  - archs: [ arm64 ]                   # the list of architecture slices
54    allowed-clients: [ client ]        # Optional: List of clients
55    re-exports: [ ]                    # Optional: List of re-exports
56    symbols: [ _sym ]                  # Optional: List of symbols
57    objc-classes: []                   # Optional: List of Objective-C classes
58    objc-ivars: []                     # Optional: List of Objective C Instance
59                                       #           Variables
60    weak-def-symbols: []               # Optional: List of weak defined symbols
61    thread-local-symbols: []           # Optional: List of thread local symbols
62 */
63 
64 /*
65 
66  YAML Format specification.
67 
68 --- !tapi-tbd-v2
69 archs: [ armv7, armv7s, arm64 ]  # the list of architecture slices that are
70                                  # supported by this file.
71 uuids: [ armv7:... ]             # Optional: List of architecture and UUID pairs.
72 platform: ios                    # Specifies the platform (macosx, ios, etc)
73 flags: []                        # Optional:
74 install-name: /u/l/libfoo.dylib  #
75 current-version: 1.2.3           # Optional: defaults to 1.0
76 compatibility-version: 1.0       # Optional: defaults to 1.0
77 swift-version: 0                 # Optional: defaults to 0
78 objc-constraint: retain_release  # Optional: defaults to retain_release
79 parent-umbrella:                 # Optional:
80 exports:                         # List of export sections
81 ...
82 undefineds:                      # List of undefineds sections
83 ...
84 
85 Each export section is defined as following:
86 
87 - archs: [ arm64 ]                   # the list of architecture slices
88   allowed-clients: [ client ]        # Optional: List of clients
89   re-exports: [ ]                    # Optional: List of re-exports
90   symbols: [ _sym ]                  # Optional: List of symbols
91   objc-classes: []                   # Optional: List of Objective-C classes
92   objc-ivars: []                     # Optional: List of Objective C Instance
93                                      #           Variables
94   weak-def-symbols: []               # Optional: List of weak defined symbols
95   thread-local-symbols: []           # Optional: List of thread local symbols
96 
97 Each undefineds section is defined as following:
98 - archs: [ arm64 ]     # the list of architecture slices
99   symbols: [ _sym ]    # Optional: List of symbols
100   objc-classes: []     # Optional: List of Objective-C classes
101   objc-ivars: []       # Optional: List of Objective C Instance Variables
102   weak-ref-symbols: [] # Optional: List of weak defined symbols
103 */
104 
105 /*
106 
107  YAML Format specification.
108 
109 --- !tapi-tbd-v3
110 archs: [ armv7, armv7s, arm64 ]  # the list of architecture slices that are
111                                  # supported by this file.
112 uuids: [ armv7:... ]             # Optional: List of architecture and UUID pairs.
113 platform: ios                    # Specifies the platform (macosx, ios, etc)
114 flags: []                        # Optional:
115 install-name: /u/l/libfoo.dylib  #
116 current-version: 1.2.3           # Optional: defaults to 1.0
117 compatibility-version: 1.0       # Optional: defaults to 1.0
118 swift-abi-version: 0             # Optional: defaults to 0
119 objc-constraint: retain_release  # Optional: defaults to retain_release
120 parent-umbrella:                 # Optional:
121 exports:                         # List of export sections
122 ...
123 undefineds:                      # List of undefineds sections
124 ...
125 
126 Each export section is defined as following:
127 
128 - archs: [ arm64 ]                   # the list of architecture slices
129   allowed-clients: [ client ]        # Optional: List of clients
130   re-exports: [ ]                    # Optional: List of re-exports
131   symbols: [ _sym ]                  # Optional: List of symbols
132   objc-classes: []                   # Optional: List of Objective-C classes
133   objc-eh-types: []                  # Optional: List of Objective-C classes
134                                      #           with EH
135   objc-ivars: []                     # Optional: List of Objective C Instance
136                                      #           Variables
137   weak-def-symbols: []               # Optional: List of weak defined symbols
138   thread-local-symbols: []           # Optional: List of thread local symbols
139 
140 Each undefineds section is defined as following:
141 - archs: [ arm64 ]     # the list of architecture slices
142   symbols: [ _sym ]    # Optional: List of symbols
143   objc-classes: []     # Optional: List of Objective-C classes
144   objc-eh-types: []                  # Optional: List of Objective-C classes
145                                      #           with EH
146   objc-ivars: []       # Optional: List of Objective C Instance Variables
147   weak-ref-symbols: [] # Optional: List of weak defined symbols
148 */
149 
150 /*
151 
152  YAML Format specification.
153 
154 --- !tapi-tbd
155 tbd-version: 4                              # The tbd version for format
156 targets: [ armv7-ios, x86_64-maccatalyst ]  # The list of applicable tapi supported target triples
157 uuids:                                      # Optional: List of target and UUID pairs.
158   - target: armv7-ios
159     value: ...
160   - target: x86_64-maccatalyst
161     value: ...
162 flags: []                        # Optional:
163 install-name: /u/l/libfoo.dylib  #
164 current-version: 1.2.3           # Optional: defaults to 1.0
165 compatibility-version: 1.0       # Optional: defaults to 1.0
166 swift-abi-version: 0             # Optional: defaults to 0
167 parent-umbrella:                 # Optional:
168 allowable-clients:
169   - targets: [ armv7-ios ]       # Optional:
170     clients: [ clientA ]
171 exports:                         # List of export sections
172 ...
173 re-exports:                      # List of reexport sections
174 ...
175 undefineds:                      # List of undefineds sections
176 ...
177 
178 Each export and reexport  section is defined as following:
179 
180 - targets: [ arm64-macos ]                        # The list of target triples associated with symbols
181   symbols: [ _symA ]                              # Optional: List of symbols
182   objc-classes: []                                # Optional: List of Objective-C classes
183   objc-eh-types: []                               # Optional: List of Objective-C classes
184                                                   #           with EH
185   objc-ivars: []                                  # Optional: List of Objective C Instance
186                                                   #           Variables
187   weak-symbols: []                                # Optional: List of weak defined symbols
188   thread-local-symbols: []                        # Optional: List of thread local symbols
189 - targets: [ arm64-macos, x86_64-maccatalyst ]    # Optional: Targets for applicable additional symbols
190   symbols: [ _symB ]                              # Optional: List of symbols
191 
192 Each undefineds section is defined as following:
193 - targets: [ arm64-macos ]    # The list of target triples associated with symbols
194   symbols: [ _symC ]          # Optional: List of symbols
195   objc-classes: []            # Optional: List of Objective-C classes
196   objc-eh-types: []           # Optional: List of Objective-C classes
197                               #           with EH
198   objc-ivars: []              # Optional: List of Objective C Instance Variables
199   weak-symbols: []            # Optional: List of weak defined symbols
200 */
201 // clang-format on
202 
203 using namespace llvm;
204 using namespace llvm::yaml;
205 using namespace llvm::MachO;
206 
207 namespace {
208 struct ExportSection {
209   std::vector<Architecture> Architectures;
210   std::vector<FlowStringRef> AllowableClients;
211   std::vector<FlowStringRef> ReexportedLibraries;
212   std::vector<FlowStringRef> Symbols;
213   std::vector<FlowStringRef> Classes;
214   std::vector<FlowStringRef> ClassEHs;
215   std::vector<FlowStringRef> IVars;
216   std::vector<FlowStringRef> WeakDefSymbols;
217   std::vector<FlowStringRef> TLVSymbols;
218 };
219 
220 struct UndefinedSection {
221   std::vector<Architecture> Architectures;
222   std::vector<FlowStringRef> Symbols;
223   std::vector<FlowStringRef> Classes;
224   std::vector<FlowStringRef> ClassEHs;
225   std::vector<FlowStringRef> IVars;
226   std::vector<FlowStringRef> WeakRefSymbols;
227 };
228 
229 // Sections for direct target mapping in TBDv4
230 struct SymbolSection {
231   TargetList Targets;
232   std::vector<FlowStringRef> Symbols;
233   std::vector<FlowStringRef> Classes;
234   std::vector<FlowStringRef> ClassEHs;
235   std::vector<FlowStringRef> Ivars;
236   std::vector<FlowStringRef> WeakSymbols;
237   std::vector<FlowStringRef> TlvSymbols;
238 };
239 
240 struct MetadataSection {
241   enum Option { Clients, Libraries };
242   std::vector<Target> Targets;
243   std::vector<FlowStringRef> Values;
244 };
245 
246 struct UmbrellaSection {
247   std::vector<Target> Targets;
248   std::string Umbrella;
249 };
250 
251 // UUID's for TBDv4 are mapped to target not arch
252 struct UUIDv4 {
253   Target TargetID;
254   std::string Value;
255 
256   UUIDv4() = default;
257   UUIDv4(const Target &TargetID, const std::string &Value)
258       : TargetID(TargetID), Value(Value) {}
259 };
260 } // end anonymous namespace.
261 
262 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture)
263 LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection)
264 LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection)
265 // Specific to TBDv4
266 LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection)
267 LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection)
268 LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection)
269 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target)
270 LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4)
271 
272 namespace llvm {
273 namespace yaml {
274 
275 template <> struct MappingTraits<ExportSection> {
276   static void mapping(IO &IO, ExportSection &Section) {
277     const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
278     assert((!Ctx || Ctx->FileKind != FileType::Invalid) &&
279            "File type is not set in YAML context");
280 
281     IO.mapRequired("archs", Section.Architectures);
282     if (Ctx->FileKind == FileType::TBD_V1)
283       IO.mapOptional("allowed-clients", Section.AllowableClients);
284     else
285       IO.mapOptional("allowable-clients", Section.AllowableClients);
286     IO.mapOptional("re-exports", Section.ReexportedLibraries);
287     IO.mapOptional("symbols", Section.Symbols);
288     IO.mapOptional("objc-classes", Section.Classes);
289     if (Ctx->FileKind == FileType::TBD_V3)
290       IO.mapOptional("objc-eh-types", Section.ClassEHs);
291     IO.mapOptional("objc-ivars", Section.IVars);
292     IO.mapOptional("weak-def-symbols", Section.WeakDefSymbols);
293     IO.mapOptional("thread-local-symbols", Section.TLVSymbols);
294   }
295 };
296 
297 template <> struct MappingTraits<UndefinedSection> {
298   static void mapping(IO &IO, UndefinedSection &Section) {
299     const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
300     assert((!Ctx || Ctx->FileKind != FileType::Invalid) &&
301            "File type is not set in YAML context");
302 
303     IO.mapRequired("archs", Section.Architectures);
304     IO.mapOptional("symbols", Section.Symbols);
305     IO.mapOptional("objc-classes", Section.Classes);
306     if (Ctx->FileKind == FileType::TBD_V3)
307       IO.mapOptional("objc-eh-types", Section.ClassEHs);
308     IO.mapOptional("objc-ivars", Section.IVars);
309     IO.mapOptional("weak-ref-symbols", Section.WeakRefSymbols);
310   }
311 };
312 
313 template <> struct MappingTraits<SymbolSection> {
314   static void mapping(IO &IO, SymbolSection &Section) {
315     IO.mapRequired("targets", Section.Targets);
316     IO.mapOptional("symbols", Section.Symbols);
317     IO.mapOptional("objc-classes", Section.Classes);
318     IO.mapOptional("objc-eh-types", Section.ClassEHs);
319     IO.mapOptional("objc-ivars", Section.Ivars);
320     IO.mapOptional("weak-symbols", Section.WeakSymbols);
321     IO.mapOptional("thread-local-symbols", Section.TlvSymbols);
322   }
323 };
324 
325 template <> struct MappingTraits<UmbrellaSection> {
326   static void mapping(IO &IO, UmbrellaSection &Section) {
327     IO.mapRequired("targets", Section.Targets);
328     IO.mapRequired("umbrella", Section.Umbrella);
329   }
330 };
331 
332 template <> struct MappingTraits<UUIDv4> {
333   static void mapping(IO &IO, UUIDv4 &UUID) {
334     IO.mapRequired("target", UUID.TargetID);
335     IO.mapRequired("value", UUID.Value);
336   }
337 };
338 
339 template <>
340 struct MappingContextTraits<MetadataSection, MetadataSection::Option> {
341   static void mapping(IO &IO, MetadataSection &Section,
342                       MetadataSection::Option &OptionKind) {
343     IO.mapRequired("targets", Section.Targets);
344     switch (OptionKind) {
345     case MetadataSection::Option::Clients:
346       IO.mapRequired("clients", Section.Values);
347       return;
348     case MetadataSection::Option::Libraries:
349       IO.mapRequired("libraries", Section.Values);
350       return;
351     }
352     llvm_unreachable("unexpected option for metadata");
353   }
354 };
355 
356 template <> struct ScalarBitSetTraits<TBDFlags> {
357   static void bitset(IO &IO, TBDFlags &Flags) {
358     IO.bitSetCase(Flags, "flat_namespace", TBDFlags::FlatNamespace);
359     IO.bitSetCase(Flags, "not_app_extension_safe",
360                   TBDFlags::NotApplicationExtensionSafe);
361     IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI);
362     IO.bitSetCase(Flags, "not_for_dyld_shared_cache",
363                   TBDFlags::OSLibNotForSharedCache);
364   }
365 };
366 
367 template <> struct ScalarTraits<Target> {
368   static void output(const Target &Value, void *, raw_ostream &OS) {
369     OS << Value.Arch << "-";
370     switch (Value.Platform) {
371 #define PLATFORM(platform, id, name, build_name, target, tapi_target,          \
372                  marketing)                                                    \
373   case PLATFORM_##platform:                                                    \
374     OS << #tapi_target;                                                        \
375     break;
376 #include "llvm/BinaryFormat/MachO.def"
377     }
378   }
379 
380   static StringRef input(StringRef Scalar, void *, Target &Value) {
381     auto Result = Target::create(Scalar);
382     if (!Result) {
383       consumeError(Result.takeError());
384       return "unparsable target";
385     }
386 
387     Value = *Result;
388     if (Value.Arch == AK_unknown)
389       return "unknown architecture";
390     if (Value.Platform == PLATFORM_UNKNOWN)
391       return "unknown platform";
392 
393     return {};
394   }
395 
396   static QuotingType mustQuote(StringRef) { return QuotingType::None; }
397 };
398 
399 template <> struct MappingTraits<const InterfaceFile *> {
400   struct NormalizedTBD {
401     explicit NormalizedTBD(IO &IO) {}
402     NormalizedTBD(IO &IO, const InterfaceFile *&File) {
403       Architectures = File->getArchitectures();
404       Platforms = File->getPlatforms();
405       InstallName = File->getInstallName();
406       CurrentVersion = PackedVersion(File->getCurrentVersion());
407       CompatibilityVersion = PackedVersion(File->getCompatibilityVersion());
408       SwiftABIVersion = File->getSwiftABIVersion();
409       ObjCConstraint = File->getObjCConstraint();
410 
411       Flags = TBDFlags::None;
412       if (!File->isApplicationExtensionSafe())
413         Flags |= TBDFlags::NotApplicationExtensionSafe;
414 
415       if (!File->isTwoLevelNamespace())
416         Flags |= TBDFlags::FlatNamespace;
417 
418       if (!File->umbrellas().empty())
419         ParentUmbrella = File->umbrellas().begin()->second;
420 
421       std::set<ArchitectureSet> ArchSet;
422       for (const auto &Library : File->allowableClients())
423         ArchSet.insert(Library.getArchitectures());
424 
425       for (const auto &Library : File->reexportedLibraries())
426         ArchSet.insert(Library.getArchitectures());
427 
428       std::map<const Symbol *, ArchitectureSet> SymbolToArchSet;
429       for (const auto *Symbol : File->symbols()) {
430         auto Architectures = Symbol->getArchitectures();
431         SymbolToArchSet[Symbol] = Architectures;
432         ArchSet.insert(Architectures);
433       }
434 
435       for (auto Architectures : ArchSet) {
436         ExportSection Section;
437         Section.Architectures = Architectures;
438 
439         for (const auto &Library : File->allowableClients())
440           if (Library.getArchitectures() == Architectures)
441             Section.AllowableClients.emplace_back(Library.getInstallName());
442 
443         for (const auto &Library : File->reexportedLibraries())
444           if (Library.getArchitectures() == Architectures)
445             Section.ReexportedLibraries.emplace_back(Library.getInstallName());
446 
447         for (const auto &SymArch : SymbolToArchSet) {
448           if (SymArch.second != Architectures)
449             continue;
450 
451           const auto *Symbol = SymArch.first;
452           switch (Symbol->getKind()) {
453           case EncodeKind::GlobalSymbol:
454             if (Symbol->isWeakDefined())
455               Section.WeakDefSymbols.emplace_back(Symbol->getName());
456             else if (Symbol->isThreadLocalValue())
457               Section.TLVSymbols.emplace_back(Symbol->getName());
458             else
459               Section.Symbols.emplace_back(Symbol->getName());
460             break;
461           case EncodeKind::ObjectiveCClass:
462             if (File->getFileType() != FileType::TBD_V3)
463               Section.Classes.emplace_back(
464                   copyString("_" + Symbol->getName().str()));
465             else
466               Section.Classes.emplace_back(Symbol->getName());
467             break;
468           case EncodeKind::ObjectiveCClassEHType:
469             if (File->getFileType() != FileType::TBD_V3)
470               Section.Symbols.emplace_back(
471                   copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));
472             else
473               Section.ClassEHs.emplace_back(Symbol->getName());
474             break;
475           case EncodeKind::ObjectiveCInstanceVariable:
476             if (File->getFileType() != FileType::TBD_V3)
477               Section.IVars.emplace_back(
478                   copyString("_" + Symbol->getName().str()));
479             else
480               Section.IVars.emplace_back(Symbol->getName());
481             break;
482           }
483         }
484         llvm::sort(Section.Symbols);
485         llvm::sort(Section.Classes);
486         llvm::sort(Section.ClassEHs);
487         llvm::sort(Section.IVars);
488         llvm::sort(Section.WeakDefSymbols);
489         llvm::sort(Section.TLVSymbols);
490         Exports.emplace_back(std::move(Section));
491       }
492 
493       ArchSet.clear();
494       SymbolToArchSet.clear();
495 
496       for (const auto *Symbol : File->undefineds()) {
497         auto Architectures = Symbol->getArchitectures();
498         SymbolToArchSet[Symbol] = Architectures;
499         ArchSet.insert(Architectures);
500       }
501 
502       for (auto Architectures : ArchSet) {
503         UndefinedSection Section;
504         Section.Architectures = Architectures;
505 
506         for (const auto &SymArch : SymbolToArchSet) {
507           if (SymArch.second != Architectures)
508             continue;
509 
510           const auto *Symbol = SymArch.first;
511           switch (Symbol->getKind()) {
512           case EncodeKind::GlobalSymbol:
513             if (Symbol->isWeakReferenced())
514               Section.WeakRefSymbols.emplace_back(Symbol->getName());
515             else
516               Section.Symbols.emplace_back(Symbol->getName());
517             break;
518           case EncodeKind::ObjectiveCClass:
519             if (File->getFileType() != FileType::TBD_V3)
520               Section.Classes.emplace_back(
521                   copyString("_" + Symbol->getName().str()));
522             else
523               Section.Classes.emplace_back(Symbol->getName());
524             break;
525           case EncodeKind::ObjectiveCClassEHType:
526             if (File->getFileType() != FileType::TBD_V3)
527               Section.Symbols.emplace_back(
528                   copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));
529             else
530               Section.ClassEHs.emplace_back(Symbol->getName());
531             break;
532           case EncodeKind::ObjectiveCInstanceVariable:
533             if (File->getFileType() != FileType::TBD_V3)
534               Section.IVars.emplace_back(
535                   copyString("_" + Symbol->getName().str()));
536             else
537               Section.IVars.emplace_back(Symbol->getName());
538             break;
539           }
540         }
541         llvm::sort(Section.Symbols);
542         llvm::sort(Section.Classes);
543         llvm::sort(Section.ClassEHs);
544         llvm::sort(Section.IVars);
545         llvm::sort(Section.WeakRefSymbols);
546         Undefineds.emplace_back(std::move(Section));
547       }
548     }
549 
550     // TBD v1 - TBD v3 files only support one platform and several
551     // architectures. It is possible to have more than one platform for TBD v3
552     // files, but the architectures don't apply to all
553     // platforms, specifically to filter out the i386 slice from
554     // platform macCatalyst.
555     TargetList synthesizeTargets(ArchitectureSet Architectures,
556                                  const PlatformSet &Platforms) {
557       TargetList Targets;
558 
559       for (auto Platform : Platforms) {
560         Platform = mapToPlatformType(Platform, Architectures.hasX86());
561 
562         for (const auto &&Architecture : Architectures) {
563           if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST))
564             continue;
565 
566           Targets.emplace_back(Architecture, Platform);
567         }
568       }
569       return Targets;
570     }
571 
572     const InterfaceFile *denormalize(IO &IO) {
573       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
574       assert(Ctx);
575 
576       auto *File = new InterfaceFile;
577       File->setPath(Ctx->Path);
578       File->setFileType(Ctx->FileKind);
579       File->addTargets(synthesizeTargets(Architectures, Platforms));
580       File->setInstallName(InstallName);
581       File->setCurrentVersion(CurrentVersion);
582       File->setCompatibilityVersion(CompatibilityVersion);
583       File->setSwiftABIVersion(SwiftABIVersion);
584       File->setObjCConstraint(ObjCConstraint);
585       for (const auto &Target : File->targets())
586         File->addParentUmbrella(Target, ParentUmbrella);
587 
588       if (Ctx->FileKind == FileType::TBD_V1) {
589         File->setTwoLevelNamespace();
590         File->setApplicationExtensionSafe();
591       } else {
592         File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
593         File->setApplicationExtensionSafe(
594             !(Flags & TBDFlags::NotApplicationExtensionSafe));
595       }
596 
597       // For older file formats, the segment where the symbol
598       // comes from is unknown, treat all symbols as Data
599       // in these cases.
600       const auto Flags = SymbolFlags::Data;
601 
602       for (const auto &Section : Exports) {
603         const auto Targets =
604             synthesizeTargets(Section.Architectures, Platforms);
605 
606         for (const auto &Lib : Section.AllowableClients)
607           for (const auto &Target : Targets)
608             File->addAllowableClient(Lib, Target);
609 
610         for (const auto &Lib : Section.ReexportedLibraries)
611           for (const auto &Target : Targets)
612             File->addReexportedLibrary(Lib, Target);
613 
614         for (const auto &Symbol : Section.Symbols) {
615           if (Ctx->FileKind != FileType::TBD_V3 &&
616               Symbol.value.starts_with(ObjC2EHTypePrefix))
617             File->addSymbol(EncodeKind::ObjectiveCClassEHType,
618                             Symbol.value.drop_front(15), Targets, Flags);
619           else
620             File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, Flags);
621         }
622         for (auto &Symbol : Section.Classes) {
623           auto Name = Symbol.value;
624           if (Ctx->FileKind != FileType::TBD_V3)
625             Name = Name.drop_front();
626           File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets, Flags);
627         }
628         for (auto &Symbol : Section.ClassEHs)
629           File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets,
630                           Flags);
631         for (auto &Symbol : Section.IVars) {
632           auto Name = Symbol.value;
633           if (Ctx->FileKind != FileType::TBD_V3)
634             Name = Name.drop_front();
635           File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets,
636                           Flags);
637         }
638         for (auto &Symbol : Section.WeakDefSymbols)
639           File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,
640                           SymbolFlags::WeakDefined | Flags);
641         for (auto &Symbol : Section.TLVSymbols)
642           File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,
643                           SymbolFlags::ThreadLocalValue | Flags);
644       }
645 
646       for (const auto &Section : Undefineds) {
647         const auto Targets =
648             synthesizeTargets(Section.Architectures, Platforms);
649         for (auto &Symbol : Section.Symbols) {
650           if (Ctx->FileKind != FileType::TBD_V3 &&
651               Symbol.value.starts_with(ObjC2EHTypePrefix))
652             File->addSymbol(EncodeKind::ObjectiveCClassEHType,
653                             Symbol.value.drop_front(15), Targets,
654                             SymbolFlags::Undefined | Flags);
655           else
656             File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,
657                             SymbolFlags::Undefined | Flags);
658         }
659         for (auto &Symbol : Section.Classes) {
660           auto Name = Symbol.value;
661           if (Ctx->FileKind != FileType::TBD_V3)
662             Name = Name.drop_front();
663           File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets,
664                           SymbolFlags::Undefined | Flags);
665         }
666         for (auto &Symbol : Section.ClassEHs)
667           File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets,
668                           SymbolFlags::Undefined | Flags);
669         for (auto &Symbol : Section.IVars) {
670           auto Name = Symbol.value;
671           if (Ctx->FileKind != FileType::TBD_V3)
672             Name = Name.drop_front();
673           File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets,
674                           SymbolFlags::Undefined | Flags);
675         }
676         for (auto &Symbol : Section.WeakRefSymbols)
677           File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,
678                           SymbolFlags::Undefined | SymbolFlags::WeakReferenced |
679                               Flags);
680       }
681 
682       return File;
683     }
684 
685     llvm::BumpPtrAllocator Allocator;
686     StringRef copyString(StringRef String) {
687       if (String.empty())
688         return {};
689 
690       void *Ptr = Allocator.Allocate(String.size(), 1);
691       memcpy(Ptr, String.data(), String.size());
692       return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
693     }
694 
695     std::vector<Architecture> Architectures;
696     std::vector<UUID> UUIDs;
697     PlatformSet Platforms;
698     StringRef InstallName;
699     PackedVersion CurrentVersion;
700     PackedVersion CompatibilityVersion;
701     SwiftVersion SwiftABIVersion{0};
702     ObjCConstraintType ObjCConstraint{ObjCConstraintType::None};
703     TBDFlags Flags{TBDFlags::None};
704     StringRef ParentUmbrella;
705     std::vector<ExportSection> Exports;
706     std::vector<UndefinedSection> Undefineds;
707   };
708 
709   static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) {
710     if (IO.mapTag("!tapi-tbd", false))
711       Ctx->FileKind = FileType::TBD_V4;
712     else if (IO.mapTag("!tapi-tbd-v3", false))
713       Ctx->FileKind = FileType::TBD_V3;
714     else if (IO.mapTag("!tapi-tbd-v2", false))
715       Ctx->FileKind = FileType::TBD_V2;
716     else if (IO.mapTag("!tapi-tbd-v1", false) ||
717              IO.mapTag("tag:yaml.org,2002:map", false))
718       Ctx->FileKind = FileType::TBD_V1;
719     else {
720       Ctx->FileKind = FileType::Invalid;
721       return;
722     }
723   }
724 
725   static void mapping(IO &IO, const InterfaceFile *&File) {
726     auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
727     assert((!Ctx || !IO.outputting() ||
728             (Ctx && Ctx->FileKind != FileType::Invalid)) &&
729            "File type is not set in YAML context");
730 
731     if (!IO.outputting()) {
732       setFileTypeForInput(Ctx, IO);
733       switch (Ctx->FileKind) {
734       default:
735         break;
736       case FileType::TBD_V4:
737         mapKeysToValuesV4(IO, File);
738         return;
739       case FileType::Invalid:
740         IO.setError("unsupported file type");
741         return;
742       }
743     } else {
744       // Set file type when writing.
745       switch (Ctx->FileKind) {
746       default:
747         llvm_unreachable("unexpected file type");
748       case FileType::TBD_V4:
749         mapKeysToValuesV4(IO, File);
750         return;
751       case FileType::TBD_V3:
752         IO.mapTag("!tapi-tbd-v3", true);
753         break;
754       case FileType::TBD_V2:
755         IO.mapTag("!tapi-tbd-v2", true);
756         break;
757       case FileType::TBD_V1:
758         // Don't write the tag into the .tbd file for TBD v1
759         break;
760       }
761     }
762     mapKeysToValues(Ctx->FileKind, IO, File);
763   }
764 
765   using SectionList = std::vector<SymbolSection>;
766   struct NormalizedTBD_V4 {
767     explicit NormalizedTBD_V4(IO &IO) {}
768     NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) {
769       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
770       assert(Ctx);
771       TBDVersion = Ctx->FileKind >> 4;
772       Targets.insert(Targets.begin(), File->targets().begin(),
773                      File->targets().end());
774       InstallName = File->getInstallName();
775       CurrentVersion = File->getCurrentVersion();
776       CompatibilityVersion = File->getCompatibilityVersion();
777       SwiftABIVersion = File->getSwiftABIVersion();
778 
779       Flags = TBDFlags::None;
780       if (!File->isApplicationExtensionSafe())
781         Flags |= TBDFlags::NotApplicationExtensionSafe;
782 
783       if (!File->isTwoLevelNamespace())
784         Flags |= TBDFlags::FlatNamespace;
785 
786       if (File->isOSLibNotForSharedCache())
787         Flags |= TBDFlags::OSLibNotForSharedCache;
788 
789       {
790         std::map<std::string, TargetList> valueToTargetList;
791         for (const auto &it : File->umbrellas())
792           valueToTargetList[it.second].emplace_back(it.first);
793 
794         for (const auto &it : valueToTargetList) {
795           UmbrellaSection CurrentSection;
796           CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
797                                         it.second.begin(), it.second.end());
798           CurrentSection.Umbrella = it.first;
799           ParentUmbrellas.emplace_back(std::move(CurrentSection));
800         }
801       }
802 
803       assignTargetsToLibrary(File->allowableClients(), AllowableClients);
804       assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries);
805 
806       auto handleSymbols =
807           [](SectionList &CurrentSections,
808              InterfaceFile::const_filtered_symbol_range Symbols) {
809             std::set<TargetList> TargetSet;
810             std::map<const Symbol *, TargetList> SymbolToTargetList;
811             for (const auto *Symbol : Symbols) {
812               TargetList Targets(Symbol->targets());
813               SymbolToTargetList[Symbol] = Targets;
814               TargetSet.emplace(std::move(Targets));
815             }
816             for (const auto &TargetIDs : TargetSet) {
817               SymbolSection CurrentSection;
818               CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
819                                             TargetIDs.begin(), TargetIDs.end());
820 
821               for (const auto &IT : SymbolToTargetList) {
822                 if (IT.second != TargetIDs)
823                   continue;
824 
825                 const auto *Symbol = IT.first;
826                 switch (Symbol->getKind()) {
827                 case EncodeKind::GlobalSymbol:
828                   if (Symbol->isWeakDefined())
829                     CurrentSection.WeakSymbols.emplace_back(Symbol->getName());
830                   else if (Symbol->isThreadLocalValue())
831                     CurrentSection.TlvSymbols.emplace_back(Symbol->getName());
832                   else
833                     CurrentSection.Symbols.emplace_back(Symbol->getName());
834                   break;
835                 case EncodeKind::ObjectiveCClass:
836                   CurrentSection.Classes.emplace_back(Symbol->getName());
837                   break;
838                 case EncodeKind::ObjectiveCClassEHType:
839                   CurrentSection.ClassEHs.emplace_back(Symbol->getName());
840                   break;
841                 case EncodeKind::ObjectiveCInstanceVariable:
842                   CurrentSection.Ivars.emplace_back(Symbol->getName());
843                   break;
844                 }
845               }
846               sort(CurrentSection.Symbols);
847               sort(CurrentSection.Classes);
848               sort(CurrentSection.ClassEHs);
849               sort(CurrentSection.Ivars);
850               sort(CurrentSection.WeakSymbols);
851               sort(CurrentSection.TlvSymbols);
852               CurrentSections.emplace_back(std::move(CurrentSection));
853             }
854           };
855 
856       handleSymbols(Exports, File->exports());
857       handleSymbols(Reexports, File->reexports());
858       handleSymbols(Undefineds, File->undefineds());
859     }
860 
861     const InterfaceFile *denormalize(IO &IO) {
862       auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
863       assert(Ctx);
864 
865       auto *File = new InterfaceFile;
866       File->setPath(Ctx->Path);
867       File->setFileType(Ctx->FileKind);
868       File->addTargets(Targets);
869       File->setInstallName(InstallName);
870       File->setCurrentVersion(CurrentVersion);
871       File->setCompatibilityVersion(CompatibilityVersion);
872       File->setSwiftABIVersion(SwiftABIVersion);
873       for (const auto &CurrentSection : ParentUmbrellas)
874         for (const auto &target : CurrentSection.Targets)
875           File->addParentUmbrella(target, CurrentSection.Umbrella);
876       File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
877       File->setApplicationExtensionSafe(
878           !(Flags & TBDFlags::NotApplicationExtensionSafe));
879       File->setOSLibNotForSharedCache(
880           (Flags & TBDFlags::OSLibNotForSharedCache));
881 
882       for (const auto &CurrentSection : AllowableClients) {
883         for (const auto &lib : CurrentSection.Values)
884           for (const auto &Target : CurrentSection.Targets)
885             File->addAllowableClient(lib, Target);
886       }
887 
888       for (const auto &CurrentSection : ReexportedLibraries) {
889         for (const auto &Lib : CurrentSection.Values)
890           for (const auto &Target : CurrentSection.Targets)
891             File->addReexportedLibrary(Lib, Target);
892       }
893 
894       auto handleSymbols = [File](const SectionList &CurrentSections,
895                                   SymbolFlags InputFlag = SymbolFlags::None) {
896         // For older file formats, the segment where the symbol
897         // comes from is unknown, treat all symbols as Data
898         // in these cases.
899         const SymbolFlags Flag = InputFlag | SymbolFlags::Data;
900 
901         for (const auto &CurrentSection : CurrentSections) {
902           for (auto &sym : CurrentSection.Symbols)
903             File->addSymbol(EncodeKind::GlobalSymbol, sym,
904                             CurrentSection.Targets, Flag);
905 
906           for (auto &sym : CurrentSection.Classes)
907             File->addSymbol(EncodeKind::ObjectiveCClass, sym,
908                             CurrentSection.Targets, Flag);
909 
910           for (auto &sym : CurrentSection.ClassEHs)
911             File->addSymbol(EncodeKind::ObjectiveCClassEHType, sym,
912                             CurrentSection.Targets, Flag);
913 
914           for (auto &sym : CurrentSection.Ivars)
915             File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, sym,
916                             CurrentSection.Targets, Flag);
917 
918           SymbolFlags SymFlag =
919               ((Flag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
920                   ? SymbolFlags::WeakReferenced
921                   : SymbolFlags::WeakDefined;
922           for (auto &sym : CurrentSection.WeakSymbols) {
923             File->addSymbol(EncodeKind::GlobalSymbol, sym,
924                             CurrentSection.Targets, Flag | SymFlag);
925           }
926 
927           for (auto &sym : CurrentSection.TlvSymbols)
928             File->addSymbol(EncodeKind::GlobalSymbol, sym,
929                             CurrentSection.Targets,
930                             Flag | SymbolFlags::ThreadLocalValue);
931         }
932       };
933 
934       handleSymbols(Exports);
935       handleSymbols(Reexports, SymbolFlags::Rexported);
936       handleSymbols(Undefineds, SymbolFlags::Undefined);
937 
938       return File;
939     }
940 
941     unsigned TBDVersion;
942     std::vector<UUIDv4> UUIDs;
943     TargetList Targets;
944     StringRef InstallName;
945     PackedVersion CurrentVersion;
946     PackedVersion CompatibilityVersion;
947     SwiftVersion SwiftABIVersion{0};
948     std::vector<MetadataSection> AllowableClients;
949     std::vector<MetadataSection> ReexportedLibraries;
950     TBDFlags Flags{TBDFlags::None};
951     std::vector<UmbrellaSection> ParentUmbrellas;
952     SectionList Exports;
953     SectionList Reexports;
954     SectionList Undefineds;
955 
956   private:
957     void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries,
958                                 std::vector<MetadataSection> &Section) {
959       std::set<TargetList> targetSet;
960       std::map<const InterfaceFileRef *, TargetList> valueToTargetList;
961       for (const auto &library : Libraries) {
962         TargetList targets(library.targets());
963         valueToTargetList[&library] = targets;
964         targetSet.emplace(std::move(targets));
965       }
966 
967       for (const auto &targets : targetSet) {
968         MetadataSection CurrentSection;
969         CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
970                                       targets.begin(), targets.end());
971 
972         for (const auto &it : valueToTargetList) {
973           if (it.second != targets)
974             continue;
975 
976           CurrentSection.Values.emplace_back(it.first->getInstallName());
977         }
978         llvm::sort(CurrentSection.Values);
979         Section.emplace_back(std::move(CurrentSection));
980       }
981     }
982   };
983 
984   static void mapKeysToValues(FileType FileKind, IO &IO,
985                               const InterfaceFile *&File) {
986     MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File);
987     std::vector<UUID> EmptyUUID;
988     IO.mapRequired("archs", Keys->Architectures);
989     if (FileKind != FileType::TBD_V1)
990       IO.mapOptional("uuids", EmptyUUID);
991     IO.mapRequired("platform", Keys->Platforms);
992     if (FileKind != FileType::TBD_V1)
993       IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
994     IO.mapRequired("install-name", Keys->InstallName);
995     IO.mapOptional("current-version", Keys->CurrentVersion,
996                    PackedVersion(1, 0, 0));
997     IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,
998                    PackedVersion(1, 0, 0));
999     if (FileKind != FileType::TBD_V3)
1000       IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0));
1001     else
1002       IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion,
1003                      SwiftVersion(0));
1004     IO.mapOptional("objc-constraint", Keys->ObjCConstraint,
1005                    (FileKind == FileType::TBD_V1)
1006                        ? ObjCConstraintType::None
1007                        : ObjCConstraintType::Retain_Release);
1008     if (FileKind != FileType::TBD_V1)
1009       IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef());
1010     IO.mapOptional("exports", Keys->Exports);
1011     if (FileKind != FileType::TBD_V1)
1012       IO.mapOptional("undefineds", Keys->Undefineds);
1013   }
1014 
1015   static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) {
1016     MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO,
1017                                                                        File);
1018     std::vector<UUIDv4> EmptyUUID;
1019     IO.mapTag("!tapi-tbd", true);
1020     IO.mapRequired("tbd-version", Keys->TBDVersion);
1021     IO.mapRequired("targets", Keys->Targets);
1022     IO.mapOptional("uuids", EmptyUUID);
1023     IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
1024     IO.mapRequired("install-name", Keys->InstallName);
1025     IO.mapOptional("current-version", Keys->CurrentVersion,
1026                    PackedVersion(1, 0, 0));
1027     IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,
1028                    PackedVersion(1, 0, 0));
1029     IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0));
1030     IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas);
1031     auto OptionKind = MetadataSection::Option::Clients;
1032     IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients,
1033                               OptionKind);
1034     OptionKind = MetadataSection::Option::Libraries;
1035     IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries,
1036                               OptionKind);
1037     IO.mapOptional("exports", Keys->Exports);
1038     IO.mapOptional("reexports", Keys->Reexports);
1039     IO.mapOptional("undefineds", Keys->Undefineds);
1040   }
1041 };
1042 
1043 template <>
1044 struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> {
1045   static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) {
1046     return Seq.size();
1047   }
1048   static const InterfaceFile *&
1049   element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) {
1050     if (Index >= Seq.size())
1051       Seq.resize(Index + 1);
1052     return Seq[Index];
1053   }
1054 };
1055 
1056 } // end namespace yaml.
1057 } // namespace llvm
1058 
1059 static void DiagHandler(const SMDiagnostic &Diag, void *Context) {
1060   auto *File = static_cast<TextAPIContext *>(Context);
1061   SmallString<1024> Message;
1062   raw_svector_ostream S(Message);
1063 
1064   SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path,
1065                        Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(),
1066                        Diag.getMessage(), Diag.getLineContents(),
1067                        Diag.getRanges(), Diag.getFixIts());
1068 
1069   NewDiag.print(nullptr, S);
1070   File->ErrorMessage = ("malformed file\n" + Message).str();
1071 }
1072 
1073 Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) {
1074   auto TAPIFile = InputBuffer.getBuffer().trim();
1075   if (TAPIFile.starts_with("{") && TAPIFile.ends_with("}"))
1076     return FileType::TBD_V5;
1077 
1078   if (!TAPIFile.ends_with("..."))
1079     return createStringError(std::errc::not_supported, "unsupported file type");
1080 
1081   if (TAPIFile.starts_with("--- !tapi-tbd"))
1082     return FileType::TBD_V4;
1083 
1084   if (TAPIFile.starts_with("--- !tapi-tbd-v3"))
1085     return FileType::TBD_V3;
1086 
1087   if (TAPIFile.starts_with("--- !tapi-tbd-v2"))
1088     return FileType::TBD_V2;
1089 
1090   if (TAPIFile.starts_with("--- !tapi-tbd-v1") ||
1091       TAPIFile.starts_with("---\narchs:"))
1092     return FileType::TBD_V1;
1093 
1094   return createStringError(std::errc::not_supported, "unsupported file type");
1095 }
1096 
1097 Expected<std::unique_ptr<InterfaceFile>>
1098 TextAPIReader::get(MemoryBufferRef InputBuffer) {
1099   TextAPIContext Ctx;
1100   Ctx.Path = std::string(InputBuffer.getBufferIdentifier());
1101   if (auto FTOrErr = canRead(InputBuffer))
1102     Ctx.FileKind = *FTOrErr;
1103   else
1104     return FTOrErr.takeError();
1105 
1106   // Handle JSON Format.
1107   if (Ctx.FileKind >= FileType::TBD_V5) {
1108     auto FileOrErr = getInterfaceFileFromJSON(InputBuffer.getBuffer());
1109     if (!FileOrErr)
1110       return FileOrErr.takeError();
1111 
1112     (*FileOrErr)->setPath(Ctx.Path);
1113     return std::move(*FileOrErr);
1114   }
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 (const InterfaceFile *FI : llvm::drop_begin(Files))
1127     File->addDocument(
1128         std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI)));
1129 
1130   if (YAMLIn.error())
1131     return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error());
1132 
1133   return std::move(File);
1134 }
1135 
1136 Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File,
1137                                    const FileType FileKind, bool Compact) {
1138   TextAPIContext Ctx;
1139   Ctx.Path = std::string(File.getPath());
1140 
1141   // Prefer parameter for format if passed, otherwise fallback to the File
1142   // FileType.
1143   Ctx.FileKind =
1144       (FileKind == FileType::Invalid) ? File.getFileType() : FileKind;
1145 
1146   // Write out in JSON format.
1147   if (Ctx.FileKind >= FileType::TBD_V5) {
1148     return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact);
1149   }
1150 
1151   llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80);
1152 
1153   std::vector<const InterfaceFile *> Files;
1154   Files.emplace_back(&File);
1155 
1156   for (const auto &Document : File.documents())
1157     Files.emplace_back(Document.get());
1158 
1159   // Stream out yaml.
1160   YAMLOut << Files;
1161 
1162   return Error::success();
1163 }
1164