1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[llvm][TextAPI] add equality operator for InterfaceFile

This patch adds functionality to compare for the equality between `InterfaceFile`s based on attributes specific to linking.

Reviewed By: cishida, steven_wu

Differential Revision: https://reviews.llvm.org/D96629
This commit is contained in:
Sam Powell 2021-02-18 11:27:54 -08:00 committed by Cyndy Ishida
parent c0b486e8f3
commit 3bda5a764e
6 changed files with 439 additions and 3 deletions

View File

@ -336,9 +336,7 @@ public:
/// Add a library for inlining to top level library.
///
///\param Document The library to inline with top level library.
void addDocument(std::shared_ptr<InterfaceFile> &&Document) {
Documents.emplace_back(std::move(Document));
}
void addDocument(std::shared_ptr<InterfaceFile> &&Document);
/// Get the list of inlined libraries.
///
@ -397,6 +395,14 @@ public:
fn);
}
/// The equality is determined by attributes that impact linking
/// compatibilities. UUIDs, Path, & FileKind are irrelevant since these by
/// itself should not impact linking.
/// This is an expensive operation.
bool operator==(const InterfaceFile &O) const;
bool operator!=(const InterfaceFile &O) const { return !(*this == O); }
private:
llvm::BumpPtrAllocator Allocator;
StringRef copyString(StringRef String) {
@ -427,6 +433,21 @@ private:
SymbolMapType Symbols;
};
template <typename DerivedT, typename KeyInfoT, typename BucketT>
bool operator==(const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
KeyInfoT, BucketT> &LHS,
const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *,
KeyInfoT, BucketT> &RHS) {
if (LHS.size() != RHS.size())
return false;
for (auto KV : LHS) {
auto I = RHS.find(KV.first);
if (I == RHS.end() || *I->second != *KV.second)
return false;
}
return true;
}
} // end namespace MachO.
} // end namespace llvm.

View File

@ -104,6 +104,15 @@ public:
void dump() const { dump(llvm::errs()); }
#endif
bool operator==(const Symbol &O) const {
return (Kind == O.Kind) && (Name == O.Name) && (Targets == O.Targets) &&
(Flags == O.Flags);
}
bool operator!=(const Symbol &O) const {
return !(*this == O);
}
private:
StringRef Name;
TargetList Targets;

View File

@ -117,3 +117,46 @@ void InterfaceFile::addSymbol(SymbolKind Kind, StringRef Name,
for (const auto &Target : Targets)
result.first->second->addTarget(Target);
}
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;
});
Documents.insert(Pos, Document);
}
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 (IsInstallAPI != O.IsInstallAPI)
return false;
if (ParentUmbrellas != O.ParentUmbrellas)
return false;
if (AllowableClients != O.AllowableClients)
return false;
if (ReexportedLibraries != O.ReexportedLibraries)
return false;
if (Symbols != O.Symbols)
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;
}

View File

@ -40,5 +40,24 @@ inline std::string stripWhitespace(std::string S) {
S.erase(std::remove_if(S.begin(), S.end(), ::isspace), S.end());
return S;
}
// This will transform a single InterfaceFile then compare against the other
// InterfaceFile then transform the second InterfaceFile in the same way to
// regain equality.
inline bool
checkEqualityOnTransform(MachO::InterfaceFile &FileA,
MachO::InterfaceFile &FileB,
void (*Transform)(MachO::InterfaceFile *)) {
Transform(&FileA);
// Files should not be equal.
if (FileA == FileB)
return false;
Transform(&FileB);
// Files should be equal.
if (FileA != FileB)
return false;
return true;
}
} // namespace llvm
#endif

View File

