1 //===- TextStubV5.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 Text Stub JSON mappings.
10 //
11 //===----------------------------------------------------------------------===//
12 #include "TextStubCommon.h"
13 #include "llvm/ADT/StringSwitch.h"
14 #include "llvm/Support/JSON.h"
15 #include <utility>
16 
17 // clang-format off
18 /*
19 
20 JSON Format specification.
21 
22 All library level keys, accept target values and are defaulted if not specified.
23 
24 {
25 "tapi_tbd_version": 5,                            # Required: TBD version for all documents in file
26 "main_library": {                                 # Required: top level library
27   "target_info": [                                # Required: target information
28     {
29       "target": "x86_64-macos",
30       "min_deployment": "10.14"                   # Required: minimum OS deployment version
31     },
32     {
33       "target": "arm64-macos",
34       "min_deployment": "10.14"
35     },
36     {
37       "target": "arm64-maccatalyst",
38       "min_deployment": "12.1"
39     }],
40   "flags":[{"attributes": ["flat_namespace"]}],     # Optional:
41   "install_names":[{"name":"/S/L/F/Foo.fwk/Foo"}],  # Required: library install name
42   "current_versions":[{"version": "1.2"}],          # Optional: defaults to 1
43   "compatibility_versions":[{ "version": "1.1"}],   # Optional: defaults to 1
44   "rpaths": [                                       # Optional:
45     {
46       "targets": ["x86_64-macos"],                  # Optional: defaults to targets in `target-info`
47       "paths": ["@executable_path/.../Frameworks"]
48     }],
49   "parent_umbrellas": [{"umbrella": "System"}],
50   "allowable_clients": [{"clients": ["ClientA"]}],
51   "reexported_libraries": [{"names": ["/u/l/l/foo.dylib"]}],
52   "exported_symbols": [{                            # List of export symbols section
53       "targets": ["x86_64-macos", "arm64-macos"],   # Optional: defaults to targets in `target-info`
54         "text": {                                   # List of Text segment symbols
55           "global": [ "_func" ],
56           "weak": [],
57           "thread_local": []
58         },
59         "data": { ... },                            # List of Data segment symbols
60    }],
61   "reexported_symbols": [{  ... }],                 # List of reexported symbols section
62   "undefined_symbols": [{ ... }]                    # List of undefined symbols section
63 },
64 "libraries": [                                      # Optional: Array of inlined libraries
65   {...}, {...}, {...}
66 ]
67 }
68 */
69 // clang-format on
70 
71 using namespace llvm;
72 using namespace llvm::json;
73 using namespace llvm::MachO;
74 
75 namespace {
76 struct JSONSymbol {
77   SymbolKind Kind;
78   std::string Name;
79   SymbolFlags Flags;
80 };
81 
82 using AttrToTargets = std::map<std::string, TargetList>;
83 using TargetsToSymbols =
84     SmallVector<std::pair<TargetList, std::vector<JSONSymbol>>>;
85 
86 enum TBDKey : size_t {
87   TBDVersion = 0U,
88   MainLibrary,
89   Documents,
90   TargetInfo,
91   Targets,
92   Target,
93   Deployment,
94   Flags,
95   Attributes,
96   InstallName,
97   CurrentVersion,
98   CompatibilityVersion,
99   Version,
100   SwiftABI,
101   ABI,
102   ParentUmbrella,
103   Umbrella,
104   AllowableClients,
105   Clients,
106   ReexportLibs,
107   Names,
108   Name,
109   Exports,
110   Reexports,
111   Undefineds,
112   Data,
113   Text,
114   Weak,
115   ThreadLocal,
116   Globals,
117   ObjCClass,
118   ObjCEHType,
119   ObjCIvar,
120   RPath,
121   Paths,
122 };
123 
124 std::array<StringRef, 64> Keys = {
125     "tapi_tbd_version",
126     "main_library",
127     "libraries",
128     "target_info",
129     "targets",
130     "target",
131     "min_deployment",
132     "flags",
133     "attributes",
134     "install_names",
135     "current_versions",
136     "compatibility_versions",
137     "version",
138     "swift_abi",
139     "abi",
140     "parent_umbrellas",
141     "umbrella",
142     "allowable_clients",
143     "clients",
144     "reexported_libraries",
145     "names",
146     "name",
147     "exported_symbols",
148     "reexported_symbols",
149     "undefined_symbols",
150     "data",
151     "text",
152     "weak",
153     "thread_local",
154     "global",
155     "objc_class",
156     "objc_eh_type",
157     "objc_ivar",
158     "rpaths",
159     "paths",
160 };
161 
162 static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) {
163   return {"invalid ", Keys[Key], " section"};
164 }
165 
166 static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) {
167   return {"missing ", Keys[Key], " information"};
168 }
169 
170 class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {
171 public:
172   JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {}
173 
174   void log(llvm::raw_ostream &OS) const override { OS << Message << "\n"; }
175   std::error_code convertToErrorCode() const override {
176     return llvm::inconvertibleErrorCode();
177   }
178 
179 private:
180   std::string Message;
181 };
182 
183 template <typename JsonT, typename StubT = JsonT>
184 Expected<StubT> getRequiredValue(
185     TBDKey Key, const Object *Obj,
186     std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
187     std::function<std::optional<StubT>(JsonT)> Validate = nullptr) {
188   std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
189   if (!Val)
190     return make_error<JSONStubError>(getParseErrorMsg(Key));
191 
192   if (Validate == nullptr)
193     return static_cast<StubT>(*Val);
194 
195   std::optional<StubT> Result = Validate(*Val);
196   if (!Result.has_value())
197     return make_error<JSONStubError>(getParseErrorMsg(Key));
198   return Result.value();
199 }
200 
201 template <typename JsonT, typename StubT = JsonT>
202 Expected<StubT> getRequiredValue(
203     TBDKey Key, const Object *Obj,
204     std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
205     StubT DefaultValue, std::function<std::optional<StubT>(JsonT)> Validate) {
206   std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
207   if (!Val)
208     return DefaultValue;
209 
210   std::optional<StubT> Result;
211   Result = Validate(*Val);
212   if (!Result.has_value())
213     return make_error<JSONStubError>(getParseErrorMsg(Key));
214   return Result.value();
215 }
216 
217 Error collectFromArray(TBDKey Key, const Object *Obj,
218                        std::function<void(StringRef)> Append,
219                        bool IsRequired = false) {
220   const auto *Values = Obj->getArray(Keys[Key]);
221   if (!Values) {
222     if (IsRequired)
223       return make_error<JSONStubError>(getParseErrorMsg(Key));
224     return Error::success();
225   }
226 
227   for (const Value &Val : *Values) {
228     auto ValStr = Val.getAsString();
229     if (!ValStr.has_value())
230       return make_error<JSONStubError>(getParseErrorMsg(Key));
231     Append(ValStr.value());
232   }
233 
234   return Error::success();
235 }
236 
237 namespace StubParser {
238 
239 Expected<FileType> getVersion(const Object *File) {
240   auto VersionOrErr = getRequiredValue<int64_t, FileType>(
241       TBDKey::TBDVersion, File, &Object::getInteger,
242       [](int64_t Val) -> std::optional<FileType> {
243         unsigned Result = Val;
244         if (Result != 5)
245           return std::nullopt;
246         return FileType::TBD_V5;
247       });
248 
249   if (!VersionOrErr)
250     return VersionOrErr.takeError();
251   return *VersionOrErr;
252 }
253 
254 Expected<TargetList> getTargets(const Object *Section) {
255   const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);
256   if (!Targets)
257     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
258 
259   TargetList IFTargets;
260   for (const Value &JSONTarget : *Targets) {
261     auto TargetStr = JSONTarget.getAsString();
262     if (!TargetStr.has_value())
263       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
264     auto TargetOrErr = Target::create(TargetStr.value());
265     if (!TargetOrErr)
266       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
267     IFTargets.push_back(*TargetOrErr);
268   }
269   return std::move(IFTargets);
270 }
271 
272 Expected<TargetList> getTargetsSection(const Object *Section) {
273   const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);
274   if (!Targets)
275     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
276 
277   TargetList IFTargets;
278   for (const Value &JSONTarget : *Targets) {
279     const auto *Obj = JSONTarget.getAsObject();
280     if (!Obj)
281       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
282     auto TargetStr =
283         getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);
284     if (!TargetStr)
285       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
286     auto VersionStr = getRequiredValue<StringRef>(TBDKey::Deployment, Obj,
287                                                   &Object::getString);
288     if (!VersionStr)
289       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
290     VersionTuple Version;
291     if (Version.tryParse(*VersionStr))
292       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
293     auto TargetOrErr = Target::create(*TargetStr);
294     if (!TargetOrErr)
295       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
296     TargetOrErr->MinDeployment = Version;
297     // Convert to LLVM::Triple to accurately compute minOS + platform + arch
298     // pairing.
299     IFTargets.push_back(
300         MachO::Target(Triple(getTargetTripleName(*TargetOrErr))));
301   }
302   return std::move(IFTargets);
303 }
304 
305 Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result,
306                                 SymbolFlags SectionFlag) {
307   auto Err = collectFromArray(
308       TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {
309         JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), SectionFlag};
310         Result.back().second.emplace_back(Sym);
311       });
312   if (Err)
313     return Err;
314 
315   Err = collectFromArray(
316       TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {
317         JSONSymbol Sym = {SymbolKind::ObjectiveCClass, Name.str(), SectionFlag};
318         Result.back().second.emplace_back(Sym);
319       });
320   if (Err)
321     return Err;
322 
323   Err = collectFromArray(TBDKey::ObjCEHType, Segment,
324                          [&Result, &SectionFlag](StringRef Name) {
325                            JSONSymbol Sym = {SymbolKind::ObjectiveCClassEHType,
326                                              Name.str(), SectionFlag};
327                            Result.back().second.emplace_back(Sym);
328                          });
329   if (Err)
330     return Err;
331 
332   Err = collectFromArray(
333       TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {
334         JSONSymbol Sym = {SymbolKind::ObjectiveCInstanceVariable, Name.str(),
335                           SectionFlag};
336         Result.back().second.emplace_back(Sym);
337       });
338   if (Err)
339     return Err;
340 
341   SymbolFlags WeakFlag =
342       SectionFlag |
343       (((SectionFlag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
344            ? SymbolFlags::WeakReferenced
345            : SymbolFlags::WeakDefined);
346   Err = collectFromArray(
347       TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {
348         JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), WeakFlag};
349         Result.back().second.emplace_back(Sym);
350       });
351   if (Err)
352     return Err;
353 
354   Err = collectFromArray(
355       TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {
356         JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(),
357                           SymbolFlags::ThreadLocalValue | SectionFlag};
358         Result.back().second.emplace_back(Sym);
359       });
360   if (Err)
361     return Err;
362 
363   return Error::success();
364 }
365 
366 Expected<StringRef> getNameSection(const Object *File) {
367   const Array *Section = File->getArray(Keys[TBDKey::InstallName]);
368   if (!Section)
369     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
370 
371   assert(!Section->empty() && "unexpected missing install name");
372   // TODO: Just take first for now.
373   const auto *Obj = Section->front().getAsObject();
374   if (!Obj)
375     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
376 
377   return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);
378 }
379 
380 Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,
381                                             TargetList &Targets) {
382 
383   const Array *Section = File->getArray(Keys[Key]);
384   if (!Section)
385     return TargetsToSymbols();
386 
387   SymbolFlags SectionFlag;
388   switch (Key) {
389   case TBDKey::Reexports:
390     SectionFlag = SymbolFlags::Rexported;
391     break;
392   case TBDKey::Undefineds:
393     SectionFlag = SymbolFlags::Undefined;
394     break;
395   default:
396     SectionFlag = SymbolFlags::None;
397     break;
398   };
399 
400   TargetsToSymbols Result;
401   TargetList MappedTargets;
402   for (auto Val : *Section) {
403     auto *Obj = Val.getAsObject();
404     if (!Obj)
405       continue;
406 
407     auto TargetsOrErr = getTargets(Obj);
408     if (!TargetsOrErr) {
409       MappedTargets = Targets;
410       consumeError(TargetsOrErr.takeError());
411     } else {
412       MappedTargets = *TargetsOrErr;
413     }
414     Result.emplace_back(
415         std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));
416 
417     auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);
418     auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);
419     // There should be at least one valid section.
420     if (!DataSection && !TextSection)
421       return make_error<JSONStubError>(getParseErrorMsg(Key));
422 
423     if (DataSection) {
424       auto Err = collectSymbolsFromSegment(DataSection, Result,
425                                            SectionFlag | SymbolFlags::Data);
426       if (Err)
427         return std::move(Err);
428     }
429     if (TextSection) {
430       auto Err = collectSymbolsFromSegment(TextSection, Result,
431                                            SectionFlag | SymbolFlags::Text);
432       if (Err)
433         return std::move(Err);
434     }
435   }
436 
437   return std::move(Result);
438 }
439 
440 Expected<AttrToTargets> getLibSection(const Object *File, TBDKey Key,
441                                       TBDKey SubKey,
442                                       const TargetList &Targets) {
443   auto *Section = File->getArray(Keys[Key]);
444   if (!Section)
445     return AttrToTargets();
446 
447   AttrToTargets Result;
448   TargetList MappedTargets;
449   for (auto Val : *Section) {
450     auto *Obj = Val.getAsObject();
451     if (!Obj)
452       continue;
453 
454     auto TargetsOrErr = getTargets(Obj);
455     if (!TargetsOrErr) {
456       MappedTargets = Targets;
457       consumeError(TargetsOrErr.takeError());
458     } else {
459       MappedTargets = *TargetsOrErr;
460     }
461     auto Err =
462         collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {
463           Result[Key.str()] = MappedTargets;
464         });
465     if (Err)
466       return std::move(Err);
467   }
468 
469   return std::move(Result);
470 }
471 
472 Expected<AttrToTargets> getUmbrellaSection(const Object *File,
473                                            const TargetList &Targets) {
474   const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);
475   if (!Umbrella)
476     return AttrToTargets();
477 
478   AttrToTargets Result;
479   TargetList MappedTargets;
480   for (auto Val : *Umbrella) {
481     auto *Obj = Val.getAsObject();
482     if (!Obj)
483       return make_error<JSONStubError>(
484           getParseErrorMsg(TBDKey::ParentUmbrella));
485 
486     // Get Targets section.
487     auto TargetsOrErr = getTargets(Obj);
488     if (!TargetsOrErr) {
489       MappedTargets = Targets;
490       consumeError(TargetsOrErr.takeError());
491     } else {
492       MappedTargets = *TargetsOrErr;
493     }
494 
495     auto UmbrellaOrErr =
496         getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);
497     if (!UmbrellaOrErr)
498       return UmbrellaOrErr.takeError();
499     Result[UmbrellaOrErr->str()] = Targets;
500   }
501   return std::move(Result);
502 }
503 
504 Expected<uint8_t> getSwiftVersion(const Object *File) {
505   const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);
506   if (!Versions)
507     return 0;
508 
509   for (const auto &Val : *Versions) {
510     const auto *Obj = Val.getAsObject();
511     if (!Obj)
512       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));
513 
514     // TODO: Take first for now.
515     return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,
516                                               &Object::getInteger);
517   }
518 
519   return 0;
520 }
521 
522 Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) {
523   const Array *Versions = File->getArray(Keys[Key]);
524   if (!Versions)
525     return PackedVersion(1, 0, 0);
526 
527   for (const auto &Val : *Versions) {
528     const auto *Obj = Val.getAsObject();
529     if (!Obj)
530       return make_error<JSONStubError>(getParseErrorMsg(Key));
531 
532     auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {
533       PackedVersion PV;
534       auto [success, truncated] = PV.parse64(Version);
535       if (!success || truncated)
536         return std::nullopt;
537       return PV;
538     };
539     // TODO: Take first for now.
540     return getRequiredValue<StringRef, PackedVersion>(
541         TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),
542         ValidatePV);
543   }
544 
545   return PackedVersion(1, 0, 0);
546 }
547 
548 Expected<TBDFlags> getFlags(const Object *File) {
549   TBDFlags Flags = TBDFlags::None;
550   const Array *Section = File->getArray(Keys[TBDKey::Flags]);
551   if (!Section)
552     return Flags;
553 
554   for (auto &Val : *Section) {
555     // TODO: Just take first for now.
556     const auto *Obj = Val.getAsObject();
557     if (!Obj)
558       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));
559 
560     auto FlagsOrErr =
561         collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {
562           TBDFlags TBDFlag =
563               StringSwitch<TBDFlags>(Flag)
564                   .Case("flat_namespace", TBDFlags::FlatNamespace)
565                   .Case("not_app_extension_safe",
566                         TBDFlags::NotApplicationExtensionSafe)
567                   .Default(TBDFlags::None);
568           Flags |= TBDFlag;
569         });
570 
571     if (FlagsOrErr)
572       return std::move(FlagsOrErr);
573 
574     return Flags;
575   }
576 
577   return Flags;
578 }
579 
580 using IFPtr = std::unique_ptr<InterfaceFile>;
581 Expected<IFPtr> parseToInterfaceFile(const Object *File) {
582   auto TargetsOrErr = getTargetsSection(File);
583   if (!TargetsOrErr)
584     return TargetsOrErr.takeError();
585   TargetList Targets = *TargetsOrErr;
586 
587   auto NameOrErr = getNameSection(File);
588   if (!NameOrErr)
589     return NameOrErr.takeError();
590   StringRef Name = *NameOrErr;
591 
592   auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);
593   if (!CurrVersionOrErr)
594     return CurrVersionOrErr.takeError();
595   PackedVersion CurrVersion = *CurrVersionOrErr;
596 
597   auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);
598   if (!CompVersionOrErr)
599     return CompVersionOrErr.takeError();
600   PackedVersion CompVersion = *CompVersionOrErr;
601 
602   auto SwiftABIOrErr = getSwiftVersion(File);
603   if (!SwiftABIOrErr)
604     return SwiftABIOrErr.takeError();
605   uint8_t SwiftABI = *SwiftABIOrErr;
606 
607   auto FlagsOrErr = getFlags(File);
608   if (!FlagsOrErr)
609     return FlagsOrErr.takeError();
610   TBDFlags Flags = *FlagsOrErr;
611 
612   auto UmbrellasOrErr = getUmbrellaSection(File, Targets);
613   if (!UmbrellasOrErr)
614     return UmbrellasOrErr.takeError();
615   AttrToTargets Umbrellas = *UmbrellasOrErr;
616 
617   auto ClientsOrErr =
618       getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);
619   if (!ClientsOrErr)
620     return ClientsOrErr.takeError();
621   AttrToTargets Clients = *ClientsOrErr;
622 
623   auto RLOrErr =
624       getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);
625   if (!RLOrErr)
626     return RLOrErr.takeError();
627   AttrToTargets ReexportLibs = std::move(*RLOrErr);
628 
629   auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);
630   if (!RPathsOrErr)
631     return RPathsOrErr.takeError();
632   AttrToTargets RPaths = std::move(*RPathsOrErr);
633 
634   auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
635   if (!ExportsOrErr)
636     return ExportsOrErr.takeError();
637   TargetsToSymbols Exports = std::move(*ExportsOrErr);
638 
639   auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);
640   if (!ReexportsOrErr)
641     return ReexportsOrErr.takeError();
642   TargetsToSymbols Reexports = std::move(*ReexportsOrErr);
643 
644   auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);
645   if (!UndefinedsOrErr)
646     return UndefinedsOrErr.takeError();
647   TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);
648 
649   IFPtr F(new InterfaceFile);
650   F->setInstallName(Name);
651   F->setCurrentVersion(CurrVersion);
652   F->setCompatibilityVersion(CompVersion);
653   F->setSwiftABIVersion(SwiftABI);
654   F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
655   F->setApplicationExtensionSafe(
656       !(Flags & TBDFlags::NotApplicationExtensionSafe));
657   for (auto &T : Targets)
658     F->addTarget(T);
659   for (auto &[Lib, Targets] : Clients)
660     for (auto Target : Targets)
661       F->addAllowableClient(Lib, Target);
662   for (auto &[Lib, Targets] : ReexportLibs)
663     for (auto Target : Targets)
664       F->addReexportedLibrary(Lib, Target);
665   for (auto &[Lib, Targets] : Umbrellas)
666     for (auto Target : Targets)
667       F->addParentUmbrella(Target, Lib);
668   for (auto &[Path, Targets] : RPaths)
669     for (auto Target : Targets)
670       F->addRPath(Target, Path);
671   for (auto &[Targets, Symbols] : Exports)
672     for (auto &Sym : Symbols)
673       F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
674   for (auto &[Targets, Symbols] : Reexports)
675     for (auto &Sym : Symbols)
676       F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
677   for (auto &[Targets, Symbols] : Undefineds)
678     for (auto &Sym : Symbols)
679       F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
680 
681   return std::move(F);
682 }
683 
684 Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {
685   std::vector<IFPtr> IFs;
686   const Array *Files = File->getArray(Keys[TBDKey::Documents]);
687   if (!Files)
688     return std::move(IFs);
689 
690   for (auto Lib : *Files) {
691     auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());
692     if (!IFOrErr)
693       return IFOrErr.takeError();
694     auto IF = std::move(*IFOrErr);
695     IFs.emplace_back(std::move(IF));
696   }
697   return std::move(IFs);
698 }
699 
700 } // namespace StubParser
701 } // namespace
702 
703 Expected<std::unique_ptr<InterfaceFile>>
704 MachO::getInterfaceFileFromJSON(StringRef JSON) {
705   auto ValOrErr = parse(JSON);
706   if (!ValOrErr)
707     return ValOrErr.takeError();
708 
709   auto *Root = ValOrErr->getAsObject();
710   auto VersionOrErr = StubParser::getVersion(Root);
711   if (!VersionOrErr)
712     return VersionOrErr.takeError();
713   FileType Version = *VersionOrErr;
714 
715   Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);
716   auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);
717   if (!IFOrErr)
718     return IFOrErr.takeError();
719   (*IFOrErr)->setFileType(Version);
720   std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));
721 
722   auto IFsOrErr = StubParser::getInlinedLibs(Root);
723   if (!IFsOrErr)
724     return IFsOrErr.takeError();
725   for (auto &File : *IFsOrErr) {
726     File->setFileType(Version);
727     IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));
728   }
729   return std::move(IF);
730 }
731 
732 namespace {
733 
734 template <typename ContainerT = Array>
735 bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
736   if (Contents.empty())
737     return false;
738   Obj[Keys[Key]] = std::move(Contents);
739   return true;
740 }
741 
742 std::string getFormattedStr(const MachO::Target &Targ) {
743   std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
744                                 ? "maccatalyst"
745                                 : getOSAndEnvironmentName(Targ.Platform);
746   return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
747 }
748 
749 template <typename AggregateT>
750 std::vector<std::string> serializeTargets(const AggregateT Targets,
751                                           const TargetList &ActiveTargets) {
752   std::vector<std::string> TargetsStr;
753   if (Targets.size() == ActiveTargets.size())
754     return TargetsStr;
755 
756   llvm::for_each(Targets, [&TargetsStr](const MachO::Target &Target) {
757     TargetsStr.emplace_back(getFormattedStr(Target));
758   });
759   return TargetsStr;
760 }
761 
762 Array serializeTargetInfo(const TargetList &ActiveTargets) {
763   Array Targets;
764   for (const auto Targ : ActiveTargets) {
765     Object TargetInfo;
766     TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();
767     TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
768     Targets.emplace_back(std::move(TargetInfo));
769   }
770   return Targets;
771 }
772 
773 template <typename ValueT, typename EntryT = ValueT>
774 Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
775   if (Value == Default)
776     return {};
777   Array Container;
778   Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
779 
780   Container.emplace_back(std::move(ScalarObj));
781   return Container;
782 }
783 
784 using TargetsToValuesMap =
785     std::map<std::vector<std::string>, std::vector<std::string>>;
786 
787 template <typename AggregateT = TargetsToValuesMap>
788 Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
789   Array Container;
790   for (const auto &[Targets, Values] : Entries) {
791     Object Obj;
792     insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
793     Obj[Keys[Key]] = Values;
794     Container.emplace_back(std::move(Obj));
795   }
796   return Container;
797 }
798 
799 template <typename ValueT = std::string,
800           typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
801 Array serializeField(TBDKey Key, const AggregateT &Values,
802                      const TargetList &ActiveTargets, bool IsArray = true) {
803   std::map<ValueT, std::set<MachO::Target>> Entries;
804   for (const auto &[Target, Val] : Values)
805     Entries[Val].insert(Target);
806 
807   if (!IsArray) {
808     std::map<std::vector<std::string>, std::string> FinalEntries;
809     for (const auto &[Val, Targets] : Entries)
810       FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
811     return serializeAttrToTargets(FinalEntries, Key);
812   }
813 
814   TargetsToValuesMap FinalEntries;
815   for (const auto &[Val, Targets] : Entries)
816     FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
817   return serializeAttrToTargets(FinalEntries, Key);
818 }
819 
820 Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
821                      const TargetList &ActiveTargets) {
822   TargetsToValuesMap FinalEntries;
823   for (const auto &Ref : Values) {
824     TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
825     FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
826         Ref.getInstallName());
827   }
828   return serializeAttrToTargets(FinalEntries, Key);
829 }
830 
831 struct SymbolFields {
832   struct SymbolTypes {
833     std::vector<StringRef> Weaks;
834     std::vector<StringRef> Globals;
835     std::vector<StringRef> TLV;
836     std::vector<StringRef> ObjCClasses;
837     std::vector<StringRef> IVars;
838     std::vector<StringRef> EHTypes;
839 
840     bool empty() const {
841       return Weaks.empty() && Globals.empty() && TLV.empty() &&
842              ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
843     }
844   };
845   SymbolTypes Data;
846   SymbolTypes Text;
847 };
848 
849 Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,
850                        const TargetList &ActiveTargets) {
851   auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
852                                 const Symbol *Sym) {
853     switch (Sym->getKind()) {
854     case SymbolKind::ObjectiveCClass:
855       Assignment.ObjCClasses.emplace_back(Sym->getName());
856       return;
857     case SymbolKind::ObjectiveCClassEHType:
858       Assignment.EHTypes.emplace_back(Sym->getName());
859       return;
860     case SymbolKind::ObjectiveCInstanceVariable:
861       Assignment.IVars.emplace_back(Sym->getName());
862       return;
863     case SymbolKind::GlobalSymbol: {
864       if (Sym->isWeakReferenced() || Sym->isWeakDefined())
865         Assignment.Weaks.emplace_back(Sym->getName());
866       else if (Sym->isThreadLocalValue())
867         Assignment.TLV.emplace_back(Sym->getName());
868       else
869         Assignment.Globals.emplace_back(Sym->getName());
870       return;
871     }
872     }
873   };
874 
875   std::map<std::vector<std::string>, SymbolFields> Entries;
876   for (const auto *Sym : Symbols) {
877     std::set<MachO::Target> Targets{Sym->targets().begin(),
878                                     Sym->targets().end()};
879     auto JSONTargets = serializeTargets(Targets, ActiveTargets);
880     if (Sym->isData())
881       AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
882     else if (Sym->isText())
883       AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
884     else
885       llvm_unreachable("unexpected symbol type");
886   }
887 
888   auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
889                                 SymbolFields::SymbolTypes &SymField) {
890     if (SymField.empty())
891       return;
892     Object Segment;
893     insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
894     insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
895     insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
896     insertNonEmptyValues(Segment, TBDKey::ObjCClass,
897                          std::move(SymField.ObjCClasses));
898     insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
899                          std::move(SymField.EHTypes));
900     insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
901     insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
902   };
903 
904   Array SymbolSection;
905   for (auto &[Targets, Fields] : Entries) {
906     Object AllSyms;
907     insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
908     InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
909     InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
910     SymbolSection.emplace_back(std::move(AllSyms));
911   }
912 
913   return SymbolSection;
914 }
915 
916 Array serializeFlags(const InterfaceFile *File) {
917   // TODO: Give all Targets the same flags for now.
918   Array Flags;
919   if (!File->isTwoLevelNamespace())
920     Flags.emplace_back("flat_namespace");
921   if (!File->isApplicationExtensionSafe())
922     Flags.emplace_back("not_app_extension_safe");
923   return serializeScalar(TBDKey::Attributes, std::move(Flags));
924 }
925 
926 Expected<Object> serializeIF(const InterfaceFile *File) {
927   Object Library;
928 
929   // Handle required keys.
930   TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
931   if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
932                             serializeTargetInfo(ActiveTargets)))
933     return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
934 
935   Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
936   if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
937     return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
938 
939   // Handle optional keys.
940   Array Flags = serializeFlags(File);
941   insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
942 
943   Array CurrentV = serializeScalar<PackedVersion, std::string>(
944       TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
945   insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
946 
947   Array CompatV = serializeScalar<PackedVersion, std::string>(
948       TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
949   insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
950                        std::move(CompatV));
951 
952   Array SwiftABI = serializeScalar<uint8_t, int64_t>(
953       TBDKey::ABI, File->getSwiftABIVersion(), 0u);
954   insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
955 
956   Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
957   insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
958 
959   Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
960                                    ActiveTargets, /*IsArray=*/false);
961   insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
962 
963   Array Clients =
964       serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
965   insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
966 
967   Array ReexportLibs =
968       serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
969   insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
970 
971   // Handle symbols.
972   Array Exports = serializeSymbols(File->exports(), ActiveTargets);
973   insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
974 
975   Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
976   insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
977 
978   if (!File->isTwoLevelNamespace()) {
979     Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
980     insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
981   }
982 
983   return std::move(Library);
984 }
985 
986 Expected<Object> getJSON(const InterfaceFile *File) {
987   assert(File->getFileType() == FileType::TBD_V5 &&
988          "unexpected json file format version");
989   Object Root;
990 
991   auto MainLibOrErr = serializeIF(File);
992   if (!MainLibOrErr)
993     return MainLibOrErr;
994   Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
995   Array Documents;
996   for (const auto &Doc : File->documents()) {
997     auto LibOrErr = serializeIF(Doc.get());
998     if (!LibOrErr)
999       return LibOrErr;
1000     Documents.emplace_back(std::move(*LibOrErr));
1001   }
1002 
1003   Root[Keys[TBDKey::TBDVersion]] = 5;
1004   insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
1005   return std::move(Root);
1006 }
1007 
1008 } // namespace
1009 
1010 Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,
1011                                           const InterfaceFile &File,
1012                                           bool Compact) {
1013   auto TextFile = getJSON(&File);
1014   if (!TextFile)
1015     return TextFile.takeError();
1016   if (Compact)
1017     OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
1018   else
1019     OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
1020   return Error::success();
1021 }
1022