aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp401
1 files changed, 401 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp b/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp
new file mode 100644
index 000000000000..d712ed386825
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp
@@ -0,0 +1,401 @@
+//===- InterfaceFile.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements the Interface File.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TextAPI/InterfaceFile.h"
+#include "llvm/TextAPI/TextAPIError.h"
+#include <iomanip>
+#include <sstream>
+
+using namespace llvm;
+using namespace llvm::MachO;
+
+void InterfaceFileRef::addTarget(const Target &Target) {
+ addEntry(Targets, Target);
+}
+
+void InterfaceFile::addAllowableClient(StringRef InstallName,
+ const Target &Target) {
+ if (InstallName.empty())
+ return;
+ auto Client = addEntry(AllowableClients, InstallName);
+ Client->addTarget(Target);
+}
+
+void InterfaceFile::addReexportedLibrary(StringRef InstallName,
+ const Target &Target) {
+ if (InstallName.empty())
+ return;
+ auto Lib = addEntry(ReexportedLibraries, InstallName);
+ Lib->addTarget(Target);
+}
+
+void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) {
+ if (Parent.empty())
+ return;
+ auto Iter = lower_bound(ParentUmbrellas, Target_,
+ [](const std::pair<Target, std::string> &LHS,
+ Target RHS) { return LHS.first < RHS; });
+
+ if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) {
+ Iter->second = std::string(Parent);
+ return;
+ }
+
+ ParentUmbrellas.emplace(Iter, Target_, std::string(Parent));
+}
+
+void InterfaceFile::addRPath(const Target &InputTarget, StringRef RPath) {
+ if (RPath.empty())
+ return;
+ using RPathEntryT = const std::pair<Target, std::string>;
+ RPathEntryT Entry(InputTarget, RPath);
+ auto Iter =
+ lower_bound(RPaths, Entry,
+ [](RPathEntryT &LHS, RPathEntryT &RHS) { return LHS < RHS; });
+
+ if ((Iter != RPaths.end()) && (*Iter == Entry))
+ return;
+
+ RPaths.emplace(Iter, Entry);
+}
+
+void InterfaceFile::addTarget(const Target &Target) {
+ addEntry(Targets, Target);
+}
+
+InterfaceFile::const_filtered_target_range
+InterfaceFile::targets(ArchitectureSet Archs) const {
+ std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {
+ return Archs.has(Target_.Arch);
+ };
+ return make_filter_range(Targets, fn);
+}
+
+void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
+ auto Pos = llvm::lower_bound(Documents, Document,
+ [](const std::shared_ptr<InterfaceFile> &LHS,
+ const std::shared_ptr<InterfaceFile> &RHS) {
+ return LHS->InstallName < RHS->InstallName;
+ });
+ Document->Parent = this;
+ 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);
+}
+
+bool InterfaceFile::operator==(const InterfaceFile &O) const {
+ if (Targets != O.Targets)
+ return false;
+ if (InstallName != O.InstallName)
+ return false;
+ if ((CurrentVersion != O.CurrentVersion) ||
+ (CompatibilityVersion != O.CompatibilityVersion))
+ return false;
+ if (SwiftABIVersion != O.SwiftABIVersion)
+ return false;
+ if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)
+ return false;
+ if (IsAppExtensionSafe != O.IsAppExtensionSafe)
+ return false;
+ if (IsOSLibNotForSharedCache != O.IsOSLibNotForSharedCache)
+ return false;
+ if (HasSimSupport != O.HasSimSupport)
+ return false;
+ if (ParentUmbrellas != O.ParentUmbrellas)
+ return false;
+ if (AllowableClients != O.AllowableClients)
+ return false;
+ if (ReexportedLibraries != O.ReexportedLibraries)
+ return false;
+ if (*SymbolsSet != *O.SymbolsSet)
+ return false;
+ // Don't compare run search paths for older filetypes that cannot express
+ // them.
+ if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) {
+ if (RPaths != O.RPaths)
+ return false;
+ if (mapToPlatformVersionSet(Targets) != mapToPlatformVersionSet(O.Targets))
+ return false;
+ }
+
+ if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(),
+ O.Documents.end(),
+ [](const std::shared_ptr<InterfaceFile> LHS,
+ const std::shared_ptr<InterfaceFile> RHS) {
+ return *LHS == *RHS;
+ }))
+ return false;
+ return true;
+}