@ -836,4 +836,114 @@ TEST(TBDv3, MalformedFile2) {
ErrorMessage);
}
TEST(TBDv3, InterfaceEquality) {
static const char TBDv3File[] =
"--- !tapi-tbd-v3\n"
"archs: [ armv7, arm64 ]\n"
"uuids: [ 'armv7: 00000000-0000-0000-0000-000000000000',\n"
" 'arm64: 11111111-1111-1111-1111-111111111111']\n"
"platform: ios\n"
"flags: [ installapi ]\n"
"install-name: Test.dylib\n"
"current-version: 2.3.4\n"
"compatibility-version: 1.0\n"
"swift-abi-version: 1.1\n"
"parent-umbrella: Umbrella.dylib\n"
"exports:\n"
" - archs: [ armv7, arm64 ]\n"
" allowable-clients: [ clientA ]\n"
" re-exports: [ /usr/lib/libfoo.dylib ]\n"
" symbols: [ _sym1, _sym2, _sym3, _sym4, $ld$hide$os9.0$_sym1 ]\n"
" objc-classes: [ class1, class2 ]\n"
" objc-eh-types: [ class1 ]\n"
" objc-ivars: [ class1._ivar1, class1._ivar2 ]\n"
" weak-def-symbols: [ _weak1, _weak2 ]\n"
" thread-local-symbols: [ _tlv1, _tlv3 ]\n"
" - archs: [ armv7 ]\n"
" symbols: [ _sym5 ]\n"
" objc-classes: [ class3 ]\n"
" objc-ivars: [ class1._ivar3 ]\n"
" weak-def-symbols: [ _weak3 ]\n"
" thread-local-symbols: [ _tlv3 ]\n"
"--- !tapi-tbd-v3\n"
"archs: [ i386 ]\n"
"platform: macosx\n"
"install-name: '/usr/lib/libbar.dylib'\n"
"current-version: 0\n"
"compatibility-version: 0\n"
"swift-abi-version: 5\n"
"objc-constraint: none\n"
"exports:\n"
" - archs: [ i386 ]\n"
" symbols: [ _sym3, _sym4 ]\n"
"...\n";
Expected<TBDFile> ResultA =
TextAPIReader::get(MemoryBufferRef(TBDv3File, "TestA.tbd"));
EXPECT_TRUE(!!ResultA);
InterfaceFile FileA = std::move(*ResultA.get());
Expected<TBDFile> ResultB =
TextAPIReader::get(MemoryBufferRef(TBDv3File, "TestB.tbd"));
EXPECT_TRUE(!!ResultB);
InterfaceFile FileB = std::move(*ResultB.get());
EXPECT_FALSE(FileA.getPath() == FileB.getPath());
EXPECT_TRUE(FileA == FileB);
}
TEST(TBDv3, InterfaceInequality) {
static const char TBDv3File[] = "--- !tapi-tbd-v3\n"
"archs: [ armv7, arm64 ]\n"
"platform: ios\n"
"install-name: Test.dylib\n"
"...\n";
Expected<TBDFile> ResultA =
TextAPIReader::get(MemoryBufferRef(TBDv3File, "TestA.tbd"));
EXPECT_TRUE(!!ResultA);
InterfaceFile FileA = std::move(*ResultA.get());
Expected<TBDFile> ResultB =
TextAPIReader::get(MemoryBufferRef(TBDv3File, "TestB.tbd"));
EXPECT_TRUE(!!ResultB);
InterfaceFile FileB = std::move(*ResultB.get());
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addTarget(Target(AK_x86_64, PlatformKind::iOS));
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->setCurrentVersion(PackedVersion(1, 2, 3));
File->setCompatibilityVersion(PackedVersion(1, 0, 0));
}));
EXPECT_TRUE(checkEqualityOnTransform(
FileA, FileB, [](InterfaceFile *File) { File->setSwiftABIVersion(5); }));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->setTwoLevelNamespace(false);
}));
EXPECT_TRUE(checkEqualityOnTransform(
FileA, FileB, [](InterfaceFile *File) { File->setInstallAPI(true); }));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->setApplicationExtensionSafe(false);
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addParentUmbrella(Target(AK_armv7, PlatformKind::iOS), "Umbrella.dylib");
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addAllowableClient("ClientA", Target(AK_armv7, PlatformKind::iOS));
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addReexportedLibrary("/System/Library/Frameworks/A.framework/A",
Target(AK_armv7, PlatformKind::iOS));
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addSymbol(SymbolKind::GlobalSymbol, "_symA", {Target(AK_arm64, PlatformKind::iOS)});
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
InterfaceFile Document;
Document.addTargets(TargetList{Target(AK_armv7, PlatformKind::iOS),
Target(AK_arm64, PlatformKind::iOS)});
Document.setInstallName("/System/Library/Frameworks/A.framework/A");
File->addDocument(std::make_shared<InterfaceFile>(std::move(Document)));
}));
}
} // namespace TBDv3

View File

