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