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