@ -938,4 +938,238 @@ TEST(TBDv4, MalformedFile3) {
ErrorMessage);
}
TEST(TBDv4, InterfaceEquality) {
static const char TBDv4File[] =
"--- !tapi-tbd\n"
"tbd-version: 4\n"
"targets: [ i386-macos, x86_64-macos, x86_64-ios ]\n"
"uuids:\n"
" - target: i386-macos\n"
" value: 00000000-0000-0000-0000-000000000000\n"
" - target: x86_64-macos\n"
" value: 11111111-1111-1111-1111-111111111111\n"
" - target: x86_64-ios\n"
" value: 11111111-1111-1111-1111-111111111111\n"
"flags: [ flat_namespace, installapi ]\n"
"install-name: Umbrella.framework/Umbrella\n"
"current-version: 1.2.3\n"
"compatibility-version: 1.2\n"
"swift-abi-version: 5\n"
"parent-umbrella:\n"
" - targets: [ i386-macos, x86_64-macos, x86_64-ios ]\n"
" umbrella: System\n"
"allowable-clients:\n"
" - targets: [ i386-macos, x86_64-macos, x86_64-ios ]\n"
" clients: [ ClientA ]\n"
"reexported-libraries:\n"
" - targets: [ i386-macos ]\n"
" libraries: [ /System/Library/Frameworks/A.framework/A ]\n"
"exports:\n"
" - targets: [ i386-macos ]\n"
" symbols: [ _symA ]\n"
" objc-classes: []\n"
" objc-eh-types: []\n"
" objc-ivars: []\n"
" weak-symbols: []\n"
" thread-local-symbols: []\n"
" - targets: [ x86_64-ios ]\n"
" symbols: [_symB]\n"
" - targets: [ x86_64-macos, x86_64-ios ]\n"
" symbols: [_symAB]\n"
"reexports:\n"
" - targets: [ i386-macos ]\n"
" symbols: [_symC]\n"
" objc-classes: []\n"
" objc-eh-types: []\n"
" objc-ivars: []\n"
" weak-symbols: []\n"
" thread-local-symbols: []\n"
"undefineds:\n"
" - targets: [ i386-macos ]\n"
" symbols: [ _symD ]\n"
" objc-classes: []\n"
" objc-eh-types: []\n"
" objc-ivars: []\n"
" weak-symbols: []\n"
" thread-local-symbols: []\n"
"tbd-version: 4\n"
"targets: [ i386-maccatalyst, x86_64-maccatalyst ]\n"
"uuids:\n"
" - target: i386-maccatalyst\n"
" value: 00000000-0000-0000-0000-000000000000\n"
" - target: x86_64-maccatalyst\n"
" value: 11111111-1111-1111-1111-111111111111\n"
"install-name: '/System/Library/Frameworks/A.framework/A'\n"
"exports:\n"
" - targets: [ i386-maccatalyst ]\n"
" weak-symbols: [ _symC ]\n"
" - targets: [ i386-maccatalyst, x86_64-maccatalyst ]\n"
" symbols: [ _symA ]\n"
" objc-classes: [ Class1 ]\n"
" - targets: [ x86_64-maccatalyst ]\n"
" symbols: [ _symAB ]\n"
"...\n";
Expected<TBDFile> ResultA =
TextAPIReader::get(MemoryBufferRef(TBDv4File, "TestA.tbd"));
EXPECT_TRUE(!!ResultA);
InterfaceFile FileA = std::move(*ResultA.get());
Expected<TBDFile> ResultB =
TextAPIReader::get(MemoryBufferRef(TBDv4File, "TestB.tbd"));
EXPECT_TRUE(!!ResultB);
InterfaceFile FileB = std::move(*ResultB.get());
EXPECT_TRUE(FileA == FileB);
}
TEST(TBDv4, InterfaceDiffVersionsEquality) {
static const char TBDv4File[] =
"--- !tapi-tbd\n"
"tbd-version: 4\n"
"targets: [ i386-macos, x86_64-macos ]\n"
"uuids:\n"
" - target: i386-macos\n"
" value: 00000000-0000-0000-0000-000000000000\n"
" - target: x86_64-macos\n"
" value: 11111111-1111-1111-1111-111111111111\n"
"flags: [ installapi ]\n"
"install-name: Umbrella.framework/Umbrella\n"
"current-version: 1.2.3\n"
"compatibility-version: 1.0\n"
"swift-abi-version: 5\n"
"parent-umbrella:\n"
" - targets: [ i386-macos, x86_64-macos ]\n"
" umbrella: System\n"
"allowable-clients:\n"
" - targets: [ i386-macos, x86_64-macos ]\n"
" clients: [ ClientA ]\n"
"reexported-libraries:\n"
" - targets: [ i386-macos ]\n"
" libraries: [ /System/Library/Frameworks/A.framework/A ]\n"
"exports:\n"
" - targets: [ i386-macos ]\n"
" symbols: [ _sym5 ]\n"
" objc-classes: [ class3]\n"
" objc-eh-types: []\n"
" objc-ivars: [ class1._ivar3 ]\n"
" weak-symbols: [ _weak3 ]\n"
" - targets: [ x86_64-macos ]\n"
" symbols: [_symAB]\n"
" - targets: [ i386-macos, x86_64-macos ]\n"
" symbols: [_symA]\n"
" objc-classes: [ class1, class2 ]\n"
" objc-eh-types: [ class1 ]\n"
" objc-ivars: [ class1._ivar1, class1._ivar2 ]\n"
" weak-symbols: [ _weak1, _weak2 ]\n"
" thread-local-symbols: [ _tlv1, _tlv3 ]\n"
"undefineds:\n"
" - targets: [ i386-macos ]\n"
" symbols: [ _symC ]\n"
" objc-classes: []\n"
" objc-eh-types: []\n"
" objc-ivars: []\n"
" weak-symbols: []\n"
" thread-local-symbols: []\n"
"...\n";
static const char TBDv3File[] =
"--- !tapi-tbd-v3\n"
"archs: [ i386, x86_64 ]\n"
"uuids: [ 'i386: 00000000-0000-0000-0000-000000000000',\n"
" 'x86_64: 22222222-2222-2222-2222-222222222222']\n"
"platform: macosx\n"
"flags: [ installapi ]\n"
"install-name: Umbrella.framework/Umbrella\n"
"current-version: 1.2.3\n"
"compatibility-version: 1.0\n"
"swift-abi-version: 5\n"
"parent-umbrella: System\n"
"exports:\n"
" - archs: [ i386, x86_64 ]\n"
" allowable-clients: [ ClientA ]\n"
" symbols: [ _symA ]\n"
" objc-classes: [ class1, class2 ]\n"
" objc-eh-types: [ class1 ]\n"
" objc-ivars: [ class1._ivar1, class1._ivar2 ]\n"
" weak-def-symbols: [ _weak1, _weak2 ]\n"
" thread-local-symbols: [ _tlv1, _tlv3 ]\n"
" - archs: [ i386 ]\n"
" re-exports: [ /System/Library/Frameworks/A.framework/A ]\n"
" symbols: [ _sym5 ]\n"
" objc-classes: [ class3 ]\n"
" objc-ivars: [ class1._ivar3 ]\n"
" weak-def-symbols: [ _weak3 ]\n"
" - archs: [ x86_64 ]\n"
" symbols: [ _symAB ]\n"
"undefineds:\n"
" - archs: [ i386 ]\n"
" symbols: [ _symC ]\n"
"...\n";
Expected<TBDFile> ResultA =
TextAPIReader::get(MemoryBufferRef(TBDv4File, "TestA.tbd"));
EXPECT_TRUE(!!ResultA);
InterfaceFile FileA = std::move(*ResultA.get());
Expected<TBDFile> ResultB =
TextAPIReader::get(MemoryBufferRef(TBDv3File, "TestB.tbd"));
EXPECT_TRUE(!!ResultB);
InterfaceFile FileB = std::move(*ResultB.get());
EXPECT_NE(FileA.uuids(), FileB.uuids());
EXPECT_TRUE(FileA == FileB);
}
TEST(TBDv4, InterfaceInequality) {
static const char TBDv4File[] = "--- !tapi-tbd\n"
"tbd-version: 4\n"
"targets: [ i386-macos, x86_64-macos ]\n"
"install-name: Umbrella.framework/Umbrella\n"
"...\n";
Expected<TBDFile> ResultA =
TextAPIReader::get(MemoryBufferRef(TBDv4File, "TestA.tbd"));
EXPECT_TRUE(!!ResultA);
InterfaceFile FileA = std::move(*ResultA.get());
Expected<TBDFile> ResultB =
TextAPIReader::get(MemoryBufferRef(TBDv4File, "TestB.tbd"));
EXPECT_TRUE(!!ResultB);
InterfaceFile FileB = std::move(*ResultB.get());
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addTarget(Target(AK_x86_64, PlatformKind::iOS));
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->setCurrentVersion(PackedVersion(1, 2, 3));
File->setCompatibilityVersion(PackedVersion(1, 0, 0));
}));
EXPECT_TRUE(checkEqualityOnTransform(
FileA, FileB, [](InterfaceFile *File) { File->setSwiftABIVersion(5); }));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->setTwoLevelNamespace(false);
}));
EXPECT_TRUE(checkEqualityOnTransform(
FileA, FileB, [](InterfaceFile *File) { File->setInstallAPI(true); }));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->setApplicationExtensionSafe(false);
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addParentUmbrella(Target(AK_x86_64, PlatformKind::macOS), "System.dylib");
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addAllowableClient("ClientA", Target(AK_i386, PlatformKind::macOS));
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addReexportedLibrary("/System/Library/Frameworks/A.framework/A",
Target(AK_i386, PlatformKind::macOS));
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
File->addSymbol(SymbolKind::GlobalSymbol, "_symA", {Target(AK_x86_64, PlatformKind::macOS)});
}));
EXPECT_TRUE(checkEqualityOnTransform(FileA, FileB, [](InterfaceFile *File) {
InterfaceFile Document;
Document.addTargets(TargetList {Target(AK_i386, PlatformKind::macOS),
Target(AK_x86_64, PlatformKind::macOS)});
Document.setInstallName("/System/Library/Frameworks/A.framework/A");
File->addDocument(std::make_shared<InterfaceFile>(std::move(Document)));
}));
}
} // end namespace TBDv4