Abi: Allow for roundtrips enum->string->enum

Add all static methods to turn the various Abi enums into a string
and back.

Use these methods in the Abi constructor.

Add a unit test that does round-trips between Abi enum, string and back
and fix the code to actually handle this.

Change-Id: Icb56cce07d36152dbee7bbf9dd119a753444ada9
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Tobias Hunger
2018-03-27 14:35:35 +02:00
parent b3a92fc58e
commit 5c4abeaffe
3 changed files with 203 additions and 109 deletions

View File

@@ -387,124 +387,33 @@ Abi::Abi(const QString &abiString) :
{
const QVector<QStringRef> abiParts = abiString.splitRef('-');
if (abiParts.count() >= 1) {
if (abiParts.at(0) == "unknown")
m_architecture = UnknownArchitecture;
else if (abiParts.at(0) == "arm")
m_architecture = ArmArchitecture;
else if (abiParts.at(0) == "aarch64")
m_architecture = ArmArchitecture;
else if (abiParts.at(0) == "avr")
m_architecture = AvrArchitecture;
else if (abiParts.at(0) == "x86")
m_architecture = X86Architecture;
else if (abiParts.at(0) == "mips")
m_architecture = MipsArchitecture;
else if (abiParts.at(0) == "ppc")
m_architecture = PowerPCArchitecture;
else if (abiParts.at(0) == "itanium")
m_architecture = ItaniumArchitecture;
else if (abiParts.at(0) == "sh")
m_architecture = ShArchitecture;
else
m_architecture = architectureFromString(abiParts.at(0));
if (abiParts.at(0) != toString(m_architecture))
return;
}
if (abiParts.count() >= 2) {
if (abiParts.at(1) == "unknown")
m_os = UnknownOS;
else if (abiParts.at(1) == "linux")
m_os = LinuxOS;
else if (abiParts.at(1) == "bsd")
m_os = BsdOS;
else if (abiParts.at(1) == "darwin"
|| abiParts.at(1) == "macos")
m_os = DarwinOS;
else if (abiParts.at(1) == "unix")
m_os = UnixOS;
else if (abiParts.at(1) == "windows")
m_os = WindowsOS;
else if (abiParts.at(1) == "vxworks")
m_os = VxWorks;
else if (abiParts.at(1) == "qnx")
m_os = QnxOS;
else
m_os = osFromString(abiParts.at(1));
if (abiParts.at(1) != toString(m_os))
return;
}
if (abiParts.count() >= 3) {
if (abiParts.at(2) == "unknown")
m_osFlavor = UnknownFlavor;
else if (abiParts.at(2) == "generic" && m_os == LinuxOS)
m_osFlavor = GenericLinuxFlavor;
else if (abiParts.at(2) == "android" && m_os == LinuxOS)
m_osFlavor = AndroidLinuxFlavor;
else if (abiParts.at(2) == "generic" && m_os == QnxOS)
m_osFlavor = GenericQnxFlavor;
else if (abiParts.at(2) == "freebsd" && m_os == BsdOS)
m_osFlavor = FreeBsdFlavor;
else if (abiParts.at(2) == "netbsd" && m_os == BsdOS)
m_osFlavor = NetBsdFlavor;
else if (abiParts.at(2) == "openbsd" && m_os == BsdOS)
m_osFlavor = OpenBsdFlavor;
else if (abiParts.at(2) == "generic" && m_os == DarwinOS)
m_osFlavor = GenericDarwinFlavor;
else if (abiParts.at(2) == "generic" && m_os == UnixOS)
m_osFlavor = GenericUnixFlavor;
else if (abiParts.at(2) == "solaris" && m_os == UnixOS)
m_osFlavor = SolarisUnixFlavor;
else if (abiParts.at(2) == "msvc2005" && m_os == WindowsOS)
m_osFlavor = WindowsMsvc2005Flavor;
else if (abiParts.at(2) == "msvc2008" && m_os == WindowsOS)
m_osFlavor = WindowsMsvc2008Flavor;
else if (abiParts.at(2) == "msvc2010" && m_os == WindowsOS)
m_osFlavor = WindowsMsvc2010Flavor;
else if (abiParts.at(2) == "msvc2012" && m_os == WindowsOS)
m_osFlavor = WindowsMsvc2012Flavor;
else if (abiParts.at(2) == "msvc2013" && m_os == WindowsOS)
m_osFlavor = WindowsMsvc2013Flavor;
else if (abiParts.at(2) == "msvc2015" && m_os == WindowsOS)
m_osFlavor = WindowsMsvc2015Flavor;
else if (abiParts.at(2) == "msvc2017" && m_os == WindowsOS)
m_osFlavor = WindowsMsvc2017Flavor;
else if (abiParts.at(2) == "msys" && m_os == WindowsOS)
m_osFlavor = WindowsMSysFlavor;
else if (abiParts.at(2) == "ce" && m_os == WindowsOS)
m_osFlavor = WindowsCEFlavor;
else if (abiParts.at(2) == "vxworks" && m_os == VxWorks)
m_osFlavor = VxWorksFlavor;
else
m_osFlavor = osFlavorFromString(abiParts.at(2), m_os);
if (abiParts.at(2) != toString(m_osFlavor))
return;
}
if (abiParts.count() >= 4) {
if (abiParts.at(3) == "unknown")
m_binaryFormat = UnknownFormat;
else if (abiParts.at(3) == "elf")
m_binaryFormat = ElfFormat;
else if (abiParts.at(3) == "pe")
m_binaryFormat = PEFormat;
else if (abiParts.at(3) == "mach_o")
m_binaryFormat = MachOFormat;
else if (abiParts.at(3) == "qml_rt")
m_binaryFormat = RuntimeQmlFormat;
else
m_binaryFormat = binaryFormatFromString(abiParts.at(3));
if (abiParts.at(3) != toString(m_binaryFormat))
return;
}
if (abiParts.count() >= 5) {
const QStringRef &bits = abiParts.at(4);
if (!bits.endsWith("bit"))
m_wordWidth = wordWidthFromString(abiParts.at(4));
if (abiParts.at(4) != toString(m_wordWidth))
return;
bool ok = false;
const QStringRef number =
bits.string()->midRef(bits.position(), bits.count() - 3);
const int bitCount = number.toInt(&ok);
if (!ok)
return;
if (bitCount != 8 && bitCount != 16 && bitCount != 32 && bitCount != 64)
return;
m_wordWidth = bitCount;
}
}
@@ -739,6 +648,10 @@ QString Abi::toString(const OSFlavor &of)
{
switch (of) {
case GenericLinuxFlavor:
case GenericDarwinFlavor:
case GenericUnixFlavor:
case GenericBareMetalFlavor:
case GenericQnxFlavor:
return QLatin1String("generic");
case AndroidLinuxFlavor:
return QLatin1String("android");
@@ -748,10 +661,6 @@ QString Abi::toString(const OSFlavor &of)
return QLatin1String("netbsd");
case OpenBsdFlavor:
return QLatin1String("openbsd");
case GenericDarwinFlavor:
return QLatin1String("generic");
case GenericUnixFlavor:
return QLatin1String("generic");
case SolarisUnixFlavor:
return QLatin1String("solaris");
case WindowsMsvc2005Flavor:
@@ -774,11 +683,7 @@ QString Abi::toString(const OSFlavor &of)
return QLatin1String("ce");
case VxWorksFlavor:
return QLatin1String("vxworks");
case GenericQnxFlavor:
case GenericBareMetalFlavor:
return QLatin1String("generic");
case UnknownFlavor:
Q_FALLTHROUGH();
default:
return QLatin1String("unknown");
}
@@ -809,6 +714,141 @@ QString Abi::toString(int w)
return QString::fromLatin1("%1bit").arg(w);
}
Abi::Architecture Abi::architectureFromString(const QStringRef &a)
{
if (a == "unknown")
return UnknownArchitecture;
if (a == "arm")
return ArmArchitecture;
if (a == "aarch64")
return ArmArchitecture;
if (a == "avr")
return AvrArchitecture;
if (a == "x86")
return X86Architecture;
if (a == "mips")
return MipsArchitecture;
if (a == "ppc")
return PowerPCArchitecture;
if (a == "itanium")
return ItaniumArchitecture;
if (a == "sh")
return ShArchitecture;
return UnknownArchitecture;
}
Abi::OS Abi::osFromString(const QStringRef &o)
{
if (o == "unknown")
return UnknownOS;
if (o == "linux")
return LinuxOS;
if (o == "bsd")
return BsdOS;
if (o == "darwin" || o == "macos")
return DarwinOS;
if (o == "unix")
return UnixOS;
if (o == "windows")
return WindowsOS;
if (o == "vxworks")
return VxWorks;
if (o == "qnx")
return QnxOS;
if (o == "baremetal")
return BareMetalOS;
return UnknownOS;
}
Abi::OSFlavor Abi::osFlavorFromString(const QStringRef &of, const OS os)
{
Abi::OSFlavor result = UnknownFlavor;
if (of == "generic") {
switch (os) {
case LinuxOS:
result = GenericLinuxFlavor;
break;
case DarwinOS:
result = GenericDarwinFlavor;
break;
case UnixOS:
result = GenericUnixFlavor;
break;
case BareMetalOS:
result = GenericBareMetalFlavor;
break;
case QnxOS:
result = GenericQnxFlavor;
break;
default:
result = UnknownFlavor;
}
} else if (of == "android") {
result = AndroidLinuxFlavor;
} else if (of == "freebsd") {
result = FreeBsdFlavor;
} else if (of == "netbsd") {
result = NetBsdFlavor;
} else if (of == "openbsd") {
result = OpenBsdFlavor;
} else if (of == "solaris") {
result = SolarisUnixFlavor;
} else if (of == "msvc2005") {
result = WindowsMsvc2005Flavor;
} else if (of == "msvc2008") {
result = WindowsMsvc2008Flavor;
} else if (of == "msvc2010") {
result = WindowsMsvc2010Flavor;
} else if (of == "msvc2012") {
result = WindowsMsvc2012Flavor;
} else if (of == "msvc2013") {
result = WindowsMsvc2013Flavor;
} else if (of == "msvc2015") {
result = WindowsMsvc2015Flavor;
} else if (of == "msvc2017") {
result = WindowsMsvc2017Flavor;
} else if (of == "msys") {
result = WindowsMSysFlavor;
} else if (of == "ce") {
result = WindowsCEFlavor;
} else if (of == "vxworks") {
result = VxWorksFlavor;
}
return flavorsForOs(os).contains(result) ? result : UnknownFlavor;
}
Abi::BinaryFormat Abi::binaryFormatFromString(const QStringRef &bf)
{
if (bf == "unknown")
return UnknownFormat;
if (bf == "elf")
return ElfFormat;
if (bf == "pe")
return PEFormat;
if (bf == "mach_o")
return MachOFormat;
if (bf == "qml_rt")
return RuntimeQmlFormat;
return UnknownFormat;
}
unsigned char Abi::wordWidthFromString(const QStringRef &w)
{
if (!w.endsWith("bit"))
return 0;
bool ok = false;
const QStringRef number = w.string()->midRef(w.position(), w.count() - 3);
const int bitCount = number.toInt(&ok);
if (!ok)
return 0;
if (bitCount != 8 && bitCount != 16 && bitCount != 32 && bitCount != 64)
return 0;
return static_cast<unsigned char>(bitCount);
}
QList<Abi::OSFlavor> Abi::flavorsForOs(const Abi::OS &o)
{
switch (o) {
@@ -973,6 +1013,53 @@ QList<Abi> Abi::abisOfBinary(const Utils::FileName &path)
# include "projectexplorer.h"
static bool isGenericFlavor(ProjectExplorer::Abi::OSFlavor f)
{
return f == ProjectExplorer::Abi::GenericBareMetalFlavor
|| f == ProjectExplorer::Abi::GenericDarwinFlavor
|| f == ProjectExplorer::Abi::GenericLinuxFlavor
|| f == ProjectExplorer::Abi::GenericQnxFlavor
|| f == ProjectExplorer::Abi::GenericUnixFlavor;
}
void ProjectExplorer::ProjectExplorerPlugin::testAbiRoundTrips()
{
for (int i = 0; i <= Abi::UnknownArchitecture; ++i) {
const QString string = Abi::toString(static_cast<Abi::Architecture>(i));
const Abi::Architecture arch = Abi::architectureFromString(QStringRef(&string));
QCOMPARE(static_cast<Abi::Architecture>(i), arch);
}
for (int i = 0; i <= Abi::UnknownOS; ++i) {
const QString string = Abi::toString(static_cast<Abi::OS>(i));
const Abi::OS os = Abi::osFromString(QStringRef(&string));
QCOMPARE(static_cast<Abi::OS>(i), os);
}
for (int i = 0; i <= Abi::UnknownFlavor; ++i) {
const Abi::OSFlavor flavorEnum = static_cast<Abi::OSFlavor>(i);
const QString string = Abi::toString(flavorEnum);
for (int os = 0; os <= Abi::UnknownOS; ++os) {
const Abi::OS osEnum = static_cast<Abi::OS>(os);
const Abi::OSFlavor flavor = Abi::osFlavorFromString(QStringRef(&string), osEnum);
if (isGenericFlavor(flavorEnum) && flavor != Abi::UnknownFlavor)
QVERIFY(isGenericFlavor(flavor));
else if (flavor == Abi::UnknownFlavor && i != Abi::UnknownFlavor)
QVERIFY(!Abi::flavorsForOs(osEnum).contains(flavorEnum));
else
QCOMPARE(flavorEnum, flavor);
}
}
for (int i = 0; i <= Abi::UnknownFormat; ++i) {
QString string = Abi::toString(static_cast<Abi::BinaryFormat>(i));
Abi::BinaryFormat format = Abi::binaryFormatFromString(QStringRef(&string));
QCOMPARE(static_cast<Abi::BinaryFormat>(i), format);
}
for (unsigned char i : {0, 8, 16, 32, 64}) {
QString string = Abi::toString(i);
unsigned char wordwidth = Abi::wordWidthFromString(QStringRef(&string));
QCOMPARE(i, wordwidth);
}
}
void ProjectExplorer::ProjectExplorerPlugin::testAbiOfBinary_data()
{
QTest::addColumn<QString>("file");

View File

@@ -140,6 +140,12 @@ public:
static QString toString(const BinaryFormat &bf);
static QString toString(int w);
static Architecture architectureFromString(const QStringRef &a);
static OS osFromString(const QStringRef &o);
static OSFlavor osFlavorFromString(const QStringRef &of, const OS os);
static BinaryFormat binaryFormatFromString(const QStringRef &bf);
static unsigned char wordWidthFromString(const QStringRef &w);
static QList<OSFlavor> flavorsForOs(const OS &o);
static OSFlavor flavorForMsvcVersion(int version);

View File

@@ -222,6 +222,7 @@ private slots:
void testGccAbiGuessing_data();
void testGccAbiGuessing();
void testAbiRoundTrips();
void testAbiOfBinary_data();
void testAbiOfBinary();
void testFlavorForOs();