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