xref: /llvm-project/llvm/lib/TextAPI/TextStubV5.cpp (revision 515d3f7d62679cba178fb3603db963baa6ec8c93)
179320a0cSCyndy Ishida //===- TextStubV5.cpp -----------------------------------------------------===//
279320a0cSCyndy Ishida //
379320a0cSCyndy Ishida // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
479320a0cSCyndy Ishida // See https://llvm.org/LICENSE.txt for license information.
579320a0cSCyndy Ishida // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
679320a0cSCyndy Ishida //
779320a0cSCyndy Ishida //===----------------------------------------------------------------------===//
879320a0cSCyndy Ishida //
979320a0cSCyndy Ishida // Implements Text Stub JSON mappings.
1079320a0cSCyndy Ishida //
1179320a0cSCyndy Ishida //===----------------------------------------------------------------------===//
1279320a0cSCyndy Ishida #include "TextStubCommon.h"
1379320a0cSCyndy Ishida #include "llvm/ADT/StringSwitch.h"
1479320a0cSCyndy Ishida #include "llvm/Support/JSON.h"
159b29de1cSCyndy Ishida #include <utility>
1679320a0cSCyndy Ishida 
1779320a0cSCyndy Ishida // clang-format off
1879320a0cSCyndy Ishida /*
1979320a0cSCyndy Ishida 
2079320a0cSCyndy Ishida JSON Format specification.
2179320a0cSCyndy Ishida 
2279320a0cSCyndy Ishida All library level keys, accept target values and are defaulted if not specified.
2379320a0cSCyndy Ishida 
2479320a0cSCyndy Ishida {
2579320a0cSCyndy Ishida "tapi_tbd_version": 5,                            # Required: TBD version for all documents in file
2679320a0cSCyndy Ishida "main_library": {                                 # Required: top level library
2779320a0cSCyndy Ishida   "target_info": [                                # Required: target information
2879320a0cSCyndy Ishida     {
2979320a0cSCyndy Ishida       "target": "x86_64-macos",
303b731391SCyndy Ishida       "min_deployment": "10.14"                   # Optional: minOS defaults to 0
3179320a0cSCyndy Ishida     },
3279320a0cSCyndy Ishida     {
3379320a0cSCyndy Ishida       "target": "arm64-macos",
3479320a0cSCyndy Ishida       "min_deployment": "10.14"
3579320a0cSCyndy Ishida     },
3679320a0cSCyndy Ishida     {
3779320a0cSCyndy Ishida       "target": "arm64-maccatalyst",
3879320a0cSCyndy Ishida       "min_deployment": "12.1"
3979320a0cSCyndy Ishida     }],
4079320a0cSCyndy Ishida   "flags":[{"attributes": ["flat_namespace"]}],     # Optional:
4179320a0cSCyndy Ishida   "install_names":[{"name":"/S/L/F/Foo.fwk/Foo"}],  # Required: library install name
4279320a0cSCyndy Ishida   "current_versions":[{"version": "1.2"}],          # Optional: defaults to 1
4379320a0cSCyndy Ishida   "compatibility_versions":[{ "version": "1.1"}],   # Optional: defaults to 1
4479320a0cSCyndy Ishida   "rpaths": [                                       # Optional:
4579320a0cSCyndy Ishida     {
4679320a0cSCyndy Ishida       "targets": ["x86_64-macos"],                  # Optional: defaults to targets in `target-info`
4779320a0cSCyndy Ishida       "paths": ["@executable_path/.../Frameworks"]
4879320a0cSCyndy Ishida     }],
4979320a0cSCyndy Ishida   "parent_umbrellas": [{"umbrella": "System"}],
5079320a0cSCyndy Ishida   "allowable_clients": [{"clients": ["ClientA"]}],
5179320a0cSCyndy Ishida   "reexported_libraries": [{"names": ["/u/l/l/foo.dylib"]}],
5279320a0cSCyndy Ishida   "exported_symbols": [{                            # List of export symbols section
5379320a0cSCyndy Ishida       "targets": ["x86_64-macos", "arm64-macos"],   # Optional: defaults to targets in `target-info`
5479320a0cSCyndy Ishida         "text": {                                   # List of Text segment symbols
5579320a0cSCyndy Ishida           "global": [ "_func" ],
5679320a0cSCyndy Ishida           "weak": [],
5779320a0cSCyndy Ishida           "thread_local": []
5879320a0cSCyndy Ishida         },
5979320a0cSCyndy Ishida         "data": { ... },                            # List of Data segment symbols
6079320a0cSCyndy Ishida    }],
6179320a0cSCyndy Ishida   "reexported_symbols": [{  ... }],                 # List of reexported symbols section
6279320a0cSCyndy Ishida   "undefined_symbols": [{ ... }]                    # List of undefined symbols section
6379320a0cSCyndy Ishida },
6479320a0cSCyndy Ishida "libraries": [                                      # Optional: Array of inlined libraries
6579320a0cSCyndy Ishida   {...}, {...}, {...}
6679320a0cSCyndy Ishida ]
6779320a0cSCyndy Ishida }
6879320a0cSCyndy Ishida */
6979320a0cSCyndy Ishida // clang-format on
7079320a0cSCyndy Ishida 
7179320a0cSCyndy Ishida using namespace llvm;
7279320a0cSCyndy Ishida using namespace llvm::json;
7379320a0cSCyndy Ishida using namespace llvm::MachO;
7479320a0cSCyndy Ishida 
756e55370bSBenjamin Kramer namespace {
7679320a0cSCyndy Ishida struct JSONSymbol {
77d9a9872eSCyndy Ishida   EncodeKind Kind;
7879320a0cSCyndy Ishida   std::string Name;
7979320a0cSCyndy Ishida   SymbolFlags Flags;
8079320a0cSCyndy Ishida };
8179320a0cSCyndy Ishida 
8279320a0cSCyndy Ishida using AttrToTargets = std::map<std::string, TargetList>;
8379320a0cSCyndy Ishida using TargetsToSymbols =
8479320a0cSCyndy Ishida     SmallVector<std::pair<TargetList, std::vector<JSONSymbol>>>;
8579320a0cSCyndy Ishida 
8679320a0cSCyndy Ishida enum TBDKey : size_t {
8779320a0cSCyndy Ishida   TBDVersion = 0U,
8879320a0cSCyndy Ishida   MainLibrary,
8979320a0cSCyndy Ishida   Documents,
9079320a0cSCyndy Ishida   TargetInfo,
9179320a0cSCyndy Ishida   Targets,
9279320a0cSCyndy Ishida   Target,
9379320a0cSCyndy Ishida   Deployment,
9479320a0cSCyndy Ishida   Flags,
9579320a0cSCyndy Ishida   Attributes,
9679320a0cSCyndy Ishida   InstallName,
9779320a0cSCyndy Ishida   CurrentVersion,
9879320a0cSCyndy Ishida   CompatibilityVersion,
9979320a0cSCyndy Ishida   Version,
10079320a0cSCyndy Ishida   SwiftABI,
10179320a0cSCyndy Ishida   ABI,
10279320a0cSCyndy Ishida   ParentUmbrella,
10379320a0cSCyndy Ishida   Umbrella,
10479320a0cSCyndy Ishida   AllowableClients,
10579320a0cSCyndy Ishida   Clients,
10679320a0cSCyndy Ishida   ReexportLibs,
10779320a0cSCyndy Ishida   Names,
10879320a0cSCyndy Ishida   Name,
10979320a0cSCyndy Ishida   Exports,
11079320a0cSCyndy Ishida   Reexports,
11179320a0cSCyndy Ishida   Undefineds,
11279320a0cSCyndy Ishida   Data,
11379320a0cSCyndy Ishida   Text,
11479320a0cSCyndy Ishida   Weak,
11579320a0cSCyndy Ishida   ThreadLocal,
11679320a0cSCyndy Ishida   Globals,
11779320a0cSCyndy Ishida   ObjCClass,
11879320a0cSCyndy Ishida   ObjCEHType,
11979320a0cSCyndy Ishida   ObjCIvar,
120b70d87bcSCyndy Ishida   RPath,
121b70d87bcSCyndy Ishida   Paths,
12279320a0cSCyndy Ishida };
12379320a0cSCyndy Ishida 
12479320a0cSCyndy Ishida std::array<StringRef, 64> Keys = {
12579320a0cSCyndy Ishida     "tapi_tbd_version",
12679320a0cSCyndy Ishida     "main_library",
12779320a0cSCyndy Ishida     "libraries",
12879320a0cSCyndy Ishida     "target_info",
12979320a0cSCyndy Ishida     "targets",
13079320a0cSCyndy Ishida     "target",
13179320a0cSCyndy Ishida     "min_deployment",
13279320a0cSCyndy Ishida     "flags",
13379320a0cSCyndy Ishida     "attributes",
13479320a0cSCyndy Ishida     "install_names",
13579320a0cSCyndy Ishida     "current_versions",
13679320a0cSCyndy Ishida     "compatibility_versions",
13779320a0cSCyndy Ishida     "version",
13879320a0cSCyndy Ishida     "swift_abi",
13979320a0cSCyndy Ishida     "abi",
14079320a0cSCyndy Ishida     "parent_umbrellas",
14179320a0cSCyndy Ishida     "umbrella",
14279320a0cSCyndy Ishida     "allowable_clients",
14379320a0cSCyndy Ishida     "clients",
14479320a0cSCyndy Ishida     "reexported_libraries",
14579320a0cSCyndy Ishida     "names",
14679320a0cSCyndy Ishida     "name",
14779320a0cSCyndy Ishida     "exported_symbols",
14879320a0cSCyndy Ishida     "reexported_symbols",
14979320a0cSCyndy Ishida     "undefined_symbols",
15079320a0cSCyndy Ishida     "data",
15179320a0cSCyndy Ishida     "text",
15279320a0cSCyndy Ishida     "weak",
15379320a0cSCyndy Ishida     "thread_local",
15479320a0cSCyndy Ishida     "global",
15579320a0cSCyndy Ishida     "objc_class",
15679320a0cSCyndy Ishida     "objc_eh_type",
15779320a0cSCyndy Ishida     "objc_ivar",
158b70d87bcSCyndy Ishida     "rpaths",
159b70d87bcSCyndy Ishida     "paths",
16079320a0cSCyndy Ishida };
16179320a0cSCyndy Ishida 
getParseErrorMsg(TBDKey Key)16279320a0cSCyndy Ishida static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) {
16379320a0cSCyndy Ishida   return {"invalid ", Keys[Key], " section"};
16479320a0cSCyndy Ishida }
16579320a0cSCyndy Ishida 
getSerializeErrorMsg(TBDKey Key)166d6f9b97bSCyndy Ishida static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) {
167d6f9b97bSCyndy Ishida   return {"missing ", Keys[Key], " information"};
168d6f9b97bSCyndy Ishida }
169d6f9b97bSCyndy Ishida 
17079320a0cSCyndy Ishida class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {
17179320a0cSCyndy Ishida public:
JSONStubError(Twine ErrMsg)17279320a0cSCyndy Ishida   JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {}
17379320a0cSCyndy Ishida 
log(llvm::raw_ostream & OS) const17479320a0cSCyndy Ishida   void log(llvm::raw_ostream &OS) const override { OS << Message << "\n"; }
convertToErrorCode() const17579320a0cSCyndy Ishida   std::error_code convertToErrorCode() const override {
17679320a0cSCyndy Ishida     return llvm::inconvertibleErrorCode();
17779320a0cSCyndy Ishida   }
17879320a0cSCyndy Ishida 
17979320a0cSCyndy Ishida private:
18079320a0cSCyndy Ishida   std::string Message;
18179320a0cSCyndy Ishida };
18279320a0cSCyndy Ishida 
18379320a0cSCyndy Ishida template <typename JsonT, typename StubT = JsonT>
getRequiredValue(TBDKey Key,const Object * Obj,std::function<std::optional<JsonT> (const Object *,StringRef)> GetValue,std::function<std::optional<StubT> (JsonT)> Validate=nullptr)18479320a0cSCyndy Ishida Expected<StubT> getRequiredValue(
18579320a0cSCyndy Ishida     TBDKey Key, const Object *Obj,
18679320a0cSCyndy Ishida     std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
18779320a0cSCyndy Ishida     std::function<std::optional<StubT>(JsonT)> Validate = nullptr) {
18879320a0cSCyndy Ishida   std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
18979320a0cSCyndy Ishida   if (!Val)
19079320a0cSCyndy Ishida     return make_error<JSONStubError>(getParseErrorMsg(Key));
19179320a0cSCyndy Ishida 
19279320a0cSCyndy Ishida   if (Validate == nullptr)
19379320a0cSCyndy Ishida     return static_cast<StubT>(*Val);
19479320a0cSCyndy Ishida 
19579320a0cSCyndy Ishida   std::optional<StubT> Result = Validate(*Val);
19679320a0cSCyndy Ishida   if (!Result.has_value())
19779320a0cSCyndy Ishida     return make_error<JSONStubError>(getParseErrorMsg(Key));
19879320a0cSCyndy Ishida   return Result.value();
19979320a0cSCyndy Ishida }
20079320a0cSCyndy Ishida 
20179320a0cSCyndy Ishida template <typename JsonT, typename StubT = JsonT>
getRequiredValue(TBDKey Key,const Object * Obj,std::function<std::optional<JsonT> (const Object *,StringRef)> const GetValue,StubT DefaultValue,function_ref<std::optional<StubT> (JsonT)> Validate)20279320a0cSCyndy Ishida Expected<StubT> getRequiredValue(
20379320a0cSCyndy Ishida     TBDKey Key, const Object *Obj,
2048fa31845SCyndy Ishida     std::function<std::optional<JsonT>(const Object *, StringRef)> const
2058fa31845SCyndy Ishida         GetValue,
2068fa31845SCyndy Ishida     StubT DefaultValue, function_ref<std::optional<StubT>(JsonT)> Validate) {
20779320a0cSCyndy Ishida   std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
20879320a0cSCyndy Ishida   if (!Val)
20979320a0cSCyndy Ishida     return DefaultValue;
21079320a0cSCyndy Ishida 
21179320a0cSCyndy Ishida   std::optional<StubT> Result;
21279320a0cSCyndy Ishida   Result = Validate(*Val);
21379320a0cSCyndy Ishida   if (!Result.has_value())
21479320a0cSCyndy Ishida     return make_error<JSONStubError>(getParseErrorMsg(Key));
21579320a0cSCyndy Ishida   return Result.value();
21679320a0cSCyndy Ishida }
21779320a0cSCyndy Ishida 
collectFromArray(TBDKey Key,const Object * Obj,function_ref<void (StringRef)> Append,bool IsRequired=false)21879320a0cSCyndy Ishida Error collectFromArray(TBDKey Key, const Object *Obj,
2198fa31845SCyndy Ishida                        function_ref<void(StringRef)> Append,
22079320a0cSCyndy Ishida                        bool IsRequired = false) {
22179320a0cSCyndy Ishida   const auto *Values = Obj->getArray(Keys[Key]);
22279320a0cSCyndy Ishida   if (!Values) {
22379320a0cSCyndy Ishida     if (IsRequired)
22479320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(Key));
22579320a0cSCyndy Ishida     return Error::success();
22679320a0cSCyndy Ishida   }
22779320a0cSCyndy Ishida 
22835e21725SSimon Pilgrim   for (const Value &Val : *Values) {
22979320a0cSCyndy Ishida     auto ValStr = Val.getAsString();
23079320a0cSCyndy Ishida     if (!ValStr.has_value())
23179320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(Key));
23279320a0cSCyndy Ishida     Append(ValStr.value());
23379320a0cSCyndy Ishida   }
23479320a0cSCyndy Ishida 
23579320a0cSCyndy Ishida   return Error::success();
23679320a0cSCyndy Ishida }
23779320a0cSCyndy Ishida 
23879320a0cSCyndy Ishida namespace StubParser {
23979320a0cSCyndy Ishida 
getVersion(const Object * File)24079320a0cSCyndy Ishida Expected<FileType> getVersion(const Object *File) {
24179320a0cSCyndy Ishida   auto VersionOrErr = getRequiredValue<int64_t, FileType>(
24279320a0cSCyndy Ishida       TBDKey::TBDVersion, File, &Object::getInteger,
24379320a0cSCyndy Ishida       [](int64_t Val) -> std::optional<FileType> {
24479320a0cSCyndy Ishida         unsigned Result = Val;
24579320a0cSCyndy Ishida         if (Result != 5)
24679320a0cSCyndy Ishida           return std::nullopt;
24779320a0cSCyndy Ishida         return FileType::TBD_V5;
24879320a0cSCyndy Ishida       });
24979320a0cSCyndy Ishida 
25079320a0cSCyndy Ishida   if (!VersionOrErr)
25179320a0cSCyndy Ishida     return VersionOrErr.takeError();
25279320a0cSCyndy Ishida   return *VersionOrErr;
25379320a0cSCyndy Ishida }
25479320a0cSCyndy Ishida 
getTargets(const Object * Section)25579320a0cSCyndy Ishida Expected<TargetList> getTargets(const Object *Section) {
25679320a0cSCyndy Ishida   const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);
25779320a0cSCyndy Ishida   if (!Targets)
25879320a0cSCyndy Ishida     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
25979320a0cSCyndy Ishida 
26079320a0cSCyndy Ishida   TargetList IFTargets;
26135e21725SSimon Pilgrim   for (const Value &JSONTarget : *Targets) {
26279320a0cSCyndy Ishida     auto TargetStr = JSONTarget.getAsString();
26379320a0cSCyndy Ishida     if (!TargetStr.has_value())
26479320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
26579320a0cSCyndy Ishida     auto TargetOrErr = Target::create(TargetStr.value());
26679320a0cSCyndy Ishida     if (!TargetOrErr)
26779320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
26879320a0cSCyndy Ishida     IFTargets.push_back(*TargetOrErr);
26979320a0cSCyndy Ishida   }
27079320a0cSCyndy Ishida   return std::move(IFTargets);
27179320a0cSCyndy Ishida }
27279320a0cSCyndy Ishida 
getTargetsSection(const Object * Section)27379320a0cSCyndy Ishida Expected<TargetList> getTargetsSection(const Object *Section) {
27479320a0cSCyndy Ishida   const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);
27579320a0cSCyndy Ishida   if (!Targets)
27679320a0cSCyndy Ishida     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
27779320a0cSCyndy Ishida 
27879320a0cSCyndy Ishida   TargetList IFTargets;
27979320a0cSCyndy Ishida   for (const Value &JSONTarget : *Targets) {
28079320a0cSCyndy Ishida     const auto *Obj = JSONTarget.getAsObject();
28179320a0cSCyndy Ishida     if (!Obj)
28279320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
28379320a0cSCyndy Ishida     auto TargetStr =
28479320a0cSCyndy Ishida         getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);
28579320a0cSCyndy Ishida     if (!TargetStr)
28679320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
28779320a0cSCyndy Ishida     auto TargetOrErr = Target::create(*TargetStr);
28879320a0cSCyndy Ishida     if (!TargetOrErr)
28979320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
2903b731391SCyndy Ishida 
2913b731391SCyndy Ishida     auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]);
2923b731391SCyndy Ishida     VersionTuple Version;
2933b731391SCyndy Ishida     if (VersionStr && Version.tryParse(*VersionStr))
2943b731391SCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
295b70d87bcSCyndy Ishida     TargetOrErr->MinDeployment = Version;
2963b731391SCyndy Ishida 
29739748656SCyndy Ishida     // Convert to LLVM::Triple to accurately compute minOS + platform + arch
29839748656SCyndy Ishida     // pairing.
29939748656SCyndy Ishida     IFTargets.push_back(
30039748656SCyndy Ishida         MachO::Target(Triple(getTargetTripleName(*TargetOrErr))));
30179320a0cSCyndy Ishida   }
30279320a0cSCyndy Ishida   return std::move(IFTargets);
30379320a0cSCyndy Ishida }
30479320a0cSCyndy Ishida 
collectSymbolsFromSegment(const Object * Segment,TargetsToSymbols & Result,SymbolFlags SectionFlag)30579320a0cSCyndy Ishida Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result,
30679320a0cSCyndy Ishida                                 SymbolFlags SectionFlag) {
30779320a0cSCyndy Ishida   auto Err = collectFromArray(
30879320a0cSCyndy Ishida       TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {
309d9a9872eSCyndy Ishida         JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), SectionFlag};
31079320a0cSCyndy Ishida         Result.back().second.emplace_back(Sym);
31179320a0cSCyndy Ishida       });
31279320a0cSCyndy Ishida   if (Err)
31379320a0cSCyndy Ishida     return Err;
31479320a0cSCyndy Ishida 
31579320a0cSCyndy Ishida   Err = collectFromArray(
31679320a0cSCyndy Ishida       TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {
317d9a9872eSCyndy Ishida         JSONSymbol Sym = {EncodeKind::ObjectiveCClass, Name.str(), SectionFlag};
31879320a0cSCyndy Ishida         Result.back().second.emplace_back(Sym);
31979320a0cSCyndy Ishida       });
32079320a0cSCyndy Ishida   if (Err)
32179320a0cSCyndy Ishida     return Err;
32279320a0cSCyndy Ishida 
32379320a0cSCyndy Ishida   Err = collectFromArray(TBDKey::ObjCEHType, Segment,
32479320a0cSCyndy Ishida                          [&Result, &SectionFlag](StringRef Name) {
325d9a9872eSCyndy Ishida                            JSONSymbol Sym = {EncodeKind::ObjectiveCClassEHType,
32679320a0cSCyndy Ishida                                              Name.str(), SectionFlag};
32779320a0cSCyndy Ishida                            Result.back().second.emplace_back(Sym);
32879320a0cSCyndy Ishida                          });
32979320a0cSCyndy Ishida   if (Err)
33079320a0cSCyndy Ishida     return Err;
33179320a0cSCyndy Ishida 
33279320a0cSCyndy Ishida   Err = collectFromArray(
33379320a0cSCyndy Ishida       TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {
334d9a9872eSCyndy Ishida         JSONSymbol Sym = {EncodeKind::ObjectiveCInstanceVariable, Name.str(),
33579320a0cSCyndy Ishida                           SectionFlag};
33679320a0cSCyndy Ishida         Result.back().second.emplace_back(Sym);
33779320a0cSCyndy Ishida       });
33879320a0cSCyndy Ishida   if (Err)
33979320a0cSCyndy Ishida     return Err;
34079320a0cSCyndy Ishida 
3419b29de1cSCyndy Ishida   SymbolFlags WeakFlag =
3429b29de1cSCyndy Ishida       SectionFlag |
3439b29de1cSCyndy Ishida       (((SectionFlag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
34479320a0cSCyndy Ishida            ? SymbolFlags::WeakReferenced
34579320a0cSCyndy Ishida            : SymbolFlags::WeakDefined);
346b70d87bcSCyndy Ishida   Err = collectFromArray(
347b70d87bcSCyndy Ishida       TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {
348d9a9872eSCyndy Ishida         JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), WeakFlag};
34979320a0cSCyndy Ishida         Result.back().second.emplace_back(Sym);
35079320a0cSCyndy Ishida       });
35179320a0cSCyndy Ishida   if (Err)
35279320a0cSCyndy Ishida     return Err;
35379320a0cSCyndy Ishida 
35479320a0cSCyndy Ishida   Err = collectFromArray(
35579320a0cSCyndy Ishida       TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {
356d9a9872eSCyndy Ishida         JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(),
35779320a0cSCyndy Ishida                           SymbolFlags::ThreadLocalValue | SectionFlag};
35879320a0cSCyndy Ishida         Result.back().second.emplace_back(Sym);
35979320a0cSCyndy Ishida       });
36079320a0cSCyndy Ishida   if (Err)
36179320a0cSCyndy Ishida     return Err;
36279320a0cSCyndy Ishida 
36379320a0cSCyndy Ishida   return Error::success();
36479320a0cSCyndy Ishida }
36579320a0cSCyndy Ishida 
getNameSection(const Object * File)36679320a0cSCyndy Ishida Expected<StringRef> getNameSection(const Object *File) {
36779320a0cSCyndy Ishida   const Array *Section = File->getArray(Keys[TBDKey::InstallName]);
36879320a0cSCyndy Ishida   if (!Section)
36979320a0cSCyndy Ishida     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
37079320a0cSCyndy Ishida 
37179320a0cSCyndy Ishida   assert(!Section->empty() && "unexpected missing install name");
37279320a0cSCyndy Ishida   // TODO: Just take first for now.
37379320a0cSCyndy Ishida   const auto *Obj = Section->front().getAsObject();
37479320a0cSCyndy Ishida   if (!Obj)
37579320a0cSCyndy Ishida     return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
37679320a0cSCyndy Ishida 
37779320a0cSCyndy Ishida   return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);
37879320a0cSCyndy Ishida }
37979320a0cSCyndy Ishida 
getSymbolSection(const Object * File,TBDKey Key,TargetList & Targets)38079320a0cSCyndy Ishida Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,
38179320a0cSCyndy Ishida                                             TargetList &Targets) {
38279320a0cSCyndy Ishida 
38379320a0cSCyndy Ishida   const Array *Section = File->getArray(Keys[Key]);
38479320a0cSCyndy Ishida   if (!Section)
38579320a0cSCyndy Ishida     return TargetsToSymbols();
38679320a0cSCyndy Ishida 
38779320a0cSCyndy Ishida   SymbolFlags SectionFlag;
38879320a0cSCyndy Ishida   switch (Key) {
38979320a0cSCyndy Ishida   case TBDKey::Reexports:
39079320a0cSCyndy Ishida     SectionFlag = SymbolFlags::Rexported;
39179320a0cSCyndy Ishida     break;
39279320a0cSCyndy Ishida   case TBDKey::Undefineds:
39379320a0cSCyndy Ishida     SectionFlag = SymbolFlags::Undefined;
39479320a0cSCyndy Ishida     break;
39579320a0cSCyndy Ishida   default:
39679320a0cSCyndy Ishida     SectionFlag = SymbolFlags::None;
39779320a0cSCyndy Ishida     break;
39879320a0cSCyndy Ishida   };
39979320a0cSCyndy Ishida 
40079320a0cSCyndy Ishida   TargetsToSymbols Result;
40179320a0cSCyndy Ishida   TargetList MappedTargets;
40279320a0cSCyndy Ishida   for (auto Val : *Section) {
40379320a0cSCyndy Ishida     auto *Obj = Val.getAsObject();
40479320a0cSCyndy Ishida     if (!Obj)
40579320a0cSCyndy Ishida       continue;
40679320a0cSCyndy Ishida 
40779320a0cSCyndy Ishida     auto TargetsOrErr = getTargets(Obj);
40879320a0cSCyndy Ishida     if (!TargetsOrErr) {
40979320a0cSCyndy Ishida       MappedTargets = Targets;
41079320a0cSCyndy Ishida       consumeError(TargetsOrErr.takeError());
41179320a0cSCyndy Ishida     } else {
41279320a0cSCyndy Ishida       MappedTargets = *TargetsOrErr;
41379320a0cSCyndy Ishida     }
4149b29de1cSCyndy Ishida     Result.emplace_back(
4159b29de1cSCyndy Ishida         std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));
41679320a0cSCyndy Ishida 
41779320a0cSCyndy Ishida     auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);
41879320a0cSCyndy Ishida     auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);
41979320a0cSCyndy Ishida     // There should be at least one valid section.
42079320a0cSCyndy Ishida     if (!DataSection && !TextSection)
42179320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(Key));
42279320a0cSCyndy Ishida 
42379320a0cSCyndy Ishida     if (DataSection) {
424b70d87bcSCyndy Ishida       auto Err = collectSymbolsFromSegment(DataSection, Result,
425b70d87bcSCyndy Ishida                                            SectionFlag | SymbolFlags::Data);
42679320a0cSCyndy Ishida       if (Err)
42779320a0cSCyndy Ishida         return std::move(Err);
42879320a0cSCyndy Ishida     }
42979320a0cSCyndy Ishida     if (TextSection) {
430b70d87bcSCyndy Ishida       auto Err = collectSymbolsFromSegment(TextSection, Result,
431b70d87bcSCyndy Ishida                                            SectionFlag | SymbolFlags::Text);
43279320a0cSCyndy Ishida       if (Err)
43379320a0cSCyndy Ishida         return std::move(Err);
43479320a0cSCyndy Ishida     }
43579320a0cSCyndy Ishida   }
43679320a0cSCyndy Ishida 
43779320a0cSCyndy Ishida   return std::move(Result);
43879320a0cSCyndy Ishida }
43979320a0cSCyndy Ishida 
getLibSection(const Object * File,TBDKey Key,TBDKey SubKey,const TargetList & Targets)44079320a0cSCyndy Ishida Expected<AttrToTargets> getLibSection(const Object *File, TBDKey Key,
44179320a0cSCyndy Ishida                                       TBDKey SubKey,
44279320a0cSCyndy Ishida                                       const TargetList &Targets) {
44379320a0cSCyndy Ishida   auto *Section = File->getArray(Keys[Key]);
44479320a0cSCyndy Ishida   if (!Section)
44579320a0cSCyndy Ishida     return AttrToTargets();
44679320a0cSCyndy Ishida 
44779320a0cSCyndy Ishida   AttrToTargets Result;
44879320a0cSCyndy Ishida   TargetList MappedTargets;
44979320a0cSCyndy Ishida   for (auto Val : *Section) {
45079320a0cSCyndy Ishida     auto *Obj = Val.getAsObject();
45179320a0cSCyndy Ishida     if (!Obj)
45279320a0cSCyndy Ishida       continue;
45379320a0cSCyndy Ishida 
45479320a0cSCyndy Ishida     auto TargetsOrErr = getTargets(Obj);
45579320a0cSCyndy Ishida     if (!TargetsOrErr) {
45679320a0cSCyndy Ishida       MappedTargets = Targets;
45779320a0cSCyndy Ishida       consumeError(TargetsOrErr.takeError());
45879320a0cSCyndy Ishida     } else {
45979320a0cSCyndy Ishida       MappedTargets = *TargetsOrErr;
46079320a0cSCyndy Ishida     }
46179320a0cSCyndy Ishida     auto Err =
46279320a0cSCyndy Ishida         collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {
46379320a0cSCyndy Ishida           Result[Key.str()] = MappedTargets;
46479320a0cSCyndy Ishida         });
46579320a0cSCyndy Ishida     if (Err)
46679320a0cSCyndy Ishida       return std::move(Err);
46779320a0cSCyndy Ishida   }
46879320a0cSCyndy Ishida 
46979320a0cSCyndy Ishida   return std::move(Result);
47079320a0cSCyndy Ishida }
47179320a0cSCyndy Ishida 
getUmbrellaSection(const Object * File,const TargetList & Targets)47279320a0cSCyndy Ishida Expected<AttrToTargets> getUmbrellaSection(const Object *File,
47379320a0cSCyndy Ishida                                            const TargetList &Targets) {
47479320a0cSCyndy Ishida   const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);
47579320a0cSCyndy Ishida   if (!Umbrella)
47679320a0cSCyndy Ishida     return AttrToTargets();
47779320a0cSCyndy Ishida 
47879320a0cSCyndy Ishida   AttrToTargets Result;
47979320a0cSCyndy Ishida   TargetList MappedTargets;
48079320a0cSCyndy Ishida   for (auto Val : *Umbrella) {
48179320a0cSCyndy Ishida     auto *Obj = Val.getAsObject();
48279320a0cSCyndy Ishida     if (!Obj)
48379320a0cSCyndy Ishida       return make_error<JSONStubError>(
48479320a0cSCyndy Ishida           getParseErrorMsg(TBDKey::ParentUmbrella));
48579320a0cSCyndy Ishida 
48679320a0cSCyndy Ishida     // Get Targets section.
48779320a0cSCyndy Ishida     auto TargetsOrErr = getTargets(Obj);
48879320a0cSCyndy Ishida     if (!TargetsOrErr) {
48979320a0cSCyndy Ishida       MappedTargets = Targets;
49079320a0cSCyndy Ishida       consumeError(TargetsOrErr.takeError());
49179320a0cSCyndy Ishida     } else {
49279320a0cSCyndy Ishida       MappedTargets = *TargetsOrErr;
49379320a0cSCyndy Ishida     }
49479320a0cSCyndy Ishida 
49579320a0cSCyndy Ishida     auto UmbrellaOrErr =
49679320a0cSCyndy Ishida         getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);
49779320a0cSCyndy Ishida     if (!UmbrellaOrErr)
49879320a0cSCyndy Ishida       return UmbrellaOrErr.takeError();
49979320a0cSCyndy Ishida     Result[UmbrellaOrErr->str()] = Targets;
50079320a0cSCyndy Ishida   }
50179320a0cSCyndy Ishida   return std::move(Result);
50279320a0cSCyndy Ishida }
50379320a0cSCyndy Ishida 
getSwiftVersion(const Object * File)50479320a0cSCyndy Ishida Expected<uint8_t> getSwiftVersion(const Object *File) {
50579320a0cSCyndy Ishida   const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);
50679320a0cSCyndy Ishida   if (!Versions)
50779320a0cSCyndy Ishida     return 0;
50879320a0cSCyndy Ishida 
50979320a0cSCyndy Ishida   for (const auto &Val : *Versions) {
51079320a0cSCyndy Ishida     const auto *Obj = Val.getAsObject();
51179320a0cSCyndy Ishida     if (!Obj)
51279320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));
51379320a0cSCyndy Ishida 
51479320a0cSCyndy Ishida     // TODO: Take first for now.
51579320a0cSCyndy Ishida     return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,
51679320a0cSCyndy Ishida                                               &Object::getInteger);
51779320a0cSCyndy Ishida   }
51879320a0cSCyndy Ishida 
51979320a0cSCyndy Ishida   return 0;
52079320a0cSCyndy Ishida }
52179320a0cSCyndy Ishida 
getPackedVersion(const Object * File,TBDKey Key)52279320a0cSCyndy Ishida Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) {
52379320a0cSCyndy Ishida   const Array *Versions = File->getArray(Keys[Key]);
52479320a0cSCyndy Ishida   if (!Versions)
52579320a0cSCyndy Ishida     return PackedVersion(1, 0, 0);
52679320a0cSCyndy Ishida 
52779320a0cSCyndy Ishida   for (const auto &Val : *Versions) {
52879320a0cSCyndy Ishida     const auto *Obj = Val.getAsObject();
52979320a0cSCyndy Ishida     if (!Obj)
53079320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(Key));
53179320a0cSCyndy Ishida 
53279320a0cSCyndy Ishida     auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {
53379320a0cSCyndy Ishida       PackedVersion PV;
53479320a0cSCyndy Ishida       auto [success, truncated] = PV.parse64(Version);
53579320a0cSCyndy Ishida       if (!success || truncated)
53679320a0cSCyndy Ishida         return std::nullopt;
53779320a0cSCyndy Ishida       return PV;
53879320a0cSCyndy Ishida     };
53979320a0cSCyndy Ishida     // TODO: Take first for now.
54079320a0cSCyndy Ishida     return getRequiredValue<StringRef, PackedVersion>(
54179320a0cSCyndy Ishida         TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),
54279320a0cSCyndy Ishida         ValidatePV);
54379320a0cSCyndy Ishida   }
54479320a0cSCyndy Ishida 
54579320a0cSCyndy Ishida   return PackedVersion(1, 0, 0);
54679320a0cSCyndy Ishida }
54779320a0cSCyndy Ishida 
getFlags(const Object * File)54879320a0cSCyndy Ishida Expected<TBDFlags> getFlags(const Object *File) {
54979320a0cSCyndy Ishida   TBDFlags Flags = TBDFlags::None;
55079320a0cSCyndy Ishida   const Array *Section = File->getArray(Keys[TBDKey::Flags]);
551913f21aeSCyndy Ishida   if (!Section || Section->empty())
55279320a0cSCyndy Ishida     return Flags;
55379320a0cSCyndy Ishida 
55479320a0cSCyndy Ishida   for (auto &Val : *Section) {
555913f21aeSCyndy Ishida     // FIXME: Flags currently apply to all target triples.
55679320a0cSCyndy Ishida     const auto *Obj = Val.getAsObject();
55779320a0cSCyndy Ishida     if (!Obj)
55879320a0cSCyndy Ishida       return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));
55979320a0cSCyndy Ishida 
56079320a0cSCyndy Ishida     auto FlagsOrErr =
56179320a0cSCyndy Ishida         collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {
56279320a0cSCyndy Ishida           TBDFlags TBDFlag =
56379320a0cSCyndy Ishida               StringSwitch<TBDFlags>(Flag)
56479320a0cSCyndy Ishida                   .Case("flat_namespace", TBDFlags::FlatNamespace)
56579320a0cSCyndy Ishida                   .Case("not_app_extension_safe",
56679320a0cSCyndy Ishida                         TBDFlags::NotApplicationExtensionSafe)
567913f21aeSCyndy Ishida                   .Case("sim_support", TBDFlags::SimulatorSupport)
568e17efa60SCyndy Ishida                   .Case("not_for_dyld_shared_cache",
569e17efa60SCyndy Ishida                         TBDFlags::OSLibNotForSharedCache)
57079320a0cSCyndy Ishida                   .Default(TBDFlags::None);
57179320a0cSCyndy Ishida           Flags |= TBDFlag;
57279320a0cSCyndy Ishida         });
57379320a0cSCyndy Ishida 
57479320a0cSCyndy Ishida     if (FlagsOrErr)
57579320a0cSCyndy Ishida       return std::move(FlagsOrErr);
57679320a0cSCyndy Ishida 
57779320a0cSCyndy Ishida     return Flags;
57879320a0cSCyndy Ishida   }
57979320a0cSCyndy Ishida 
58079320a0cSCyndy Ishida   return Flags;
58179320a0cSCyndy Ishida }
58279320a0cSCyndy Ishida 
58379320a0cSCyndy Ishida using IFPtr = std::unique_ptr<InterfaceFile>;
parseToInterfaceFile(const Object * File)58479320a0cSCyndy Ishida Expected<IFPtr> parseToInterfaceFile(const Object *File) {
58579320a0cSCyndy Ishida   auto TargetsOrErr = getTargetsSection(File);
58679320a0cSCyndy Ishida   if (!TargetsOrErr)
58779320a0cSCyndy Ishida     return TargetsOrErr.takeError();
58879320a0cSCyndy Ishida   TargetList Targets = *TargetsOrErr;
58979320a0cSCyndy Ishida 
59079320a0cSCyndy Ishida   auto NameOrErr = getNameSection(File);
59179320a0cSCyndy Ishida   if (!NameOrErr)
59279320a0cSCyndy Ishida     return NameOrErr.takeError();
59379320a0cSCyndy Ishida   StringRef Name = *NameOrErr;
59479320a0cSCyndy Ishida 
59579320a0cSCyndy Ishida   auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);
59679320a0cSCyndy Ishida   if (!CurrVersionOrErr)
59779320a0cSCyndy Ishida     return CurrVersionOrErr.takeError();
59879320a0cSCyndy Ishida   PackedVersion CurrVersion = *CurrVersionOrErr;
59979320a0cSCyndy Ishida 
60079320a0cSCyndy Ishida   auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);
60179320a0cSCyndy Ishida   if (!CompVersionOrErr)
60279320a0cSCyndy Ishida     return CompVersionOrErr.takeError();
60379320a0cSCyndy Ishida   PackedVersion CompVersion = *CompVersionOrErr;
60479320a0cSCyndy Ishida 
60579320a0cSCyndy Ishida   auto SwiftABIOrErr = getSwiftVersion(File);
60679320a0cSCyndy Ishida   if (!SwiftABIOrErr)
60779320a0cSCyndy Ishida     return SwiftABIOrErr.takeError();
60879320a0cSCyndy Ishida   uint8_t SwiftABI = *SwiftABIOrErr;
60979320a0cSCyndy Ishida 
61079320a0cSCyndy Ishida   auto FlagsOrErr = getFlags(File);
61179320a0cSCyndy Ishida   if (!FlagsOrErr)
61279320a0cSCyndy Ishida     return FlagsOrErr.takeError();
61379320a0cSCyndy Ishida   TBDFlags Flags = *FlagsOrErr;
61479320a0cSCyndy Ishida 
61579320a0cSCyndy Ishida   auto UmbrellasOrErr = getUmbrellaSection(File, Targets);
61679320a0cSCyndy Ishida   if (!UmbrellasOrErr)
61779320a0cSCyndy Ishida     return UmbrellasOrErr.takeError();
61879320a0cSCyndy Ishida   AttrToTargets Umbrellas = *UmbrellasOrErr;
61979320a0cSCyndy Ishida 
62079320a0cSCyndy Ishida   auto ClientsOrErr =
62179320a0cSCyndy Ishida       getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);
62279320a0cSCyndy Ishida   if (!ClientsOrErr)
62379320a0cSCyndy Ishida     return ClientsOrErr.takeError();
62479320a0cSCyndy Ishida   AttrToTargets Clients = *ClientsOrErr;
62579320a0cSCyndy Ishida 
62679320a0cSCyndy Ishida   auto RLOrErr =
62779320a0cSCyndy Ishida       getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);
62879320a0cSCyndy Ishida   if (!RLOrErr)
62979320a0cSCyndy Ishida     return RLOrErr.takeError();
63079320a0cSCyndy Ishida   AttrToTargets ReexportLibs = std::move(*RLOrErr);
63179320a0cSCyndy Ishida 
632b70d87bcSCyndy Ishida   auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);
633b70d87bcSCyndy Ishida   if (!RPathsOrErr)
634b70d87bcSCyndy Ishida     return RPathsOrErr.takeError();
635b70d87bcSCyndy Ishida   AttrToTargets RPaths = std::move(*RPathsOrErr);
636b70d87bcSCyndy Ishida 
63779320a0cSCyndy Ishida   auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
63879320a0cSCyndy Ishida   if (!ExportsOrErr)
63979320a0cSCyndy Ishida     return ExportsOrErr.takeError();
64079320a0cSCyndy Ishida   TargetsToSymbols Exports = std::move(*ExportsOrErr);
64179320a0cSCyndy Ishida 
64279320a0cSCyndy Ishida   auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);
64379320a0cSCyndy Ishida   if (!ReexportsOrErr)
64479320a0cSCyndy Ishida     return ReexportsOrErr.takeError();
64579320a0cSCyndy Ishida   TargetsToSymbols Reexports = std::move(*ReexportsOrErr);
64679320a0cSCyndy Ishida 
64779320a0cSCyndy Ishida   auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);
64879320a0cSCyndy Ishida   if (!UndefinedsOrErr)
64979320a0cSCyndy Ishida     return UndefinedsOrErr.takeError();
65079320a0cSCyndy Ishida   TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);
65179320a0cSCyndy Ishida 
65279320a0cSCyndy Ishida   IFPtr F(new InterfaceFile);
65379320a0cSCyndy Ishida   F->setInstallName(Name);
65479320a0cSCyndy Ishida   F->setCurrentVersion(CurrVersion);
65579320a0cSCyndy Ishida   F->setCompatibilityVersion(CompVersion);
65679320a0cSCyndy Ishida   F->setSwiftABIVersion(SwiftABI);
65779320a0cSCyndy Ishida   F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
65879320a0cSCyndy Ishida   F->setApplicationExtensionSafe(
65979320a0cSCyndy Ishida       !(Flags & TBDFlags::NotApplicationExtensionSafe));
660913f21aeSCyndy Ishida   F->setSimulatorSupport((Flags & TBDFlags::SimulatorSupport));
661e17efa60SCyndy Ishida   F->setOSLibNotForSharedCache((Flags & TBDFlags::OSLibNotForSharedCache));
66279320a0cSCyndy Ishida   for (auto &T : Targets)
66379320a0cSCyndy Ishida     F->addTarget(T);
66479320a0cSCyndy Ishida   for (auto &[Lib, Targets] : Clients)
66579320a0cSCyndy Ishida     for (auto Target : Targets)
66679320a0cSCyndy Ishida       F->addAllowableClient(Lib, Target);
66779320a0cSCyndy Ishida   for (auto &[Lib, Targets] : ReexportLibs)
66879320a0cSCyndy Ishida     for (auto Target : Targets)
66979320a0cSCyndy Ishida       F->addReexportedLibrary(Lib, Target);
67079320a0cSCyndy Ishida   for (auto &[Lib, Targets] : Umbrellas)
67179320a0cSCyndy Ishida     for (auto Target : Targets)
67279320a0cSCyndy Ishida       F->addParentUmbrella(Target, Lib);
673b70d87bcSCyndy Ishida   for (auto &[Path, Targets] : RPaths)
674b70d87bcSCyndy Ishida     for (auto Target : Targets)
675*515d3f7dSCyndy Ishida       F->addRPath(Path, Target);
67679320a0cSCyndy Ishida   for (auto &[Targets, Symbols] : Exports)
67779320a0cSCyndy Ishida     for (auto &Sym : Symbols)
67879320a0cSCyndy Ishida       F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
67979320a0cSCyndy Ishida   for (auto &[Targets, Symbols] : Reexports)
68079320a0cSCyndy Ishida     for (auto &Sym : Symbols)
68179320a0cSCyndy Ishida       F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
68279320a0cSCyndy Ishida   for (auto &[Targets, Symbols] : Undefineds)
68379320a0cSCyndy Ishida     for (auto &Sym : Symbols)
68479320a0cSCyndy Ishida       F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
68579320a0cSCyndy Ishida 
68679320a0cSCyndy Ishida   return std::move(F);
68779320a0cSCyndy Ishida }
68879320a0cSCyndy Ishida 
getInlinedLibs(const Object * File)68979320a0cSCyndy Ishida Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {
69079320a0cSCyndy Ishida   std::vector<IFPtr> IFs;
69179320a0cSCyndy Ishida   const Array *Files = File->getArray(Keys[TBDKey::Documents]);
69279320a0cSCyndy Ishida   if (!Files)
69379320a0cSCyndy Ishida     return std::move(IFs);
69479320a0cSCyndy Ishida 
69579320a0cSCyndy Ishida   for (auto Lib : *Files) {
69679320a0cSCyndy Ishida     auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());
69779320a0cSCyndy Ishida     if (!IFOrErr)
69879320a0cSCyndy Ishida       return IFOrErr.takeError();
69979320a0cSCyndy Ishida     auto IF = std::move(*IFOrErr);
70079320a0cSCyndy Ishida     IFs.emplace_back(std::move(IF));
70179320a0cSCyndy Ishida   }
70279320a0cSCyndy Ishida   return std::move(IFs);
70379320a0cSCyndy Ishida }
70479320a0cSCyndy Ishida 
70579320a0cSCyndy Ishida } // namespace StubParser
7066e55370bSBenjamin Kramer } // namespace
70779320a0cSCyndy Ishida 
70879320a0cSCyndy Ishida Expected<std::unique_ptr<InterfaceFile>>
getInterfaceFileFromJSON(StringRef JSON)70979320a0cSCyndy Ishida MachO::getInterfaceFileFromJSON(StringRef JSON) {
71079320a0cSCyndy Ishida   auto ValOrErr = parse(JSON);
71179320a0cSCyndy Ishida   if (!ValOrErr)
71279320a0cSCyndy Ishida     return ValOrErr.takeError();
71379320a0cSCyndy Ishida 
71479320a0cSCyndy Ishida   auto *Root = ValOrErr->getAsObject();
71579320a0cSCyndy Ishida   auto VersionOrErr = StubParser::getVersion(Root);
71679320a0cSCyndy Ishida   if (!VersionOrErr)
71779320a0cSCyndy Ishida     return VersionOrErr.takeError();
71879320a0cSCyndy Ishida   FileType Version = *VersionOrErr;
71979320a0cSCyndy Ishida 
72079320a0cSCyndy Ishida   Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);
72179320a0cSCyndy Ishida   auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);
72279320a0cSCyndy Ishida   if (!IFOrErr)
72379320a0cSCyndy Ishida     return IFOrErr.takeError();
72479320a0cSCyndy Ishida   (*IFOrErr)->setFileType(Version);
72579320a0cSCyndy Ishida   std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));
72679320a0cSCyndy Ishida 
72779320a0cSCyndy Ishida   auto IFsOrErr = StubParser::getInlinedLibs(Root);
72879320a0cSCyndy Ishida   if (!IFsOrErr)
72979320a0cSCyndy Ishida     return IFsOrErr.takeError();
73079320a0cSCyndy Ishida   for (auto &File : *IFsOrErr) {
73179320a0cSCyndy Ishida     File->setFileType(Version);
73279320a0cSCyndy Ishida     IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));
73379320a0cSCyndy Ishida   }
73479320a0cSCyndy Ishida   return std::move(IF);
73579320a0cSCyndy Ishida }
736d6f9b97bSCyndy Ishida 
737d6f9b97bSCyndy Ishida namespace {
738d6f9b97bSCyndy Ishida 
739d6f9b97bSCyndy Ishida template <typename ContainerT = Array>
insertNonEmptyValues(Object & Obj,TBDKey Key,ContainerT && Contents)740d6f9b97bSCyndy Ishida bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
741d6f9b97bSCyndy Ishida   if (Contents.empty())
742d6f9b97bSCyndy Ishida     return false;
743d6f9b97bSCyndy Ishida   Obj[Keys[Key]] = std::move(Contents);
744d6f9b97bSCyndy Ishida   return true;
745d6f9b97bSCyndy Ishida }
746d6f9b97bSCyndy Ishida 
getFormattedStr(const MachO::Target & Targ)747d6f9b97bSCyndy Ishida std::string getFormattedStr(const MachO::Target &Targ) {
748d6f9b97bSCyndy Ishida   std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
749d6f9b97bSCyndy Ishida                                 ? "maccatalyst"
750d6f9b97bSCyndy Ishida                                 : getOSAndEnvironmentName(Targ.Platform);
751d6f9b97bSCyndy Ishida   return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
752d6f9b97bSCyndy Ishida }
753d6f9b97bSCyndy Ishida 
754d6f9b97bSCyndy Ishida template <typename AggregateT>
serializeTargets(const AggregateT Targets,const TargetList & ActiveTargets)755d6f9b97bSCyndy Ishida std::vector<std::string> serializeTargets(const AggregateT Targets,
756d6f9b97bSCyndy Ishida                                           const TargetList &ActiveTargets) {
757d6f9b97bSCyndy Ishida   std::vector<std::string> TargetsStr;
758d6f9b97bSCyndy Ishida   if (Targets.size() == ActiveTargets.size())
759d6f9b97bSCyndy Ishida     return TargetsStr;
760d6f9b97bSCyndy Ishida 
7616da470d7SKazu Hirata   for (const MachO::Target &Target : Targets)
762d6f9b97bSCyndy Ishida     TargetsStr.emplace_back(getFormattedStr(Target));
7636da470d7SKazu Hirata 
764d6f9b97bSCyndy Ishida   return TargetsStr;
765d6f9b97bSCyndy Ishida }
766d6f9b97bSCyndy Ishida 
serializeTargetInfo(const TargetList & ActiveTargets)767d6f9b97bSCyndy Ishida Array serializeTargetInfo(const TargetList &ActiveTargets) {
768d6f9b97bSCyndy Ishida   Array Targets;
769d6f9b97bSCyndy Ishida   for (const auto Targ : ActiveTargets) {
770d6f9b97bSCyndy Ishida     Object TargetInfo;
771f5016597SCyndy Ishida     if (!Targ.MinDeployment.empty())
772d6f9b97bSCyndy Ishida       TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();
773d6f9b97bSCyndy Ishida     TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
774d6f9b97bSCyndy Ishida     Targets.emplace_back(std::move(TargetInfo));
775d6f9b97bSCyndy Ishida   }
776d6f9b97bSCyndy Ishida   return Targets;
777d6f9b97bSCyndy Ishida }
778d6f9b97bSCyndy Ishida 
779d6f9b97bSCyndy Ishida template <typename ValueT, typename EntryT = ValueT>
serializeScalar(TBDKey Key,ValueT Value,ValueT Default=ValueT ())780d6f9b97bSCyndy Ishida Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
781d6f9b97bSCyndy Ishida   if (Value == Default)
782d6f9b97bSCyndy Ishida     return {};
783d6f9b97bSCyndy Ishida   Array Container;
784d6f9b97bSCyndy Ishida   Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
785d6f9b97bSCyndy Ishida 
786d6f9b97bSCyndy Ishida   Container.emplace_back(std::move(ScalarObj));
787d6f9b97bSCyndy Ishida   return Container;
788d6f9b97bSCyndy Ishida }
789d6f9b97bSCyndy Ishida 
790d6f9b97bSCyndy Ishida using TargetsToValuesMap =
791d6f9b97bSCyndy Ishida     std::map<std::vector<std::string>, std::vector<std::string>>;
792d6f9b97bSCyndy Ishida 
793d6f9b97bSCyndy Ishida template <typename AggregateT = TargetsToValuesMap>
serializeAttrToTargets(AggregateT & Entries,TBDKey Key)794d6f9b97bSCyndy Ishida Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
795d6f9b97bSCyndy Ishida   Array Container;
796d6f9b97bSCyndy Ishida   for (const auto &[Targets, Values] : Entries) {
797d6f9b97bSCyndy Ishida     Object Obj;
798d6f9b97bSCyndy Ishida     insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
799d6f9b97bSCyndy Ishida     Obj[Keys[Key]] = Values;
800d6f9b97bSCyndy Ishida     Container.emplace_back(std::move(Obj));
801d6f9b97bSCyndy Ishida   }
802d6f9b97bSCyndy Ishida   return Container;
803d6f9b97bSCyndy Ishida }
804d6f9b97bSCyndy Ishida 
805d6f9b97bSCyndy Ishida template <typename ValueT = std::string,
806d6f9b97bSCyndy Ishida           typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
serializeField(TBDKey Key,const AggregateT & Values,const TargetList & ActiveTargets,bool IsArray=true)807d6f9b97bSCyndy Ishida Array serializeField(TBDKey Key, const AggregateT &Values,
808d6f9b97bSCyndy Ishida                      const TargetList &ActiveTargets, bool IsArray = true) {
809d6f9b97bSCyndy Ishida   std::map<ValueT, std::set<MachO::Target>> Entries;
810d6f9b97bSCyndy Ishida   for (const auto &[Target, Val] : Values)
811d6f9b97bSCyndy Ishida     Entries[Val].insert(Target);
812d6f9b97bSCyndy Ishida 
813d6f9b97bSCyndy Ishida   if (!IsArray) {
814d6f9b97bSCyndy Ishida     std::map<std::vector<std::string>, std::string> FinalEntries;
815d6f9b97bSCyndy Ishida     for (const auto &[Val, Targets] : Entries)
816d6f9b97bSCyndy Ishida       FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
817d6f9b97bSCyndy Ishida     return serializeAttrToTargets(FinalEntries, Key);
818d6f9b97bSCyndy Ishida   }
819d6f9b97bSCyndy Ishida 
820d6f9b97bSCyndy Ishida   TargetsToValuesMap FinalEntries;
821d6f9b97bSCyndy Ishida   for (const auto &[Val, Targets] : Entries)
822d6f9b97bSCyndy Ishida     FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
823d6f9b97bSCyndy Ishida   return serializeAttrToTargets(FinalEntries, Key);
824d6f9b97bSCyndy Ishida }
825d6f9b97bSCyndy Ishida 
serializeField(TBDKey Key,const std::vector<InterfaceFileRef> & Values,const TargetList & ActiveTargets)826d6f9b97bSCyndy Ishida Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
827d6f9b97bSCyndy Ishida                      const TargetList &ActiveTargets) {
828d6f9b97bSCyndy Ishida   TargetsToValuesMap FinalEntries;
829d6f9b97bSCyndy Ishida   for (const auto &Ref : Values) {
830d6f9b97bSCyndy Ishida     TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
831d6f9b97bSCyndy Ishida     FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
832d6f9b97bSCyndy Ishida         Ref.getInstallName());
833d6f9b97bSCyndy Ishida   }
834d6f9b97bSCyndy Ishida   return serializeAttrToTargets(FinalEntries, Key);
835d6f9b97bSCyndy Ishida }
836d6f9b97bSCyndy Ishida 
837d6f9b97bSCyndy Ishida struct SymbolFields {
838d6f9b97bSCyndy Ishida   struct SymbolTypes {
839d6f9b97bSCyndy Ishida     std::vector<StringRef> Weaks;
840d6f9b97bSCyndy Ishida     std::vector<StringRef> Globals;
841d6f9b97bSCyndy Ishida     std::vector<StringRef> TLV;
842d6f9b97bSCyndy Ishida     std::vector<StringRef> ObjCClasses;
843d6f9b97bSCyndy Ishida     std::vector<StringRef> IVars;
844d6f9b97bSCyndy Ishida     std::vector<StringRef> EHTypes;
845d6f9b97bSCyndy Ishida 
empty__anon2c77c6df0c11::SymbolFields::SymbolTypes846d6f9b97bSCyndy Ishida     bool empty() const {
847d6f9b97bSCyndy Ishida       return Weaks.empty() && Globals.empty() && TLV.empty() &&
848d6f9b97bSCyndy Ishida              ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
849d6f9b97bSCyndy Ishida     }
850d6f9b97bSCyndy Ishida   };
851d6f9b97bSCyndy Ishida   SymbolTypes Data;
852d6f9b97bSCyndy Ishida   SymbolTypes Text;
853d6f9b97bSCyndy Ishida };
854d6f9b97bSCyndy Ishida 
serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,const TargetList & ActiveTargets)855d6f9b97bSCyndy Ishida Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,
856d6f9b97bSCyndy Ishida                        const TargetList &ActiveTargets) {
857d6f9b97bSCyndy Ishida   auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
858d6f9b97bSCyndy Ishida                                 const Symbol *Sym) {
859d6f9b97bSCyndy Ishida     switch (Sym->getKind()) {
860d9a9872eSCyndy Ishida     case EncodeKind::ObjectiveCClass:
861d6f9b97bSCyndy Ishida       Assignment.ObjCClasses.emplace_back(Sym->getName());
862d6f9b97bSCyndy Ishida       return;
863d9a9872eSCyndy Ishida     case EncodeKind::ObjectiveCClassEHType:
864d6f9b97bSCyndy Ishida       Assignment.EHTypes.emplace_back(Sym->getName());
865d6f9b97bSCyndy Ishida       return;
866d9a9872eSCyndy Ishida     case EncodeKind::ObjectiveCInstanceVariable:
867d6f9b97bSCyndy Ishida       Assignment.IVars.emplace_back(Sym->getName());
868d6f9b97bSCyndy Ishida       return;
869d9a9872eSCyndy Ishida     case EncodeKind::GlobalSymbol: {
870d6f9b97bSCyndy Ishida       if (Sym->isWeakReferenced() || Sym->isWeakDefined())
871d6f9b97bSCyndy Ishida         Assignment.Weaks.emplace_back(Sym->getName());
872d6f9b97bSCyndy Ishida       else if (Sym->isThreadLocalValue())
873d6f9b97bSCyndy Ishida         Assignment.TLV.emplace_back(Sym->getName());
874d6f9b97bSCyndy Ishida       else
875d6f9b97bSCyndy Ishida         Assignment.Globals.emplace_back(Sym->getName());
876d6f9b97bSCyndy Ishida       return;
877d6f9b97bSCyndy Ishida     }
878d6f9b97bSCyndy Ishida     }
879d6f9b97bSCyndy Ishida   };
880d6f9b97bSCyndy Ishida 
881d6f9b97bSCyndy Ishida   std::map<std::vector<std::string>, SymbolFields> Entries;
882d6f9b97bSCyndy Ishida   for (const auto *Sym : Symbols) {
883d6f9b97bSCyndy Ishida     std::set<MachO::Target> Targets{Sym->targets().begin(),
884d6f9b97bSCyndy Ishida                                     Sym->targets().end()};
885d6f9b97bSCyndy Ishida     auto JSONTargets = serializeTargets(Targets, ActiveTargets);
886d6f9b97bSCyndy Ishida     if (Sym->isData())
887d6f9b97bSCyndy Ishida       AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
888d6f9b97bSCyndy Ishida     else if (Sym->isText())
889d6f9b97bSCyndy Ishida       AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
890d6f9b97bSCyndy Ishida     else
891d6f9b97bSCyndy Ishida       llvm_unreachable("unexpected symbol type");
892d6f9b97bSCyndy Ishida   }
893d6f9b97bSCyndy Ishida 
894d6f9b97bSCyndy Ishida   auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
895d6f9b97bSCyndy Ishida                                 SymbolFields::SymbolTypes &SymField) {
896d6f9b97bSCyndy Ishida     if (SymField.empty())
897d6f9b97bSCyndy Ishida       return;
898d6f9b97bSCyndy Ishida     Object Segment;
899d6f9b97bSCyndy Ishida     insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
900d6f9b97bSCyndy Ishida     insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
901d6f9b97bSCyndy Ishida     insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
902d6f9b97bSCyndy Ishida     insertNonEmptyValues(Segment, TBDKey::ObjCClass,
903d6f9b97bSCyndy Ishida                          std::move(SymField.ObjCClasses));
904d6f9b97bSCyndy Ishida     insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
905d6f9b97bSCyndy Ishida                          std::move(SymField.EHTypes));
906d6f9b97bSCyndy Ishida     insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
907d6f9b97bSCyndy Ishida     insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
908d6f9b97bSCyndy Ishida   };
909d6f9b97bSCyndy Ishida 
910d6f9b97bSCyndy Ishida   Array SymbolSection;
911d6f9b97bSCyndy Ishida   for (auto &[Targets, Fields] : Entries) {
912d6f9b97bSCyndy Ishida     Object AllSyms;
913d6f9b97bSCyndy Ishida     insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
914d6f9b97bSCyndy Ishida     InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
915d6f9b97bSCyndy Ishida     InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
916d6f9b97bSCyndy Ishida     SymbolSection.emplace_back(std::move(AllSyms));
917d6f9b97bSCyndy Ishida   }
918d6f9b97bSCyndy Ishida 
919d6f9b97bSCyndy Ishida   return SymbolSection;
920d6f9b97bSCyndy Ishida }
921d6f9b97bSCyndy Ishida 
serializeFlags(const InterfaceFile * File)922d6f9b97bSCyndy Ishida Array serializeFlags(const InterfaceFile *File) {
923d6f9b97bSCyndy Ishida   // TODO: Give all Targets the same flags for now.
924d6f9b97bSCyndy Ishida   Array Flags;
925d6f9b97bSCyndy Ishida   if (!File->isTwoLevelNamespace())
926d6f9b97bSCyndy Ishida     Flags.emplace_back("flat_namespace");
927d6f9b97bSCyndy Ishida   if (!File->isApplicationExtensionSafe())
928d6f9b97bSCyndy Ishida     Flags.emplace_back("not_app_extension_safe");
929913f21aeSCyndy Ishida   if (File->hasSimulatorSupport())
930913f21aeSCyndy Ishida     Flags.emplace_back("sim_support");
931e17efa60SCyndy Ishida   if (File->isOSLibNotForSharedCache())
932e17efa60SCyndy Ishida     Flags.emplace_back("not_for_dyld_shared_cache");
933d6f9b97bSCyndy Ishida   return serializeScalar(TBDKey::Attributes, std::move(Flags));
934d6f9b97bSCyndy Ishida }
935d6f9b97bSCyndy Ishida 
serializeIF(const InterfaceFile * File)936d6f9b97bSCyndy Ishida Expected<Object> serializeIF(const InterfaceFile *File) {
937d6f9b97bSCyndy Ishida   Object Library;
938d6f9b97bSCyndy Ishida 
939d6f9b97bSCyndy Ishida   // Handle required keys.
940d6f9b97bSCyndy Ishida   TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
941d6f9b97bSCyndy Ishida   if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
942d6f9b97bSCyndy Ishida                             serializeTargetInfo(ActiveTargets)))
943d6f9b97bSCyndy Ishida     return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
944d6f9b97bSCyndy Ishida 
945d6f9b97bSCyndy Ishida   Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
946d6f9b97bSCyndy Ishida   if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
947d6f9b97bSCyndy Ishida     return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
948d6f9b97bSCyndy Ishida 
949d6f9b97bSCyndy Ishida   // Handle optional keys.
950d6f9b97bSCyndy Ishida   Array Flags = serializeFlags(File);
951d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
952d6f9b97bSCyndy Ishida 
953d6f9b97bSCyndy Ishida   Array CurrentV = serializeScalar<PackedVersion, std::string>(
954d6f9b97bSCyndy Ishida       TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
955d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
956d6f9b97bSCyndy Ishida 
957d6f9b97bSCyndy Ishida   Array CompatV = serializeScalar<PackedVersion, std::string>(
958d6f9b97bSCyndy Ishida       TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
959d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
960d6f9b97bSCyndy Ishida                        std::move(CompatV));
961d6f9b97bSCyndy Ishida 
962d6f9b97bSCyndy Ishida   Array SwiftABI = serializeScalar<uint8_t, int64_t>(
963d6f9b97bSCyndy Ishida       TBDKey::ABI, File->getSwiftABIVersion(), 0u);
964d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
965d6f9b97bSCyndy Ishida 
966d6f9b97bSCyndy Ishida   Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
967d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
968d6f9b97bSCyndy Ishida 
969d6f9b97bSCyndy Ishida   Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
970d6f9b97bSCyndy Ishida                                    ActiveTargets, /*IsArray=*/false);
971d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
972d6f9b97bSCyndy Ishida 
973d6f9b97bSCyndy Ishida   Array Clients =
974d6f9b97bSCyndy Ishida       serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
975d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
976d6f9b97bSCyndy Ishida 
977d6f9b97bSCyndy Ishida   Array ReexportLibs =
978d6f9b97bSCyndy Ishida       serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
979d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
980d6f9b97bSCyndy Ishida 
981d6f9b97bSCyndy Ishida   // Handle symbols.
982d6f9b97bSCyndy Ishida   Array Exports = serializeSymbols(File->exports(), ActiveTargets);
983d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
984d6f9b97bSCyndy Ishida 
985d6f9b97bSCyndy Ishida   Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
986d6f9b97bSCyndy Ishida   insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
987d6f9b97bSCyndy Ishida 
988d6f9b97bSCyndy Ishida   if (!File->isTwoLevelNamespace()) {
989d6f9b97bSCyndy Ishida     Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
990d6f9b97bSCyndy Ishida     insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
991d6f9b97bSCyndy Ishida   }
992d6f9b97bSCyndy Ishida 
993d6f9b97bSCyndy Ishida   return std::move(Library);
994d6f9b97bSCyndy Ishida }
995d6f9b97bSCyndy Ishida 
getJSON(const InterfaceFile * File,const FileType FileKind)996455bf3d1SCyndy Ishida Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {
997455bf3d1SCyndy Ishida   assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");
998d6f9b97bSCyndy Ishida   Object Root;
999d6f9b97bSCyndy Ishida 
1000d6f9b97bSCyndy Ishida   auto MainLibOrErr = serializeIF(File);
1001d6f9b97bSCyndy Ishida   if (!MainLibOrErr)
1002d6f9b97bSCyndy Ishida     return MainLibOrErr;
1003d6f9b97bSCyndy Ishida   Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
1004d6f9b97bSCyndy Ishida   Array Documents;
1005d6f9b97bSCyndy Ishida   for (const auto &Doc : File->documents()) {
1006d6f9b97bSCyndy Ishida     auto LibOrErr = serializeIF(Doc.get());
1007d6f9b97bSCyndy Ishida     if (!LibOrErr)
1008d6f9b97bSCyndy Ishida       return LibOrErr;
1009d6f9b97bSCyndy Ishida     Documents.emplace_back(std::move(*LibOrErr));
1010d6f9b97bSCyndy Ishida   }
1011d6f9b97bSCyndy Ishida 
1012d6f9b97bSCyndy Ishida   Root[Keys[TBDKey::TBDVersion]] = 5;
1013d6f9b97bSCyndy Ishida   insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
1014d6f9b97bSCyndy Ishida   return std::move(Root);
1015d6f9b97bSCyndy Ishida }
1016d6f9b97bSCyndy Ishida 
1017d6f9b97bSCyndy Ishida } // namespace
1018d6f9b97bSCyndy Ishida 
serializeInterfaceFileToJSON(raw_ostream & OS,const InterfaceFile & File,const FileType FileKind,bool Compact)1019d6f9b97bSCyndy Ishida Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,
1020d6f9b97bSCyndy Ishida                                           const InterfaceFile &File,
1021455bf3d1SCyndy Ishida                                           const FileType FileKind,
1022d6f9b97bSCyndy Ishida                                           bool Compact) {
1023455bf3d1SCyndy Ishida   auto TextFile = getJSON(&File, FileKind);
1024d6f9b97bSCyndy Ishida   if (!TextFile)
1025d6f9b97bSCyndy Ishida     return TextFile.takeError();
1026d6f9b97bSCyndy Ishida   if (Compact)
1027d6f9b97bSCyndy Ishida     OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
1028d6f9b97bSCyndy Ishida   else
1029d6f9b97bSCyndy Ishida     OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
1030d6f9b97bSCyndy Ishida   return Error::success();
1031d6f9b97bSCyndy Ishida }
1032