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"                   # Optional: minOS defaults to 0
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 TargetOrErr = Target::create(*TargetStr);
287     if (!TargetOrErr)
288       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
289 
290     auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]);
291     VersionTuple Version;
292     if (VersionStr && Version.tryParse(*VersionStr))
293       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
294     TargetOrErr->MinDeployment = Version;
295 
296     // Convert to LLVM::Triple to accurately compute minOS + platform + arch
297     // pairing.
298     IFTargets.push_back(
299         MachO::Target(Triple(getTargetTripleName(*TargetOrErr))));
300   }
301   return std::move(IFTargets);
302 }
303 
304 Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result,
305                                 SymbolFlags SectionFlag) {
306   auto Err = collectFromArray(
307       TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {
308         JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), SectionFlag};
309         Result.back().second.emplace_back(Sym);
310       });
311   if (Err)
312     return Err;
313 
314   Err = collectFromArray(
315       TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {
316         JSONSymbol Sym = {SymbolKind::ObjectiveCClass, Name.str(), SectionFlag};
317         Result.back().second.emplace_back(Sym);
318       });
319   if (Err)
320     return Err;
321 
322   Err = collectFromArray(TBDKey::ObjCEHType, Segment,
323                          [&Result, &SectionFlag](StringRef Name) {
324                            JSONSymbol Sym = {SymbolKind::ObjectiveCClassEHType,
325                                              Name.str(), SectionFlag};
326                            Result.back().second.emplace_back(Sym);
327                          });
328   if (Err)
329     return Err;
330 
331   Err = collectFromArray(
332       TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {
333         JSONSymbol Sym = {SymbolKind::ObjectiveCInstanceVariable, Name.str(),
334                           SectionFlag};
335         Result.back().second.emplace_back(Sym);
336       });
337   if (Err)
338     return Err;
339 
340   SymbolFlags WeakFlag =
341       SectionFlag |
342       (((SectionFlag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
343            ? SymbolFlags::WeakReferenced
344            : SymbolFlags::WeakDefined);
345   Err = collectFromArray(
346       TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {
347         JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), WeakFlag};
348         Result.back().second.emplace_back(Sym);
349       });
350   if (Err)
351     return Err;
352 
353   Err = collectFromArray(
354       TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {
355         JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(),
356                           SymbolFlags::ThreadLocalValue | SectionFlag};
357         Result.back().second.emplace_back(Sym);
358       });
359   if (Err)
360     return Err;
361 
362   return Error::success();
363 }
364 
365 Expected<StringRef> getNameSection(const Object *File) {
366   const Array *Section = File->getArray(Keys[TBDKey::InstallName]);
367   if (!Section)
368     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
369 
370   assert(!Section->empty() && "unexpected missing install name");
371   // TODO: Just take first for now.
372   const auto *Obj = Section->front().getAsObject();
373   if (!Obj)
374     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
375 
376   return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);
377 }
378 
379 Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,
380                                             TargetList &Targets) {
381 
382   const Array *Section = File->getArray(Keys[Key]);
383   if (!Section)
384     return TargetsToSymbols();
385 
386   SymbolFlags SectionFlag;
387   switch (Key) {
388   case TBDKey::Reexports:
389     SectionFlag = SymbolFlags::Rexported;
390     break;
391   case TBDKey::Undefineds:
392     SectionFlag = SymbolFlags::Undefined;
393     break;
394   default:
395     SectionFlag = SymbolFlags::None;
396     break;
397   };
398 
399   TargetsToSymbols Result;
400   TargetList MappedTargets;
401   for (auto Val : *Section) {
402     auto *Obj = Val.getAsObject();
403     if (!Obj)
404       continue;
405 
406     auto TargetsOrErr = getTargets(Obj);
407     if (!TargetsOrErr) {
408       MappedTargets = Targets;
409       consumeError(TargetsOrErr.takeError());
410     } else {
411       MappedTargets = *TargetsOrErr;
412     }
413     Result.emplace_back(
414         std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));
415 
416     auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);
417     auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);
418     // There should be at least one valid section.
419     if (!DataSection && !TextSection)
420       return make_error<JSONStubError>(getParseErrorMsg(Key));
421 
422     if (DataSection) {
423       auto Err = collectSymbolsFromSegment(DataSection, Result,
424                                            SectionFlag | SymbolFlags::Data);
425       if (Err)
426         return std::move(Err);
427     }
428     if (TextSection) {
429       auto Err = collectSymbolsFromSegment(TextSection, Result,
430                                            SectionFlag | SymbolFlags::Text);
431       if (Err)
432         return std::move(Err);
433     }
434   }
435 
436   return std::move(Result);
437 }
438 
439 Expected<AttrToTargets> getLibSection(const Object *File, TBDKey Key,
440                                       TBDKey SubKey,
441                                       const TargetList &Targets) {
442   auto *Section = File->getArray(Keys[Key]);
443   if (!Section)
444     return AttrToTargets();
445 
446   AttrToTargets Result;
447   TargetList MappedTargets;
448   for (auto Val : *Section) {
449     auto *Obj = Val.getAsObject();
450     if (!Obj)
451       continue;
452 
453     auto TargetsOrErr = getTargets(Obj);
454     if (!TargetsOrErr) {
455       MappedTargets = Targets;
456       consumeError(TargetsOrErr.takeError());
457     } else {
458       MappedTargets = *TargetsOrErr;
459     }
460     auto Err =
461         collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {
462           Result[Key.str()] = MappedTargets;
463         });
464     if (Err)
465       return std::move(Err);
466   }
467 
468   return std::move(Result);
469 }
470 
471 Expected<AttrToTargets> getUmbrellaSection(const Object *File,
472                                            const TargetList &Targets) {
473   const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);
474   if (!Umbrella)
475     return AttrToTargets();
476 
477   AttrToTargets Result;
478   TargetList MappedTargets;
479   for (auto Val : *Umbrella) {
480     auto *Obj = Val.getAsObject();
481     if (!Obj)
482       return make_error<JSONStubError>(
483           getParseErrorMsg(TBDKey::ParentUmbrella));
484 
485     // Get Targets section.
486     auto TargetsOrErr = getTargets(Obj);
487     if (!TargetsOrErr) {
488       MappedTargets = Targets;
489       consumeError(TargetsOrErr.takeError());
490     } else {
491       MappedTargets = *TargetsOrErr;
492     }
493 
494     auto UmbrellaOrErr =
495         getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);
496     if (!UmbrellaOrErr)
497       return UmbrellaOrErr.takeError();
498     Result[UmbrellaOrErr->str()] = Targets;
499   }
500   return std::move(Result);
501 }
502 
503 Expected<uint8_t> getSwiftVersion(const Object *File) {
504   const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);
505   if (!Versions)
506     return 0;
507 
508   for (const auto &Val : *Versions) {
509     const auto *Obj = Val.getAsObject();
510     if (!Obj)
511       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));
512 
513     // TODO: Take first for now.
514     return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,
515                                               &Object::getInteger);
516   }
517 
518   return 0;
519 }
520 
521 Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) {
522   const Array *Versions = File->getArray(Keys[Key]);
523   if (!Versions)
524     return PackedVersion(1, 0, 0);
525 
526   for (const auto &Val : *Versions) {
527     const auto *Obj = Val.getAsObject();
528     if (!Obj)
529       return make_error<JSONStubError>(getParseErrorMsg(Key));
530 
531     auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {
532       PackedVersion PV;
533       auto [success, truncated] = PV.parse64(Version);
534       if (!success || truncated)
535         return std::nullopt;
536       return PV;
537     };
538     // TODO: Take first for now.
539     return getRequiredValue<StringRef, PackedVersion>(
540         TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),
541         ValidatePV);
542   }
543 
544   return PackedVersion(1, 0, 0);
545 }
546 
547 Expected<TBDFlags> getFlags(const Object *File) {
548   TBDFlags Flags = TBDFlags::None;
549   const Array *Section = File->getArray(Keys[TBDKey::Flags]);
550   if (!Section || Section->empty())
551     return Flags;
552 
553   for (auto &Val : *Section) {
554     // FIXME: Flags currently apply to all target triples.
555     const auto *Obj = Val.getAsObject();
556     if (!Obj)
557       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));
558 
559     auto FlagsOrErr =
560         collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {
561           TBDFlags TBDFlag =
562               StringSwitch<TBDFlags>(Flag)
563                   .Case("flat_namespace", TBDFlags::FlatNamespace)
564                   .Case("not_app_extension_safe",
565                         TBDFlags::NotApplicationExtensionSafe)
566                   .Case("sim_support", TBDFlags::SimulatorSupport)
567                   .Case("not_for_dyld_shared_cache",
568                         TBDFlags::OSLibNotForSharedCache)
569                   .Default(TBDFlags::None);
570           Flags |= TBDFlag;
571         });
572 
573     if (FlagsOrErr)
574       return std::move(FlagsOrErr);
575 
576     return Flags;
577   }
578 
579   return Flags;
580 }
581 
582 using IFPtr = std::unique_ptr<InterfaceFile>;
583 Expected<IFPtr> parseToInterfaceFile(const Object *File) {
584   auto TargetsOrErr = getTargetsSection(File);
585   if (!TargetsOrErr)
586     return TargetsOrErr.takeError();
587   TargetList Targets = *TargetsOrErr;
588 
589   auto NameOrErr = getNameSection(File);
590   if (!NameOrErr)
591     return NameOrErr.takeError();
592   StringRef Name = *NameOrErr;
593 
594   auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);
595   if (!CurrVersionOrErr)
596     return CurrVersionOrErr.takeError();
597   PackedVersion CurrVersion = *CurrVersionOrErr;
598 
599   auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);
600   if (!CompVersionOrErr)
601     return CompVersionOrErr.takeError();
602   PackedVersion CompVersion = *CompVersionOrErr;
603 
604   auto SwiftABIOrErr = getSwiftVersion(File);
605   if (!SwiftABIOrErr)
606     return SwiftABIOrErr.takeError();
607   uint8_t SwiftABI = *SwiftABIOrErr;
608 
609   auto FlagsOrErr = getFlags(File);
610   if (!FlagsOrErr)
611     return FlagsOrErr.takeError();
612   TBDFlags Flags = *FlagsOrErr;
613 
614   auto UmbrellasOrErr = getUmbrellaSection(File, Targets);
615   if (!UmbrellasOrErr)
616     return UmbrellasOrErr.takeError();
617   AttrToTargets Umbrellas = *UmbrellasOrErr;
618 
619   auto ClientsOrErr =
620       getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);
621   if (!ClientsOrErr)
622     return ClientsOrErr.takeError();
623   AttrToTargets Clients = *ClientsOrErr;
624 
625   auto RLOrErr =
626       getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);
627   if (!RLOrErr)
628     return RLOrErr.takeError();
629   AttrToTargets ReexportLibs = std::move(*RLOrErr);
630 
631   auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);
632   if (!RPathsOrErr)
633     return RPathsOrErr.takeError();
634   AttrToTargets RPaths = std::move(*RPathsOrErr);
635 
636   auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
637   if (!ExportsOrErr)
638     return ExportsOrErr.takeError();
639   TargetsToSymbols Exports = std::move(*ExportsOrErr);
640 
641   auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);
642   if (!ReexportsOrErr)
643     return ReexportsOrErr.takeError();
644   TargetsToSymbols Reexports = std::move(*ReexportsOrErr);
645 
646   auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);
647   if (!UndefinedsOrErr)
648     return UndefinedsOrErr.takeError();
649   TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);
650 
651   IFPtr F(new InterfaceFile);
652   F->setInstallName(Name);
653   F->setCurrentVersion(CurrVersion);
654   F->setCompatibilityVersion(CompVersion);
655   F->setSwiftABIVersion(SwiftABI);
656   F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
657   F->setApplicationExtensionSafe(
658       !(Flags & TBDFlags::NotApplicationExtensionSafe));
659   F->setSimulatorSupport((Flags & TBDFlags::SimulatorSupport));
660   F->setOSLibNotForSharedCache((Flags & TBDFlags::OSLibNotForSharedCache));
661   for (auto &T : Targets)
662     F->addTarget(T);
663   for (auto &[Lib, Targets] : Clients)
664     for (auto Target : Targets)
665       F->addAllowableClient(Lib, Target);
666   for (auto &[Lib, Targets] : ReexportLibs)
667     for (auto Target : Targets)
668       F->addReexportedLibrary(Lib, Target);
669   for (auto &[Lib, Targets] : Umbrellas)
670     for (auto Target : Targets)
671       F->addParentUmbrella(Target, Lib);
672   for (auto &[Path, Targets] : RPaths)
673     for (auto Target : Targets)
674       F->addRPath(Target, Path);
675   for (auto &[Targets, Symbols] : Exports)
676     for (auto &Sym : Symbols)
677       F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
678   for (auto &[Targets, Symbols] : Reexports)
679     for (auto &Sym : Symbols)
680       F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
681   for (auto &[Targets, Symbols] : Undefineds)
682     for (auto &Sym : Symbols)
683       F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
684 
685   return std::move(F);
686 }
687 
688 Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {
689   std::vector<IFPtr> IFs;
690   const Array *Files = File->getArray(Keys[TBDKey::Documents]);
691   if (!Files)
692     return std::move(IFs);
693 
694   for (auto Lib : *Files) {
695     auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());
696     if (!IFOrErr)
697       return IFOrErr.takeError();
698     auto IF = std::move(*IFOrErr);
699     IFs.emplace_back(std::move(IF));
700   }
701   return std::move(IFs);
702 }
703 
704 } // namespace StubParser
705 } // namespace
706 
707 Expected<std::unique_ptr<InterfaceFile>>
708 MachO::getInterfaceFileFromJSON(StringRef JSON) {
709   auto ValOrErr = parse(JSON);
710   if (!ValOrErr)
711     return ValOrErr.takeError();
712 
713   auto *Root = ValOrErr->getAsObject();
714   auto VersionOrErr = StubParser::getVersion(Root);
715   if (!VersionOrErr)
716     return VersionOrErr.takeError();
717   FileType Version = *VersionOrErr;
718 
719   Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);
720   auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);
721   if (!IFOrErr)
722     return IFOrErr.takeError();
723   (*IFOrErr)->setFileType(Version);
724   std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));
725 
726   auto IFsOrErr = StubParser::getInlinedLibs(Root);
727   if (!IFsOrErr)
728     return IFsOrErr.takeError();
729   for (auto &File : *IFsOrErr) {
730     File->setFileType(Version);
731     IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));
732   }
733   return std::move(IF);
734 }
735 
736 namespace {
737 
738 template <typename ContainerT = Array>
739 bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
740   if (Contents.empty())
741     return false;
742   Obj[Keys[Key]] = std::move(Contents);
743   return true;
744 }
745 
746 std::string getFormattedStr(const MachO::Target &Targ) {
747   std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
748                                 ? "maccatalyst"
749                                 : getOSAndEnvironmentName(Targ.Platform);
750   return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
751 }
752 
753 template <typename AggregateT>
754 std::vector<std::string> serializeTargets(const AggregateT Targets,
755                                           const TargetList &ActiveTargets) {
756   std::vector<std::string> TargetsStr;
757   if (Targets.size() == ActiveTargets.size())
758     return TargetsStr;
759 
760   for (const MachO::Target &Target : Targets)
761     TargetsStr.emplace_back(getFormattedStr(Target));
762 
763   return TargetsStr;
764 }
765 
766 Array serializeTargetInfo(const TargetList &ActiveTargets) {
767   Array Targets;
768   for (const auto Targ : ActiveTargets) {
769     Object TargetInfo;
770     if (!Targ.MinDeployment.empty())
771       TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();
772     TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
773     Targets.emplace_back(std::move(TargetInfo));
774   }
775   return Targets;
776 }
777 
778 template <typename ValueT, typename EntryT = ValueT>
779 Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
780   if (Value == Default)
781     return {};
782   Array Container;
783   Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
784 
785   Container.emplace_back(std::move(ScalarObj));
786   return Container;
787 }
788 
789 using TargetsToValuesMap =
790     std::map<std::vector<std::string>, std::vector<std::string>>;
791 
792 template <typename AggregateT = TargetsToValuesMap>
793 Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
794   Array Container;
795   for (const auto &[Targets, Values] : Entries) {
796     Object Obj;
797     insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
798     Obj[Keys[Key]] = Values;
799     Container.emplace_back(std::move(Obj));
800   }
801   return Container;
802 }
803 
804 template <typename ValueT = std::string,
805           typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
806 Array serializeField(TBDKey Key, const AggregateT &Values,
807                      const TargetList &ActiveTargets, bool IsArray = true) {
808   std::map<ValueT, std::set<MachO::Target>> Entries;
809   for (const auto &[Target, Val] : Values)
810     Entries[Val].insert(Target);
811 
812   if (!IsArray) {
813     std::map<std::vector<std::string>, std::string> FinalEntries;
814     for (const auto &[Val, Targets] : Entries)
815       FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
816     return serializeAttrToTargets(FinalEntries, Key);
817   }
818 
819   TargetsToValuesMap FinalEntries;
820   for (const auto &[Val, Targets] : Entries)
821     FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
822   return serializeAttrToTargets(FinalEntries, Key);
823 }
824 
825 Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
826                      const TargetList &ActiveTargets) {
827   TargetsToValuesMap FinalEntries;
828   for (const auto &Ref : Values) {
829     TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
830     FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
831         Ref.getInstallName());
832   }
833   return serializeAttrToTargets(FinalEntries, Key);
834 }
835 
836 struct SymbolFields {
837   struct SymbolTypes {
838     std::vector<StringRef> Weaks;
839     std::vector<StringRef> Globals;
840     std::vector<StringRef> TLV;
841     std::vector<StringRef> ObjCClasses;
842     std::vector<StringRef> IVars;
843     std::vector<StringRef> EHTypes;
844 
845     bool empty() const {
846       return Weaks.empty() && Globals.empty() && TLV.empty() &&
847              ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
848     }
849   };
850   SymbolTypes Data;
851   SymbolTypes Text;
852 };
853 
854 Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,
855                        const TargetList &ActiveTargets) {
856   auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
857                                 const Symbol *Sym) {
858     switch (Sym->getKind()) {
859     case SymbolKind::ObjectiveCClass:
860       Assignment.ObjCClasses.emplace_back(Sym->getName());
861       return;
862     case SymbolKind::ObjectiveCClassEHType:
863       Assignment.EHTypes.emplace_back(Sym->getName());
864       return;
865     case SymbolKind::ObjectiveCInstanceVariable:
866       Assignment.IVars.emplace_back(Sym->getName());
867       return;
868     case SymbolKind::GlobalSymbol: {
869       if (Sym->isWeakReferenced() || Sym->isWeakDefined())
870         Assignment.Weaks.emplace_back(Sym->getName());
871       else if (Sym->isThreadLocalValue())
872         Assignment.TLV.emplace_back(Sym->getName());
873       else
874         Assignment.Globals.emplace_back(Sym->getName());
875       return;
876     }
877     }
878   };
879 
880   std::map<std::vector<std::string>, SymbolFields> Entries;
881   for (const auto *Sym : Symbols) {
882     std::set<MachO::Target> Targets{Sym->targets().begin(),
883                                     Sym->targets().end()};
884     auto JSONTargets = serializeTargets(Targets, ActiveTargets);
885     if (Sym->isData())
886       AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
887     else if (Sym->isText())
888       AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
889     else
890       llvm_unreachable("unexpected symbol type");
891   }
892 
893   auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
894                                 SymbolFields::SymbolTypes &SymField) {
895     if (SymField.empty())
896       return;
897     Object Segment;
898     insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
899     insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
900     insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
901     insertNonEmptyValues(Segment, TBDKey::ObjCClass,
902                          std::move(SymField.ObjCClasses));
903     insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
904                          std::move(SymField.EHTypes));
905     insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
906     insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
907   };
908 
909   Array SymbolSection;
910   for (auto &[Targets, Fields] : Entries) {
911     Object AllSyms;
912     insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
913     InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
914     InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
915     SymbolSection.emplace_back(std::move(AllSyms));
916   }
917 
918   return SymbolSection;
919 }
920 
921 Array serializeFlags(const InterfaceFile *File) {
922   // TODO: Give all Targets the same flags for now.
923   Array Flags;
924   if (!File->isTwoLevelNamespace())
925     Flags.emplace_back("flat_namespace");
926   if (!File->isApplicationExtensionSafe())
927     Flags.emplace_back("not_app_extension_safe");
928   if (File->hasSimulatorSupport())
929     Flags.emplace_back("sim_support");
930   if (File->isOSLibNotForSharedCache())
931     Flags.emplace_back("not_for_dyld_shared_cache");
932   return serializeScalar(TBDKey::Attributes, std::move(Flags));
933 }
934 
935 Expected<Object> serializeIF(const InterfaceFile *File) {
936   Object Library;
937 
938   // Handle required keys.
939   TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
940   if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
941                             serializeTargetInfo(ActiveTargets)))
942     return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
943 
944   Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
945   if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
946     return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
947 
948   // Handle optional keys.
949   Array Flags = serializeFlags(File);
950   insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
951 
952   Array CurrentV = serializeScalar<PackedVersion, std::string>(
953       TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
954   insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
955 
956   Array CompatV = serializeScalar<PackedVersion, std::string>(
957       TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
958   insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
959                        std::move(CompatV));
960 
961   Array SwiftABI = serializeScalar<uint8_t, int64_t>(
962       TBDKey::ABI, File->getSwiftABIVersion(), 0u);
963   insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
964 
965   Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
966   insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
967 
968   Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
969                                    ActiveTargets, /*IsArray=*/false);
970   insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
971 
972   Array Clients =
973       serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
974   insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
975 
976   Array ReexportLibs =
977       serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
978   insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
979 
980   // Handle symbols.
981   Array Exports = serializeSymbols(File->exports(), ActiveTargets);
982   insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
983 
984   Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
985   insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
986 
987   if (!File->isTwoLevelNamespace()) {
988     Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
989     insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
990   }
991 
992   return std::move(Library);
993 }
994 
995 Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {
996   assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");
997   Object Root;
998 
999   auto MainLibOrErr = serializeIF(File);
1000   if (!MainLibOrErr)
1001     return MainLibOrErr;
1002   Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
1003   Array Documents;
1004   for (const auto &Doc : File->documents()) {
1005     auto LibOrErr = serializeIF(Doc.get());
1006     if (!LibOrErr)
1007       return LibOrErr;
1008     Documents.emplace_back(std::move(*LibOrErr));
1009   }
1010 
1011   Root[Keys[TBDKey::TBDVersion]] = 5;
1012   insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
1013   return std::move(Root);
1014 }
1015 
1016 } // namespace
1017 
1018 Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,
1019                                           const InterfaceFile &File,
1020                                           const FileType FileKind,
1021                                           bool Compact) {
1022   auto TextFile = getJSON(&File, FileKind);
1023   if (!TextFile)
1024     return TextFile.takeError();
1025   if (Compact)
1026     OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
1027   else
1028     OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
1029   return Error::success();
1030 }
1031