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;
UUIDv4__anon82be0b210111::UUIDv4257 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> {
mappingllvm::yaml::MappingTraits276 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> {
mappingllvm::yaml::MappingTraits298 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> {
mappingllvm::yaml::MappingTraits314 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> {
mappingllvm::yaml::MappingTraits326 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> {
mappingllvm::yaml::MappingTraits333 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> {
mappingllvm::yaml::MappingContextTraits341 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> {
bitsetllvm::yaml::ScalarBitSetTraits357 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> {
outputllvm::yaml::ScalarTraits368 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
inputllvm::yaml::ScalarTraits380 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
mustQuotellvm::yaml::ScalarTraits396 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
397 };
398
399 template <> struct MappingTraits<const InterfaceFile *> {
400 struct NormalizedTBD {
NormalizedTBDllvm::yaml::MappingTraits::NormalizedTBD401 explicit NormalizedTBD(IO &IO) {}
NormalizedTBDllvm::yaml::MappingTraits::NormalizedTBD402 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.
synthesizeTargetsllvm::yaml::MappingTraits::NormalizedTBD555 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
denormalizellvm::yaml::MappingTraits::NormalizedTBD572 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;
copyStringllvm::yaml::MappingTraits::NormalizedTBD686 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
setFileTypeForInputllvm::yaml::MappingTraits709 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
mappingllvm::yaml::MappingTraits725 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 {
NormalizedTBD_V4llvm::yaml::MappingTraits::NormalizedTBD_V4767 explicit NormalizedTBD_V4(IO &IO) {}
NormalizedTBD_V4llvm::yaml::MappingTraits::NormalizedTBD_V4768 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
denormalizellvm::yaml::MappingTraits::NormalizedTBD_V4861 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:
assignTargetsToLibraryllvm::yaml::MappingTraits::NormalizedTBD_V4957 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
mapKeysToValuesllvm::yaml::MappingTraits984 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
mapKeysToValuesV4llvm::yaml::MappingTraits1015 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 *>> {
sizellvm::yaml::DocumentListTraits1045 static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) {
1046 return Seq.size();
1047 }
1048 static const InterfaceFile *&
elementllvm::yaml::DocumentListTraits1049 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
DiagHandler(const SMDiagnostic & Diag,void * Context)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
canRead(MemoryBufferRef InputBuffer)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>>
get(MemoryBufferRef InputBuffer)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
writeToStream(raw_ostream & OS,const InterfaceFile & File,const FileType FileKind,bool Compact)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