xref: /freebsd/contrib/llvm-project/llvm/lib/TextAPI/TextStubV5.cpp (revision c6eb7f3fbffd9065ab75a2ed266f1b069fd97e6e)
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  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)> const
205          GetValue,
206      StubT DefaultValue, function_ref<std::optional<StubT>(JsonT)> Validate) {
207    std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
208    if (!Val)
209      return DefaultValue;
210  
211    std::optional<StubT> Result;
212    Result = Validate(*Val);
213    if (!Result.has_value())
214      return make_error<JSONStubError>(getParseErrorMsg(Key));
215    return Result.value();
216  }
217  
218  Error collectFromArray(TBDKey Key, const Object *Obj,
219                         function_ref<void(StringRef)> Append,
220                         bool IsRequired = false) {
221    const auto *Values = Obj->getArray(Keys[Key]);
222    if (!Values) {
223      if (IsRequired)
224        return make_error<JSONStubError>(getParseErrorMsg(Key));
225      return Error::success();
226    }
227  
228    for (const Value &Val : *Values) {
229      auto ValStr = Val.getAsString();
230      if (!ValStr.has_value())
231        return make_error<JSONStubError>(getParseErrorMsg(Key));
232      Append(ValStr.value());
233    }
234  
235    return Error::success();
236  }
237  
238  namespace StubParser {
239  
240  Expected<FileType> getVersion(const Object *File) {
241    auto VersionOrErr = getRequiredValue<int64_t, FileType>(
242        TBDKey::TBDVersion, File, &Object::getInteger,
243        [](int64_t Val) -> std::optional<FileType> {
244          unsigned Result = Val;
245          if (Result != 5)
246            return std::nullopt;
247          return FileType::TBD_V5;
248        });
249  
250    if (!VersionOrErr)
251      return VersionOrErr.takeError();
252    return *VersionOrErr;
253  }
254  
255  Expected<TargetList> getTargets(const Object *Section) {
256    const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);
257    if (!Targets)
258      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
259  
260    TargetList IFTargets;
261    for (const Value &JSONTarget : *Targets) {
262      auto TargetStr = JSONTarget.getAsString();
263      if (!TargetStr.has_value())
264        return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
265      auto TargetOrErr = Target::create(TargetStr.value());
266      if (!TargetOrErr)
267        return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
268      IFTargets.push_back(*TargetOrErr);
269    }
270    return std::move(IFTargets);
271  }
272  
273  Expected<TargetList> getTargetsSection(const Object *Section) {
274    const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);
275    if (!Targets)
276      return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
277  
278    TargetList IFTargets;
279    for (const Value &JSONTarget : *Targets) {
280      const auto *Obj = JSONTarget.getAsObject();
281      if (!Obj)
282        return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
283      auto TargetStr =
284          getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);
285      if (!TargetStr)
286        return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
287      auto TargetOrErr = Target::create(*TargetStr);
288      if (!TargetOrErr)
289        return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
290  
291      auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]);
292      VersionTuple Version;
293      if (VersionStr && Version.tryParse(*VersionStr))
294        return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
295      TargetOrErr->MinDeployment = Version;
296  
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 = {EncodeKind::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 = {EncodeKind::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 = {EncodeKind::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 = {EncodeKind::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 = {EncodeKind::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 = {EncodeKind::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 || Section->empty())
552      return Flags;
553  
554    for (auto &Val : *Section) {
555      // FIXME: Flags currently apply to all target triples.
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                    .Case("sim_support", TBDFlags::SimulatorSupport)
568                    .Case("not_for_dyld_shared_cache",
569                          TBDFlags::OSLibNotForSharedCache)
570                    .Default(TBDFlags::None);
571            Flags |= TBDFlag;
572          });
573  
574      if (FlagsOrErr)
575        return std::move(FlagsOrErr);
576  
577      return Flags;
578    }
579  
580    return Flags;
581  }
582  
583  using IFPtr = std::unique_ptr<InterfaceFile>;
584  Expected<IFPtr> parseToInterfaceFile(const Object *File) {
585    auto TargetsOrErr = getTargetsSection(File);
586    if (!TargetsOrErr)
587      return TargetsOrErr.takeError();
588    TargetList Targets = *TargetsOrErr;
589  
590    auto NameOrErr = getNameSection(File);
591    if (!NameOrErr)
592      return NameOrErr.takeError();
593    StringRef Name = *NameOrErr;
594  
595    auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);
596    if (!CurrVersionOrErr)
597      return CurrVersionOrErr.takeError();
598    PackedVersion CurrVersion = *CurrVersionOrErr;
599  
600    auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);
601    if (!CompVersionOrErr)
602      return CompVersionOrErr.takeError();
603    PackedVersion CompVersion = *CompVersionOrErr;
604  
605    auto SwiftABIOrErr = getSwiftVersion(File);
606    if (!SwiftABIOrErr)
607      return SwiftABIOrErr.takeError();
608    uint8_t SwiftABI = *SwiftABIOrErr;
609  
610    auto FlagsOrErr = getFlags(File);
611    if (!FlagsOrErr)
612      return FlagsOrErr.takeError();
613    TBDFlags Flags = *FlagsOrErr;
614  
615    auto UmbrellasOrErr = getUmbrellaSection(File, Targets);
616    if (!UmbrellasOrErr)
617      return UmbrellasOrErr.takeError();
618    AttrToTargets Umbrellas = *UmbrellasOrErr;
619  
620    auto ClientsOrErr =
621        getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);
622    if (!ClientsOrErr)
623      return ClientsOrErr.takeError();
624    AttrToTargets Clients = *ClientsOrErr;
625  
626    auto RLOrErr =
627        getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);
628    if (!RLOrErr)
629      return RLOrErr.takeError();
630    AttrToTargets ReexportLibs = std::move(*RLOrErr);
631  
632    auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);
633    if (!RPathsOrErr)
634      return RPathsOrErr.takeError();
635    AttrToTargets RPaths = std::move(*RPathsOrErr);
636  
637    auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
638    if (!ExportsOrErr)
639      return ExportsOrErr.takeError();
640    TargetsToSymbols Exports = std::move(*ExportsOrErr);
641  
642    auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);
643    if (!ReexportsOrErr)
644      return ReexportsOrErr.takeError();
645    TargetsToSymbols Reexports = std::move(*ReexportsOrErr);
646  
647    auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);
648    if (!UndefinedsOrErr)
649      return UndefinedsOrErr.takeError();
650    TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);
651  
652    IFPtr F(new InterfaceFile);
653    F->setInstallName(Name);
654    F->setCurrentVersion(CurrVersion);
655    F->setCompatibilityVersion(CompVersion);
656    F->setSwiftABIVersion(SwiftABI);
657    F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
658    F->setApplicationExtensionSafe(
659        !(Flags & TBDFlags::NotApplicationExtensionSafe));
660    F->setSimulatorSupport((Flags & TBDFlags::SimulatorSupport));
661    F->setOSLibNotForSharedCache((Flags & TBDFlags::OSLibNotForSharedCache));
662    for (auto &T : Targets)
663      F->addTarget(T);
664    for (auto &[Lib, Targets] : Clients)
665      for (auto Target : Targets)
666        F->addAllowableClient(Lib, Target);
667    for (auto &[Lib, Targets] : ReexportLibs)
668      for (auto Target : Targets)
669        F->addReexportedLibrary(Lib, Target);
670    for (auto &[Lib, Targets] : Umbrellas)
671      for (auto Target : Targets)
672        F->addParentUmbrella(Target, Lib);
673    for (auto &[Path, Targets] : RPaths)
674      for (auto Target : Targets)
675        F->addRPath(Path, Target);
676    for (auto &[Targets, Symbols] : Exports)
677      for (auto &Sym : Symbols)
678        F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
679    for (auto &[Targets, Symbols] : Reexports)
680      for (auto &Sym : Symbols)
681        F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
682    for (auto &[Targets, Symbols] : Undefineds)
683      for (auto &Sym : Symbols)
684        F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
685  
686    return std::move(F);
687  }
688  
689  Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {
690    std::vector<IFPtr> IFs;
691    const Array *Files = File->getArray(Keys[TBDKey::Documents]);
692    if (!Files)
693      return std::move(IFs);
694  
695    for (auto Lib : *Files) {
696      auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());
697      if (!IFOrErr)
698        return IFOrErr.takeError();
699      auto IF = std::move(*IFOrErr);
700      IFs.emplace_back(std::move(IF));
701    }
702    return std::move(IFs);
703  }
704  
705  } // namespace StubParser
706  } // namespace
707  
708  Expected<std::unique_ptr<InterfaceFile>>
709  MachO::getInterfaceFileFromJSON(StringRef JSON) {
710    auto ValOrErr = parse(JSON);
711    if (!ValOrErr)
712      return ValOrErr.takeError();
713  
714    auto *Root = ValOrErr->getAsObject();
715    auto VersionOrErr = StubParser::getVersion(Root);
716    if (!VersionOrErr)
717      return VersionOrErr.takeError();
718    FileType Version = *VersionOrErr;
719  
720    Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);
721    auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);
722    if (!IFOrErr)
723      return IFOrErr.takeError();
724    (*IFOrErr)->setFileType(Version);
725    std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));
726  
727    auto IFsOrErr = StubParser::getInlinedLibs(Root);
728    if (!IFsOrErr)
729      return IFsOrErr.takeError();
730    for (auto &File : *IFsOrErr) {
731      File->setFileType(Version);
732      IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));
733    }
734    return std::move(IF);
735  }
736  
737  namespace {
738  
739  template <typename ContainerT = Array>
740  bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
741    if (Contents.empty())
742      return false;
743    Obj[Keys[Key]] = std::move(Contents);
744    return true;
745  }
746  
747  std::string getFormattedStr(const MachO::Target &Targ) {
748    std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
749                                  ? "maccatalyst"
750                                  : getOSAndEnvironmentName(Targ.Platform);
751    return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
752  }
753  
754  template <typename AggregateT>
755  std::vector<std::string> serializeTargets(const AggregateT Targets,
756                                            const TargetList &ActiveTargets) {
757    std::vector<std::string> TargetsStr;
758    if (Targets.size() == ActiveTargets.size())
759      return TargetsStr;
760  
761    for (const MachO::Target &Target : Targets)
762      TargetsStr.emplace_back(getFormattedStr(Target));
763  
764    return TargetsStr;
765  }
766  
767  Array serializeTargetInfo(const TargetList &ActiveTargets) {
768    Array Targets;
769    for (const auto Targ : ActiveTargets) {
770      Object TargetInfo;
771      if (!Targ.MinDeployment.empty())
772        TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();
773      TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
774      Targets.emplace_back(std::move(TargetInfo));
775    }
776    return Targets;
777  }
778  
779  template <typename ValueT, typename EntryT = ValueT>
780  Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
781    if (Value == Default)
782      return {};
783    Array Container;
784    Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
785  
786    Container.emplace_back(std::move(ScalarObj));
787    return Container;
788  }
789  
790  using TargetsToValuesMap =
791      std::map<std::vector<std::string>, std::vector<std::string>>;
792  
793  template <typename AggregateT = TargetsToValuesMap>
794  Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
795    Array Container;
796    for (const auto &[Targets, Values] : Entries) {
797      Object Obj;
798      insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
799      Obj[Keys[Key]] = Values;
800      Container.emplace_back(std::move(Obj));
801    }
802    return Container;
803  }
804  
805  template <typename ValueT = std::string,
806            typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
807  Array serializeField(TBDKey Key, const AggregateT &Values,
808                       const TargetList &ActiveTargets, bool IsArray = true) {
809    std::map<ValueT, std::set<MachO::Target>> Entries;
810    for (const auto &[Target, Val] : Values)
811      Entries[Val].insert(Target);
812  
813    if (!IsArray) {
814      std::map<std::vector<std::string>, std::string> FinalEntries;
815      for (const auto &[Val, Targets] : Entries)
816        FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
817      return serializeAttrToTargets(FinalEntries, Key);
818    }
819  
820    TargetsToValuesMap FinalEntries;
821    for (const auto &[Val, Targets] : Entries)
822      FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
823    return serializeAttrToTargets(FinalEntries, Key);
824  }
825  
826  Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
827                       const TargetList &ActiveTargets) {
828    TargetsToValuesMap FinalEntries;
829    for (const auto &Ref : Values) {
830      TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
831      FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
832          Ref.getInstallName());
833    }
834    return serializeAttrToTargets(FinalEntries, Key);
835  }
836  
837  struct SymbolFields {
838    struct SymbolTypes {
839      std::vector<StringRef> Weaks;
840      std::vector<StringRef> Globals;
841      std::vector<StringRef> TLV;
842      std::vector<StringRef> ObjCClasses;
843      std::vector<StringRef> IVars;
844      std::vector<StringRef> EHTypes;
845  
846      bool empty() const {
847        return Weaks.empty() && Globals.empty() && TLV.empty() &&
848               ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
849      }
850    };
851    SymbolTypes Data;
852    SymbolTypes Text;
853  };
854  
855  Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,
856                         const TargetList &ActiveTargets) {
857    auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
858                                  const Symbol *Sym) {
859      switch (Sym->getKind()) {
860      case EncodeKind::ObjectiveCClass:
861        Assignment.ObjCClasses.emplace_back(Sym->getName());
862        return;
863      case EncodeKind::ObjectiveCClassEHType:
864        Assignment.EHTypes.emplace_back(Sym->getName());
865        return;
866      case EncodeKind::ObjectiveCInstanceVariable:
867        Assignment.IVars.emplace_back(Sym->getName());
868        return;
869      case EncodeKind::GlobalSymbol: {
870        if (Sym->isWeakReferenced() || Sym->isWeakDefined())
871          Assignment.Weaks.emplace_back(Sym->getName());
872        else if (Sym->isThreadLocalValue())
873          Assignment.TLV.emplace_back(Sym->getName());
874        else
875          Assignment.Globals.emplace_back(Sym->getName());
876        return;
877      }
878      }
879    };
880  
881    std::map<std::vector<std::string>, SymbolFields> Entries;
882    for (const auto *Sym : Symbols) {
883      std::set<MachO::Target> Targets{Sym->targets().begin(),
884                                      Sym->targets().end()};
885      auto JSONTargets = serializeTargets(Targets, ActiveTargets);
886      if (Sym->isData())
887        AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
888      else if (Sym->isText())
889        AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
890      else
891        llvm_unreachable("unexpected symbol type");
892    }
893  
894    auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
895                                  SymbolFields::SymbolTypes &SymField) {
896      if (SymField.empty())
897        return;
898      Object Segment;
899      insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
900      insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
901      insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
902      insertNonEmptyValues(Segment, TBDKey::ObjCClass,
903                           std::move(SymField.ObjCClasses));
904      insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
905                           std::move(SymField.EHTypes));
906      insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
907      insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
908    };
909  
910    Array SymbolSection;
911    for (auto &[Targets, Fields] : Entries) {
912      Object AllSyms;
913      insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
914      InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
915      InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
916      SymbolSection.emplace_back(std::move(AllSyms));
917    }
918  
919    return SymbolSection;
920  }
921  
922  Array serializeFlags(const InterfaceFile *File) {
923    // TODO: Give all Targets the same flags for now.
924    Array Flags;
925    if (!File->isTwoLevelNamespace())
926      Flags.emplace_back("flat_namespace");
927    if (!File->isApplicationExtensionSafe())
928      Flags.emplace_back("not_app_extension_safe");
929    if (File->hasSimulatorSupport())
930      Flags.emplace_back("sim_support");
931    if (File->isOSLibNotForSharedCache())
932      Flags.emplace_back("not_for_dyld_shared_cache");
933    return serializeScalar(TBDKey::Attributes, std::move(Flags));
934  }
935  
936  Expected<Object> serializeIF(const InterfaceFile *File) {
937    Object Library;
938  
939    // Handle required keys.
940    TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
941    if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
942                              serializeTargetInfo(ActiveTargets)))
943      return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
944  
945    Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
946    if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
947      return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
948  
949    // Handle optional keys.
950    Array Flags = serializeFlags(File);
951    insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
952  
953    Array CurrentV = serializeScalar<PackedVersion, std::string>(
954        TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
955    insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
956  
957    Array CompatV = serializeScalar<PackedVersion, std::string>(
958        TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
959    insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
960                         std::move(CompatV));
961  
962    Array SwiftABI = serializeScalar<uint8_t, int64_t>(
963        TBDKey::ABI, File->getSwiftABIVersion(), 0u);
964    insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
965  
966    Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
967    insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
968  
969    Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
970                                     ActiveTargets, /*IsArray=*/false);
971    insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
972  
973    Array Clients =
974        serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
975    insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
976  
977    Array ReexportLibs =
978        serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
979    insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
980  
981    // Handle symbols.
982    Array Exports = serializeSymbols(File->exports(), ActiveTargets);
983    insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
984  
985    Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
986    insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
987  
988    if (!File->isTwoLevelNamespace()) {
989      Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
990      insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
991    }
992  
993    return std::move(Library);
994  }
995  
996  Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {
997    assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");
998    Object Root;
999  
1000    auto MainLibOrErr = serializeIF(File);
1001    if (!MainLibOrErr)
1002      return MainLibOrErr;
1003    Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
1004    Array Documents;
1005    for (const auto &Doc : File->documents()) {
1006      auto LibOrErr = serializeIF(Doc.get());
1007      if (!LibOrErr)
1008        return LibOrErr;
1009      Documents.emplace_back(std::move(*LibOrErr));
1010    }
1011  
1012    Root[Keys[TBDKey::TBDVersion]] = 5;
1013    insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
1014    return std::move(Root);
1015  }
1016  
1017  } // namespace
1018  
1019  Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,
1020                                            const InterfaceFile &File,
1021                                            const FileType FileKind,
1022                                            bool Compact) {
1023    auto TextFile = getJSON(&File, FileKind);
1024    if (!TextFile)
1025      return TextFile.takeError();
1026    if (Compact)
1027      OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
1028    else
1029      OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
1030    return Error::success();
1031  }
1032