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