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.
40archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are
41 # supported by this file.
42platform: ios # Specifies the platform (macosx, ios, etc)
43install-name: /u/l/libfoo.dylib #
44current-version: 1.2.3 # Optional: defaults to 1.0
45compatibility-version: 1.0 # Optional: defaults to 1.0
46swift-version: 0 # Optional: defaults to 0
47objc-constraint: none # Optional: defaults to none
48exports: # List of export sections
49...
50
51Each 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
69archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are
70 # supported by this file.
71uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.
72platform: ios # Specifies the platform (macosx, ios, etc)
73flags: [] # Optional:
74install-name: /u/l/libfoo.dylib #
75current-version: 1.2.3 # Optional: defaults to 1.0
76compatibility-version: 1.0 # Optional: defaults to 1.0
77swift-version: 0 # Optional: defaults to 0
78objc-constraint: retain_release # Optional: defaults to retain_release
79parent-umbrella: # Optional:
80exports: # List of export sections
81...
82undefineds: # List of undefineds sections
83...
84
85Each 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
97Each 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
110archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are
111 # supported by this file.
112uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.
113platform: ios # Specifies the platform (macosx, ios, etc)
114flags: [] # Optional:
115install-name: /u/l/libfoo.dylib #
116current-version: 1.2.3 # Optional: defaults to 1.0
117compatibility-version: 1.0 # Optional: defaults to 1.0
118swift-abi-version: 0 # Optional: defaults to 0
119objc-constraint: retain_release # Optional: defaults to retain_release
120parent-umbrella: # Optional:
121exports: # List of export sections
122...
123undefineds: # List of undefineds sections
124...
125
126Each 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
140Each 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
155tbd-version: 4 # The tbd version for format
156targets: [ armv7-ios, x86_64-maccatalyst ] # The list of applicable tapi supported target triples
157uuids: # Optional: List of target and UUID pairs.
158 - target: armv7-ios
159 value: ...
160 - target: x86_64-maccatalyst
161 value: ...
162flags: [] # Optional:
163install-name: /u/l/libfoo.dylib #
164current-version: 1.2.3 # Optional: defaults to 1.0
165compatibility-version: 1.0 # Optional: defaults to 1.0
166swift-abi-version: 0 # Optional: defaults to 0
167parent-umbrella: # Optional:
168allowable-clients:
169 - targets: [ armv7-ios ] # Optional:
170 clients: [ clientA ]
171exports: # List of export sections
172...
173re-exports: # List of reexport sections
174...
175undefineds: # List of undefineds sections
176...
177
178Each 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
192Each 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
203using namespace llvm;
204using namespace llvm::yaml;
205using namespace llvm::MachO;
206
207namespace {
208struct 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
220struct 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
230struct 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
240struct MetadataSection {
241 enum Option { Clients, Libraries };
242 std::vector<Target> Targets;
243 std::vector<FlowStringRef> Values;
244};
245
246struct UmbrellaSection {
247 std::vector<Target> Targets;
248 std::string Umbrella;
249};
250
251// UUID's for TBDv4 are mapped to target not arch
252struct 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
262LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture)
263LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection)
264LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection)
265// Specific to TBDv4
266LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection)
267LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection)
268LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection)
269LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target)
270LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4)
271
272namespace llvm {
273namespace yaml {
274
275template <> 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(Key: "archs", Val&: Section.Architectures);
282 if (Ctx->FileKind == FileType::TBD_V1)
283 IO.mapOptional(Key: "allowed-clients", Val&: Section.AllowableClients);
284 else
285 IO.mapOptional(Key: "allowable-clients", Val&: Section.AllowableClients);
286 IO.mapOptional(Key: "re-exports", Val&: Section.ReexportedLibraries);
287 IO.mapOptional(Key: "symbols", Val&: Section.Symbols);
288 IO.mapOptional(Key: "objc-classes", Val&: Section.Classes);
289 if (Ctx->FileKind == FileType::TBD_V3)
290 IO.mapOptional(Key: "objc-eh-types", Val&: Section.ClassEHs);
291 IO.mapOptional(Key: "objc-ivars", Val&: Section.IVars);
292 IO.mapOptional(Key: "weak-def-symbols", Val&: Section.WeakDefSymbols);
293 IO.mapOptional(Key: "thread-local-symbols", Val&: Section.TLVSymbols);
294 }
295};
296
297template <> 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(Key: "archs", Val&: Section.Architectures);
304 IO.mapOptional(Key: "symbols", Val&: Section.Symbols);
305 IO.mapOptional(Key: "objc-classes", Val&: Section.Classes);
306 if (Ctx->FileKind == FileType::TBD_V3)
307 IO.mapOptional(Key: "objc-eh-types", Val&: Section.ClassEHs);
308 IO.mapOptional(Key: "objc-ivars", Val&: Section.IVars);
309 IO.mapOptional(Key: "weak-ref-symbols", Val&: Section.WeakRefSymbols);
310 }
311};
312
313template <> struct MappingTraits<SymbolSection> {
314 static void mapping(IO &IO, SymbolSection &Section) {
315 IO.mapRequired(Key: "targets", Val&: Section.Targets);
316 IO.mapOptional(Key: "symbols", Val&: Section.Symbols);
317 IO.mapOptional(Key: "objc-classes", Val&: Section.Classes);
318 IO.mapOptional(Key: "objc-eh-types", Val&: Section.ClassEHs);
319 IO.mapOptional(Key: "objc-ivars", Val&: Section.Ivars);
320 IO.mapOptional(Key: "weak-symbols", Val&: Section.WeakSymbols);
321 IO.mapOptional(Key: "thread-local-symbols", Val&: Section.TlvSymbols);
322 }
323};
324
325template <> struct MappingTraits<UmbrellaSection> {
326 static void mapping(IO &IO, UmbrellaSection &Section) {
327 IO.mapRequired(Key: "targets", Val&: Section.Targets);
328 IO.mapRequired(Key: "umbrella", Val&: Section.Umbrella);
329 }
330};
331
332template <> struct MappingTraits<UUIDv4> {
333 static void mapping(IO &IO, UUIDv4 &UUID) {
334 IO.mapRequired(Key: "target", Val&: UUID.TargetID);
335 IO.mapRequired(Key: "value", Val&: UUID.Value);
336 }
337};
338
339template <>
340struct MappingContextTraits<MetadataSection, MetadataSection::Option> {
341 static void mapping(IO &IO, MetadataSection &Section,
342 MetadataSection::Option &OptionKind) {
343 IO.mapRequired(Key: "targets", Val&: Section.Targets);
344 switch (OptionKind) {
345 case MetadataSection::Option::Clients:
346 IO.mapRequired(Key: "clients", Val&: Section.Values);
347 return;
348 case MetadataSection::Option::Libraries:
349 IO.mapRequired(Key: "libraries", Val&: Section.Values);
350 return;
351 }
352 llvm_unreachable("unexpected option for metadata");
353 }
354};
355
356template <> struct ScalarBitSetTraits<TBDFlags> {
357 static void bitset(IO &IO, TBDFlags &Flags) {
358 IO.bitSetCase(Val&: Flags, Str: "flat_namespace", ConstVal: TBDFlags::FlatNamespace);
359 IO.bitSetCase(Val&: Flags, Str: "not_app_extension_safe",
360 ConstVal: TBDFlags::NotApplicationExtensionSafe);
361 IO.bitSetCase(Val&: Flags, Str: "installapi", ConstVal: TBDFlags::InstallAPI);
362 IO.bitSetCase(Val&: Flags, Str: "not_for_dyld_shared_cache",
363 ConstVal: TBDFlags::OSLibNotForSharedCache);
364 }
365};
366
367template <> 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(Target: Scalar);
382 if (!Result) {
383 consumeError(Err: 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
399template <> 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(x: Library.getArchitectures());
424
425 for (const auto &Library : File->reexportedLibraries())
426 ArchSet.insert(x: 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(x: 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(args: Library.getInstallName());
442
443 for (const auto &Library : File->reexportedLibraries())
444 if (Library.getArchitectures() == Architectures)
445 Section.ReexportedLibraries.emplace_back(args: 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(args: Symbol->getName());
456 else if (Symbol->isThreadLocalValue())
457 Section.TLVSymbols.emplace_back(args: Symbol->getName());
458 else
459 Section.Symbols.emplace_back(args: Symbol->getName());
460 break;
461 case EncodeKind::ObjectiveCClass:
462 if (File->getFileType() != FileType::TBD_V3)
463 Section.Classes.emplace_back(
464 args: copyString(String: "_" + Symbol->getName().str()));
465 else
466 Section.Classes.emplace_back(args: Symbol->getName());
467 break;
468 case EncodeKind::ObjectiveCClassEHType:
469 if (File->getFileType() != FileType::TBD_V3)
470 Section.Symbols.emplace_back(
471 args: copyString(String: "_OBJC_EHTYPE_$_" + Symbol->getName().str()));
472 else
473 Section.ClassEHs.emplace_back(args: Symbol->getName());
474 break;
475 case EncodeKind::ObjectiveCInstanceVariable:
476 if (File->getFileType() != FileType::TBD_V3)
477 Section.IVars.emplace_back(
478 args: copyString(String: "_" + Symbol->getName().str()));
479 else
480 Section.IVars.emplace_back(args: Symbol->getName());
481 break;
482 }
483 }
484 llvm::sort(C&: Section.Symbols);
485 llvm::sort(C&: Section.Classes);
486 llvm::sort(C&: Section.ClassEHs);
487 llvm::sort(C&: Section.IVars);
488 llvm::sort(C&: Section.WeakDefSymbols);
489 llvm::sort(C&: Section.TLVSymbols);
490 Exports.emplace_back(args: 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(x: 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(args: Symbol->getName());
515 else
516 Section.Symbols.emplace_back(args: Symbol->getName());
517 break;
518 case EncodeKind::ObjectiveCClass:
519 if (File->getFileType() != FileType::TBD_V3)
520 Section.Classes.emplace_back(
521 args: copyString(String: "_" + Symbol->getName().str()));
522 else
523 Section.Classes.emplace_back(args: Symbol->getName());
524 break;
525 case EncodeKind::ObjectiveCClassEHType:
526 if (File->getFileType() != FileType::TBD_V3)
527 Section.Symbols.emplace_back(
528 args: copyString(String: "_OBJC_EHTYPE_$_" + Symbol->getName().str()));
529 else
530 Section.ClassEHs.emplace_back(args: Symbol->getName());
531 break;
532 case EncodeKind::ObjectiveCInstanceVariable:
533 if (File->getFileType() != FileType::TBD_V3)
534 Section.IVars.emplace_back(
535 args: copyString(String: "_" + Symbol->getName().str()));
536 else
537 Section.IVars.emplace_back(args: Symbol->getName());
538 break;
539 }
540 }
541 llvm::sort(C&: Section.Symbols);
542 llvm::sort(C&: Section.Classes);
543 llvm::sort(C&: Section.ClassEHs);
544 llvm::sort(C&: Section.IVars);
545 llvm::sort(C&: Section.WeakRefSymbols);
546 Undefineds.emplace_back(args: 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, WantSim: Architectures.hasX86());
561
562 for (const auto &&Architecture : Architectures) {
563 if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST))
564 continue;
565
566 Targets.emplace_back(Args: Architecture, Args&: 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(Targets: 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_: Target, Parent: 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(Architectures: Section.Architectures, Platforms);
605
606 for (const auto &Lib : Section.AllowableClients)
607 for (const auto &Target : Targets)
608 File->addAllowableClient(InstallName: Lib, Target);
609
610 for (const auto &Lib : Section.ReexportedLibraries)
611 for (const auto &Target : Targets)
612 File->addReexportedLibrary(InstallName: Lib, Target);
613
614 for (const auto &Symbol : Section.Symbols) {
615 if (Ctx->FileKind != FileType::TBD_V3 &&
616 Symbol.value.starts_with(Prefix: ObjC2EHTypePrefix))
617 File->addSymbol(Kind: EncodeKind::ObjectiveCClassEHType,
618 Name: Symbol.value.drop_front(N: 15), Targets, Flags);
619 else
620 File->addSymbol(Kind: EncodeKind::GlobalSymbol, Name: 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(Kind: EncodeKind::ObjectiveCClass, Name, Targets, Flags);
627 }
628 for (auto &Symbol : Section.ClassEHs)
629 File->addSymbol(Kind: EncodeKind::ObjectiveCClassEHType, Name: 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(Kind: EncodeKind::ObjectiveCInstanceVariable, Name, Targets,
636 Flags);
637 }
638 for (auto &Symbol : Section.WeakDefSymbols)
639 File->addSymbol(Kind: EncodeKind::GlobalSymbol, Name: Symbol, Targets,
640 Flags: SymbolFlags::WeakDefined | Flags);
641 for (auto &Symbol : Section.TLVSymbols)
642 File->addSymbol(Kind: EncodeKind::GlobalSymbol, Name: Symbol, Targets,
643 Flags: SymbolFlags::ThreadLocalValue | Flags);
644 }
645
646 for (const auto &Section : Undefineds) {
647 const auto Targets =
648 synthesizeTargets(Architectures: Section.Architectures, Platforms);
649 for (auto &Symbol : Section.Symbols) {
650 if (Ctx->FileKind != FileType::TBD_V3 &&
651 Symbol.value.starts_with(Prefix: ObjC2EHTypePrefix))
652 File->addSymbol(Kind: EncodeKind::ObjectiveCClassEHType,
653 Name: Symbol.value.drop_front(N: 15), Targets,
654 Flags: SymbolFlags::Undefined | Flags);
655 else
656 File->addSymbol(Kind: EncodeKind::GlobalSymbol, Name: Symbol, Targets,
657 Flags: 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(Kind: EncodeKind::ObjectiveCClass, Name, Targets,
664 Flags: SymbolFlags::Undefined | Flags);
665 }
666 for (auto &Symbol : Section.ClassEHs)
667 File->addSymbol(Kind: EncodeKind::ObjectiveCClassEHType, Name: Symbol, Targets,
668 Flags: 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(Kind: EncodeKind::ObjectiveCInstanceVariable, Name, Targets,
674 Flags: SymbolFlags::Undefined | Flags);
675 }
676 for (auto &Symbol : Section.WeakRefSymbols)
677 File->addSymbol(Kind: EncodeKind::GlobalSymbol, Name: Symbol, Targets,
678 Flags: 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(Size: String.size(), Alignment: 1);
691 memcpy(dest: Ptr, src: String.data(), n: 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(Tag: "!tapi-tbd", Default: false))
711 Ctx->FileKind = FileType::TBD_V4;
712 else if (IO.mapTag(Tag: "!tapi-tbd-v3", Default: false))
713 Ctx->FileKind = FileType::TBD_V3;
714 else if (IO.mapTag(Tag: "!tapi-tbd-v2", Default: false))
715 Ctx->FileKind = FileType::TBD_V2;
716 else if (IO.mapTag(Tag: "!tapi-tbd-v1", Default: false) ||
717 IO.mapTag(Tag: "tag:yaml.org,2002:map", Default: 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(Tag: "!tapi-tbd-v3", Default: true);
753 break;
754 case FileType::TBD_V2:
755 IO.mapTag(Tag: "!tapi-tbd-v2", Default: 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(FileKind: 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(I: Targets.begin(), From: File->targets().begin(),
773 To: 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(Args: it.first);
793
794 for (const auto &it : valueToTargetList) {
795 UmbrellaSection CurrentSection;
796 CurrentSection.Targets.insert(position: CurrentSection.Targets.begin(),
797 first: it.second.begin(), last: it.second.end());
798 CurrentSection.Umbrella = it.first;
799 ParentUmbrellas.emplace_back(args: std::move(CurrentSection));
800 }
801 }
802
803 assignTargetsToLibrary(Libraries: File->allowableClients(), Section&: AllowableClients);
804 assignTargetsToLibrary(Libraries: File->reexportedLibraries(), Section&: 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(args: std::move(Targets));
815 }
816 for (const auto &TargetIDs : TargetSet) {
817 SymbolSection CurrentSection;
818 CurrentSection.Targets.insert(I: CurrentSection.Targets.begin(),
819 From: TargetIDs.begin(), To: 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(args: Symbol->getName());
830 else if (Symbol->isThreadLocalValue())
831 CurrentSection.TlvSymbols.emplace_back(args: Symbol->getName());
832 else
833 CurrentSection.Symbols.emplace_back(args: Symbol->getName());
834 break;
835 case EncodeKind::ObjectiveCClass:
836 CurrentSection.Classes.emplace_back(args: Symbol->getName());
837 break;
838 case EncodeKind::ObjectiveCClassEHType:
839 CurrentSection.ClassEHs.emplace_back(args: Symbol->getName());
840 break;
841 case EncodeKind::ObjectiveCInstanceVariable:
842 CurrentSection.Ivars.emplace_back(args: Symbol->getName());
843 break;
844 }
845 }
846 sort(C&: CurrentSection.Symbols);
847 sort(C&: CurrentSection.Classes);
848 sort(C&: CurrentSection.ClassEHs);
849 sort(C&: CurrentSection.Ivars);
850 sort(C&: CurrentSection.WeakSymbols);
851 sort(C&: CurrentSection.TlvSymbols);
852 CurrentSections.emplace_back(args: 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_: target, Parent: 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(InstallName: 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(InstallName: 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(Kind: EncodeKind::GlobalSymbol, Name: sym,
904 Targets: CurrentSection.Targets, Flags: Flag);
905
906 for (auto &sym : CurrentSection.Classes)
907 File->addSymbol(Kind: EncodeKind::ObjectiveCClass, Name: sym,
908 Targets: CurrentSection.Targets, Flags: Flag);
909
910 for (auto &sym : CurrentSection.ClassEHs)
911 File->addSymbol(Kind: EncodeKind::ObjectiveCClassEHType, Name: sym,
912 Targets: CurrentSection.Targets, Flags: Flag);
913
914 for (auto &sym : CurrentSection.Ivars)
915 File->addSymbol(Kind: EncodeKind::ObjectiveCInstanceVariable, Name: sym,
916 Targets: CurrentSection.Targets, Flags: 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(Kind: EncodeKind::GlobalSymbol, Name: sym,
924 Targets: CurrentSection.Targets, Flags: Flag | SymFlag);
925 }
926
927 for (auto &sym : CurrentSection.TlvSymbols)
928 File->addSymbol(Kind: EncodeKind::GlobalSymbol, Name: sym,
929 Targets: CurrentSection.Targets,
930 Flags: 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(args: std::move(targets));
965 }
966
967 for (const auto &targets : targetSet) {
968 MetadataSection CurrentSection;
969 CurrentSection.Targets.insert(position: CurrentSection.Targets.begin(),
970 first: targets.begin(), last: targets.end());
971
972 for (const auto &it : valueToTargetList) {
973 if (it.second != targets)
974 continue;
975
976 CurrentSection.Values.emplace_back(args: it.first->getInstallName());
977 }
978 llvm::sort(C&: CurrentSection.Values);
979 Section.emplace_back(args: 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(Key: "archs", Val&: Keys->Architectures);
989 if (FileKind != FileType::TBD_V1)
990 IO.mapOptional(Key: "uuids", Val&: EmptyUUID);
991 IO.mapRequired(Key: "platform", Val&: Keys->Platforms);
992 if (FileKind != FileType::TBD_V1)
993 IO.mapOptional(Key: "flags", Val&: Keys->Flags, Default: TBDFlags::None);
994 IO.mapRequired(Key: "install-name", Val&: Keys->InstallName);
995 IO.mapOptional(Key: "current-version", Val&: Keys->CurrentVersion,
996 Default: PackedVersion(1, 0, 0));
997 IO.mapOptional(Key: "compatibility-version", Val&: Keys->CompatibilityVersion,
998 Default: PackedVersion(1, 0, 0));
999 if (FileKind != FileType::TBD_V3)
1000 IO.mapOptional(Key: "swift-version", Val&: Keys->SwiftABIVersion, Default: SwiftVersion(0));
1001 else
1002 IO.mapOptional(Key: "swift-abi-version", Val&: Keys->SwiftABIVersion,
1003 Default: SwiftVersion(0));
1004 IO.mapOptional(Key: "objc-constraint", Val&: Keys->ObjCConstraint,
1005 Default: (FileKind == FileType::TBD_V1)
1006 ? ObjCConstraintType::None
1007 : ObjCConstraintType::Retain_Release);
1008 if (FileKind != FileType::TBD_V1)
1009 IO.mapOptional(Key: "parent-umbrella", Val&: Keys->ParentUmbrella, Default: StringRef());
1010 IO.mapOptional(Key: "exports", Val&: Keys->Exports);
1011 if (FileKind != FileType::TBD_V1)
1012 IO.mapOptional(Key: "undefineds", Val&: 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(Tag: "!tapi-tbd", Default: true);
1020 IO.mapRequired(Key: "tbd-version", Val&: Keys->TBDVersion);
1021 IO.mapRequired(Key: "targets", Val&: Keys->Targets);
1022 IO.mapOptional(Key: "uuids", Val&: EmptyUUID);
1023 IO.mapOptional(Key: "flags", Val&: Keys->Flags, Default: TBDFlags::None);
1024 IO.mapRequired(Key: "install-name", Val&: Keys->InstallName);
1025 IO.mapOptional(Key: "current-version", Val&: Keys->CurrentVersion,
1026 Default: PackedVersion(1, 0, 0));
1027 IO.mapOptional(Key: "compatibility-version", Val&: Keys->CompatibilityVersion,
1028 Default: PackedVersion(1, 0, 0));
1029 IO.mapOptional(Key: "swift-abi-version", Val&: Keys->SwiftABIVersion, Default: SwiftVersion(0));
1030 IO.mapOptional(Key: "parent-umbrella", Val&: Keys->ParentUmbrellas);
1031 auto OptionKind = MetadataSection::Option::Clients;
1032 IO.mapOptionalWithContext(Key: "allowable-clients", Val&: Keys->AllowableClients,
1033 Ctx&: OptionKind);
1034 OptionKind = MetadataSection::Option::Libraries;
1035 IO.mapOptionalWithContext(Key: "reexported-libraries", Val&: Keys->ReexportedLibraries,
1036 Ctx&: OptionKind);
1037 IO.mapOptional(Key: "exports", Val&: Keys->Exports);
1038 IO.mapOptional(Key: "reexports", Val&: Keys->Reexports);
1039 IO.mapOptional(Key: "undefineds", Val&: Keys->Undefineds);
1040 }
1041};
1042
1043template <>
1044struct 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(new_size: Index + 1);
1052 return Seq[Index];
1053 }
1054};
1055
1056} // end namespace yaml.
1057} // namespace llvm
1058
1059static 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(ProgName: nullptr, S);
1070 File->ErrorMessage = ("malformed file\n" + Message).str();
1071}
1072
1073Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) {
1074 auto TAPIFile = InputBuffer.getBuffer().trim();
1075 if (TAPIFile.starts_with(Prefix: "{") && TAPIFile.ends_with(Suffix: "}"))
1076 return FileType::TBD_V5;
1077
1078 if (!TAPIFile.ends_with(Suffix: "..."))
1079 return createStringError(EC: std::errc::not_supported, Fmt: "unsupported file type");
1080
1081 if (TAPIFile.starts_with(Prefix: "--- !tapi-tbd"))
1082 return FileType::TBD_V4;
1083
1084 if (TAPIFile.starts_with(Prefix: "--- !tapi-tbd-v3"))
1085 return FileType::TBD_V3;
1086
1087 if (TAPIFile.starts_with(Prefix: "--- !tapi-tbd-v2"))
1088 return FileType::TBD_V2;
1089
1090 if (TAPIFile.starts_with(Prefix: "--- !tapi-tbd-v1") ||
1091 TAPIFile.starts_with(Prefix: "---\narchs:"))
1092 return FileType::TBD_V1;
1093
1094 return createStringError(EC: std::errc::not_supported, Fmt: "unsupported file type");
1095}
1096
1097Expected<std::unique_ptr<InterfaceFile>>
1098TextAPIReader::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(JSON: 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(RangeOrContainer&: Files))
1127 File->addDocument(
1128 Document: std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI)));
1129
1130 if (YAMLIn.error())
1131 return make_error<StringError>(Args&: Ctx.ErrorMessage, Args: YAMLIn.error());
1132
1133 return std::move(File);
1134}
1135
1136Error 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, FileKind: 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(args: &File);
1155
1156 for (const auto &Document : File.documents())
1157 Files.emplace_back(args: Document.get());
1158
1159 // Stream out yaml.
1160 YAMLOut << Files;
1161
1162 return Error::success();
1163}
1164