summaryrefslogtreecommitdiff
path: root/llvm/lib/TextAPI/InterfaceFile.cpp
diff options
context:
space:
mode:
authorCyndy Ishida <cyndy_ishida@apple.com>2023-07-25 08:32:28 -0700
committerCyndy Ishida <cyndy_ishida@apple.com>2023-07-25 09:23:57 -0700
commit16c1f43642e40dbc0d59fcf68ed1682dbf4d87bd (patch)
tree4e08556552e9ef8ac00af498ebdb24399e67d1ae /llvm/lib/TextAPI/InterfaceFile.cpp
parent0478ef2d366c6f88678e37d54190dcdaa0ec69da (diff)
[TextAPI] Add functionality to manipulate over InterfaceFiles
InterfaceFile is the in-memory representation for tbd files. Add APIs to merge, extract, remove, and inline reexported libraries. Reviewed By: zixuw Differential Revision: https://reviews.llvm.org/D153398
Diffstat (limited to 'llvm/lib/TextAPI/InterfaceFile.cpp')
-rw-r--r--llvm/lib/TextAPI/InterfaceFile.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/llvm/lib/TextAPI/InterfaceFile.cpp b/llvm/lib/TextAPI/InterfaceFile.cpp
index b7f967aa754e..b9ea02d8e097 100644
--- a/llvm/lib/TextAPI/InterfaceFile.cpp
+++ b/llvm/lib/TextAPI/InterfaceFile.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/TextAPI/InterfaceFile.h"
+#include "llvm/TextAPI/TextAPIError.h"
#include <iomanip>
#include <sstream>
@@ -81,6 +82,267 @@ void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
Documents.insert(Pos, Document);
}
+void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library,
+ bool Overwrite) {
+ auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) {
+ auto It = lower_bound(
+ Documents, Reexport->getInstallName(),
+ [](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) {
+ return Lhs->getInstallName() < Rhs;
+ });
+
+ if (Overwrite && It != Documents.end() &&
+ Reexport->getInstallName() == (*It)->getInstallName()) {
+ std::replace(Documents.begin(), Documents.end(), *It,
+ std::move(Reexport));
+ return;
+ }
+
+ if ((It != Documents.end()) &&
+ !(Reexport->getInstallName() < (*It)->getInstallName()))
+ return;
+
+ Documents.emplace(It, std::move(Reexport));
+ };
+ for (auto Doc : Library->documents())
+ AddFwk(std::move(Doc));
+
+ Library->Documents.clear();
+ AddFwk(std::move(Library));
+}
+
+Expected<std::unique_ptr<InterfaceFile>>
+InterfaceFile::merge(const InterfaceFile *O) const {
+ // Verify files can be merged.
+ if (getInstallName() != O->getInstallName()) {
+ return make_error<StringError>("install names do not match",
+ inconvertibleErrorCode());
+ }
+
+ if (getCurrentVersion() != O->getCurrentVersion()) {
+ return make_error<StringError>("current versions do not match",
+ inconvertibleErrorCode());
+ }
+
+ if (getCompatibilityVersion() != O->getCompatibilityVersion()) {
+ return make_error<StringError>("compatibility versions do not match",
+ inconvertibleErrorCode());
+ }
+
+ if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&
+ (getSwiftABIVersion() != O->getSwiftABIVersion())) {
+ return make_error<StringError>("swift ABI versions do not match",
+ inconvertibleErrorCode());
+ }
+
+ if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {
+ return make_error<StringError>("two level namespace flags do not match",
+ inconvertibleErrorCode());
+ }
+
+ if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {
+ return make_error<StringError>(
+ "application extension safe flags do not match",
+ inconvertibleErrorCode());
+ }
+
+ std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
+ IF->setFileType(std::max(getFileType(), O->getFileType()));
+ IF->setPath(getPath());
+ IF->setInstallName(getInstallName());
+ IF->setCurrentVersion(getCurrentVersion());
+ IF->setCompatibilityVersion(getCompatibilityVersion());
+
+ if (getSwiftABIVersion() == 0)
+ IF->setSwiftABIVersion(O->getSwiftABIVersion());
+ else
+ IF->setSwiftABIVersion(getSwiftABIVersion());
+
+ IF->setTwoLevelNamespace(isTwoLevelNamespace());
+ IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
+
+ for (const auto &It : umbrellas()) {
+ if (!It.second.empty())
+ IF->addParentUmbrella(It.first, It.second);
+ }
+ for (const auto &It : O->umbrellas()) {
+ if (!It.second.empty())
+ IF->addParentUmbrella(It.first, It.second);
+ }
+ IF->addTargets(targets());
+ IF->addTargets(O->targets());
+
+ for (const auto &Lib : allowableClients())
+ for (const auto &Target : Lib.targets())
+ IF->addAllowableClient(Lib.getInstallName(), Target);
+
+ for (const auto &Lib : O->allowableClients())
+ for (const auto &Target : Lib.targets())
+ IF->addAllowableClient(Lib.getInstallName(), Target);
+
+ for (const auto &Lib : reexportedLibraries())
+ for (const auto &Target : Lib.targets())
+ IF->addReexportedLibrary(Lib.getInstallName(), Target);
+
+ for (const auto &Lib : O->reexportedLibraries())
+ for (const auto &Target : Lib.targets())
+ IF->addReexportedLibrary(Lib.getInstallName(), Target);
+
+ for (const auto &[Target, Path] : rpaths())
+ IF->addRPath(Target, Path);
+ for (const auto &[Target, Path] : O->rpaths())
+ IF->addRPath(Target, Path);
+
+ for (const auto *Sym : symbols()) {
+ IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
+ Sym->getFlags());
+ }
+
+ for (const auto *Sym : O->symbols()) {
+ IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
+ Sym->getFlags());
+ }
+
+ return std::move(IF);
+}
+
+Expected<std::unique_ptr<InterfaceFile>>
+InterfaceFile::remove(Architecture Arch) const {
+ if (getArchitectures() == Arch)
+ return make_error<StringError>("cannot remove last architecture slice '" +
+ getArchitectureName(Arch) + "'",
+ inconvertibleErrorCode());
+
+ if (!getArchitectures().has(Arch)) {
+ bool Found = false;
+ for (auto &Doc : Documents) {
+ if (Doc->getArchitectures().has(Arch)) {
+ Found = true;
+ break;
+ }
+ }
+
+ if (!Found)
+ return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
+ }
+
+ std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
+ IF->setFileType(getFileType());
+ IF->setPath(getPath());
+ IF->addTargets(targets(ArchitectureSet::All().clear(Arch)));
+ IF->setInstallName(getInstallName());
+ IF->setCurrentVersion(getCurrentVersion());
+ IF->setCompatibilityVersion(getCompatibilityVersion());
+ IF->setSwiftABIVersion(getSwiftABIVersion());
+ IF->setTwoLevelNamespace(isTwoLevelNamespace());
+ IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
+ for (const auto &It : umbrellas())
+ if (It.first.Arch != Arch)
+ IF->addParentUmbrella(It.first, It.second);
+
+ for (const auto &Lib : allowableClients()) {
+ for (const auto &Target : Lib.targets())
+ if (Target.Arch != Arch)
+ IF->addAllowableClient(Lib.getInstallName(), Target);
+ }
+
+ for (const auto &Lib : reexportedLibraries()) {
+ for (const auto &Target : Lib.targets())
+ if (Target.Arch != Arch)
+ IF->addReexportedLibrary(Lib.getInstallName(), Target);
+ }
+
+ for (const auto *Sym : symbols()) {
+ auto Archs = Sym->getArchitectures();
+ Archs.clear(Arch);
+ if (Archs.empty())
+ continue;
+
+ IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs),
+ Sym->getFlags());
+ }
+
+ for (auto &Doc : Documents) {
+ // Skip the inlined document if the to be removed architecture is the
+ // only one left.
+ if (Doc->getArchitectures() == Arch)
+ continue;
+
+ // If the document doesn't contain the arch, then no work is to be done
+ // and it can be copied over.
+ if (!Doc->getArchitectures().has(Arch)) {
+ auto NewDoc = Doc;
+ IF->addDocument(std::move(NewDoc));
+ continue;
+ }
+
+ auto Result = Doc->remove(Arch);
+ if (!Result)
+ return Result;
+
+ IF->addDocument(std::move(Result.get()));
+ }
+
+ return std::move(IF);
+}
+
+Expected<std::unique_ptr<InterfaceFile>>
+InterfaceFile::extract(Architecture Arch) const {
+ if (!getArchitectures().has(Arch)) {
+ return make_error<StringError>("file doesn't have architecture '" +
+ getArchitectureName(Arch) + "'",
+ inconvertibleErrorCode());
+ }
+
+ std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
+ IF->setFileType(getFileType());
+ IF->setPath(getPath());
+ IF->addTargets(targets(Arch));
+ IF->setInstallName(getInstallName());
+ IF->setCurrentVersion(getCurrentVersion());
+ IF->setCompatibilityVersion(getCompatibilityVersion());
+ IF->setSwiftABIVersion(getSwiftABIVersion());
+ IF->setTwoLevelNamespace(isTwoLevelNamespace());
+ IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
+ for (const auto &It : umbrellas())
+ if (It.first.Arch == Arch)
+ IF->addParentUmbrella(It.first, It.second);
+
+ for (const auto &It : rpaths())
+ if (It.first.Arch == Arch)
+ IF->addRPath(It.first, It.second);
+
+ for (const auto &Lib : allowableClients())
+ for (const auto &Target : Lib.targets())
+ if (Target.Arch == Arch)
+ IF->addAllowableClient(Lib.getInstallName(), Target);
+
+ for (const auto &Lib : reexportedLibraries())
+ for (const auto &Target : Lib.targets())
+ if (Target.Arch == Arch)
+ IF->addReexportedLibrary(Lib.getInstallName(), Target);
+
+ for (const auto *Sym : symbols()) {
+ if (Sym->hasArchitecture(Arch))
+ IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch),
+ Sym->getFlags());
+ }
+
+ for (auto &Doc : Documents) {
+ // Skip documents that don't have the requested architecture.
+ if (!Doc->getArchitectures().has(Arch))
+ continue;
+
+ auto Result = Doc->extract(Arch);
+ if (!Result)
+ return Result;
+
+ IF->addDocument(std::move(Result.get()));
+ }
+
+ return std::move(IF);
+}
+
static bool isYAMLTextStub(const FileType &Kind) {
return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
}