Fix QMetaObject naming of class enum flag

Adds an enumName to QMetaEnum to carry the name of the enum since for
flags that doesn't match the name of the Qt type, but is needed if the
flag is scoped.

Change-Id: I1c0f77eb9e40e6fd1eb6a59bea77caf0f33fcf43
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Allan Sandfeld Jensen 2018-07-26 13:55:19 +02:00
parent 8f58e1319c
commit 1c623bc6d1
15 changed files with 200 additions and 61 deletions

View File

@ -946,7 +946,7 @@ QDebug qt_QMetaEnum_debugOperator(QDebug &dbg, int value, const QMetaObject *met
if (const char *scope = me.scope())
dbg << scope << "::";
if (me.isScoped())
dbg << name << "::";
dbg << me.enumName() << "::";
dbg << key;
} else {
dbg << meta->className() << "::" << name << "(" << value << ")";
@ -964,7 +964,7 @@ QDebug qt_QMetaEnum_flagDebugOperator(QDebug &debug, quint64 value, const QMetaO
const QMetaEnum me = meta->enumerator(meta->indexOfEnumerator(name));
if (const char *scope = me.scope())
debug << scope << "::";
debug << me.name() << ">(" << me.valueToKeys(value) << ')';
debug << me.enumName() << ">(" << me.valueToKeys(value) << ')';
return debug;
}
#endif // !QT_NO_QOBJECT

View File

@ -968,10 +968,24 @@ static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, co
int QMetaObject::indexOfEnumerator(const char *name) const
{
const QMetaObject *m = this;
const int intsPerEnum = priv(m->d.data)->revision >= 8 ? 5 : 4;
while (m) {
const QMetaObjectPrivate *d = priv(m->d.data);
for (int i = d->enumeratorCount - 1; i >= 0; --i) {
const char *prop = rawStringData(m, m->d.data[d->enumeratorData + 4*i]);
const char *prop = rawStringData(m, m->d.data[d->enumeratorData + intsPerEnum * i]);
if (name[0] == prop[0] && strcmp(name + 1, prop + 1) == 0) {
i += m->enumeratorOffset();
return i;
}
}
m = m->d.superdata;
}
// Check alias names:
m = this;
while (m) {
const QMetaObjectPrivate *d = priv(m->d.data);
for (int i = d->enumeratorCount - 1; i >= 0; --i) {
const char *prop = rawStringData(m, m->d.data[d->enumeratorData + intsPerEnum * i + 1]);
if (name[0] == prop[0] && strcmp(name + 1, prop + 1) == 0) {
i += m->enumeratorOffset();
return i;
@ -1086,10 +1100,11 @@ QMetaEnum QMetaObject::enumerator(int index) const
if (i < 0 && d.superdata)
return d.superdata->enumerator(index);
const int intsPerEnum = priv(d.data)->revision >= 8 ? 5 : 4;
QMetaEnum result;
if (i >= 0 && i < priv(d.data)->enumeratorCount) {
result.mobj = this;
result.handle = priv(d.data)->enumeratorData + 4*i;
result.handle = priv(d.data)->enumeratorData + intsPerEnum * i;
}
return result;
}
@ -2552,12 +2567,15 @@ bool QMetaMethod::invokeOnGadget(void* gadget, QGenericReturnArgument returnValu
*/
/*!
Returns the name of the enumerator (without the scope).
Returns the name of the type (without the scope).
For example, the Qt::AlignmentFlag enumeration has \c
AlignmentFlag as the name and \l Qt as the scope.
For example, the Qt::Key enumeration has \c
Key as the type name and \l Qt as the scope.
\sa isValid(), scope()
For flags this returns the name of the flag type, not the
name of the enum type.
\sa isValid(), scope(), enumName()
*/
const char *QMetaEnum::name() const
{
@ -2566,6 +2584,28 @@ const char *QMetaEnum::name() const
return rawStringData(mobj, mobj->d.data[handle]);
}
/*!
Returns the enum name of the flag (without the scope).
For example, the Qt::AlignmentFlag flag has \c
AlignmentFlag as the enum name, but \c Alignment as as the type name.
Non flag enums has the same type and enum names.
Enum names have the same scope as the type name.
\since 5.12
\sa isValid(), name()
*/
const char *QMetaEnum::enumName() const
{
if (!mobj)
return 0;
const bool rev8p = priv(mobj->d.data)->revision >= 8;
if (rev8p)
return rawStringData(mobj, mobj->d.data[handle + 1]);
return name();
}
/*!
Returns the number of keys.
@ -2575,10 +2615,10 @@ int QMetaEnum::keyCount() const
{
if (!mobj)
return 0;
return mobj->d.data[handle + 2];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
return mobj->d.data[handle + offset];
}
/*!
Returns the key with the given \a index, or 0 if no such key exists.
@ -2588,8 +2628,9 @@ const char *QMetaEnum::key(int index) const
{
if (!mobj)
return 0;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
if (index >= 0 && index < count)
return rawStringData(mobj, mobj->d.data[data + 2*index]);
return 0;
@ -2605,8 +2646,9 @@ int QMetaEnum::value(int index) const
{
if (!mobj)
return 0;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
if (index >= 0 && index < count)
return mobj->d.data[data + 2*index + 1];
return -1;
@ -2624,7 +2666,8 @@ int QMetaEnum::value(int index) const
*/
bool QMetaEnum::isFlag() const
{
return mobj && mobj->d.data[handle + 1] & EnumIsFlag;
const int offset = priv(mobj->d.data)->revision >= 8 ? 2 : 1;
return mobj && mobj->d.data[handle + offset] & EnumIsFlag;
}
/*!
@ -2635,7 +2678,8 @@ bool QMetaEnum::isFlag() const
*/
bool QMetaEnum::isScoped() const
{
return mobj && mobj->d.data[handle + 1] & EnumIsScoped;
const int offset = priv(mobj->d.data)->revision >= 8 ? 2 : 1;
return mobj && mobj->d.data[handle + offset] & EnumIsScoped;
}
/*!
@ -2677,8 +2721,9 @@ int QMetaEnum::keyToValue(const char *key, bool *ok) const
scope = s - key - 1;
key += scope + 2;
}
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
for (int i = 0; i < count; ++i) {
const QByteArray className = stringData(mobj, priv(mobj->d.data)->className);
if ((!scope || (className.size() == int(scope) && strncmp(qualified_key, className.constData(), scope) == 0))
@ -2703,8 +2748,9 @@ const char* QMetaEnum::valueToKey(int value) const
{
if (!mobj)
return 0;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
for (int i = 0; i < count; ++i)
if (value == (int)mobj->d.data[data + 2*i + 1])
return rawStringData(mobj, mobj->d.data[data + 2*i]);
@ -2735,8 +2781,9 @@ int QMetaEnum::keysToValue(const char *keys, bool *ok) const
return 0;
// ### TODO write proper code: do not allocate memory, so we can go nothrow
int value = 0;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
for (const QStringRef &untrimmed : splitKeys) {
const QStringRef trimmed = untrimmed.trimmed();
QByteArray qualified_key = trimmed.toLatin1();
@ -2778,8 +2825,9 @@ QByteArray QMetaEnum::valueToKeys(int value) const
QByteArray keys;
if (!mobj)
return keys;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
int v = value;
// reverse iterate to ensure values like Qt::Dialog=0x2|Qt::Window are processed first.
for (int i = count - 1; i >= 0; --i) {

View File

@ -209,6 +209,7 @@ public:
Q_DECL_CONSTEXPR inline QMetaEnum() : mobj(nullptr), handle(0) {}
const char *name() const;
const char *enumName() const;
bool isFlag() const;
bool isScoped() const;

View File

@ -171,7 +171,8 @@ class QMutex;
struct QMetaObjectPrivate
{
// revision 7 is Qt 5.0 everything lower is not supported
enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus
// revision 8 is Qt 5.12: It adds the enum name to QMetaEnum
enum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbus
int revision;
int className;

View File

@ -190,11 +190,12 @@ class QMetaEnumBuilderPrivate
{
public:
QMetaEnumBuilderPrivate(const QByteArray& _name)
: name(_name), isFlag(false), isScoped(false)
: name(_name), enumName(_name), isFlag(false), isScoped(false)
{
}
QByteArray name;
QByteArray enumName;
bool isFlag;
bool isScoped;
QList<QByteArray> keys;
@ -637,6 +638,7 @@ QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QByteArray& name)
QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype)
{
QMetaEnumBuilder en = addEnumerator(prototype.name());
en.setEnumName(prototype.enumName());
en.setIsFlag(prototype.isFlag());
en.setIsScoped(prototype.isScoped());
int count = prototype.keyCount();
@ -1216,7 +1218,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
- int(d->methods.size()) // return "parameters" don't have names
- int(d->constructors.size()); // "this" parameters don't have names
if (buf) {
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 7, "QMetaObjectBuilder should generate the same version as moc");
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 8, "QMetaObjectBuilder should generate the same version as moc");
pmeta->revision = QMetaObjectPrivate::OutputRevision;
pmeta->flags = d->flags;
pmeta->className = 0; // Class name is always the first string.
@ -1244,7 +1246,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
pmeta->enumeratorCount = int(d->enumerators.size());
pmeta->enumeratorData = dataIndex;
dataIndex += 4 * int(d->enumerators.size());
dataIndex += 5 * int(d->enumerators.size());
pmeta->constructorCount = int(d->constructors.size());
pmeta->constructorData = dataIndex;
@ -1261,7 +1263,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
dataIndex += int(d->properties.size());
if (hasRevisionedProperties)
dataIndex += int(d->properties.size());
dataIndex += 4 * int(d->enumerators.size());
dataIndex += 5 * int(d->enumerators.size());
dataIndex += 5 * int(d->constructors.size());
}
@ -1410,15 +1412,17 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
Q_ASSERT(!buf || dataIndex == pmeta->enumeratorData);
for (const auto &enumerator : d->enumerators) {
int name = strings.enter(enumerator.name);
int enumName = strings.enter(enumerator.enumName);
int isFlag = enumerator.isFlag ? EnumIsFlag : 0;
int isScoped = enumerator.isScoped ? EnumIsScoped : 0;
int count = enumerator.keys.size();
int enumOffset = enumIndex;
if (buf) {
data[dataIndex] = name;
data[dataIndex + 1] = isFlag | isScoped;
data[dataIndex + 2] = count;
data[dataIndex + 3] = enumOffset;
data[dataIndex + 1] = enumName;
data[dataIndex + 2] = isFlag | isScoped;
data[dataIndex + 3] = count;
data[dataIndex + 4] = enumOffset;
}
for (int key = 0; key < count; ++key) {
int keyIndex = strings.enter(enumerator.keys[key]);
@ -1427,7 +1431,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
data[enumOffset++] = enumerator.values[key];
}
}
dataIndex += 4;
dataIndex += 5;
enumIndex += 2 * count;
}
@ -2599,7 +2603,7 @@ QMetaEnumBuilderPrivate *QMetaEnumBuilder::d_func() const
*/
/*!
Returns the name of the enumerator (without the scope).
Returns the type name of the enumerator (without the scope).
*/
QByteArray QMetaEnumBuilder::name() const
{
@ -2610,6 +2614,33 @@ QByteArray QMetaEnumBuilder::name() const
return QByteArray();
}
/*!
Returns the enum name of the enumerator (without the scope).
\since 5.12
*/
QByteArray QMetaEnumBuilder::enumName() const
{
QMetaEnumBuilderPrivate *d = d_func();
if (d)
return d->enumName;
else
return QByteArray();
}
/*!
Sets this enumerator to have the enum name \c alias.
\since 5.12
\sa isFlag(), enumName()
*/
void QMetaEnumBuilder::setEnumName(const QByteArray &alias)
{
QMetaEnumBuilderPrivate *d = d_func();
if (d)
d->enumName = alias;
}
/*!
Returns \c true if this enumerator is used as a flag; otherwise returns
false.

View File

@ -297,6 +297,9 @@ public:
QByteArray name() const;
QByteArray enumName() const;
void setEnumName(const QByteArray &alias);
bool isFlag() const;
void setIsFlag(bool value);

View File

@ -412,7 +412,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
- methods.count(); // ditto
QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data());
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 7, "QtDBus meta-object generator should generate the same version as moc");
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 8, "QtDBus meta-object generator should generate the same version as moc");
header->revision = QMetaObjectPrivate::OutputRevision;
header->className = 0;
header->classInfoCount = 0;

View File

@ -200,9 +200,9 @@ void Generator::generateCode()
if (cdef->enumDeclarations.contains(def.name)) {
enumList += def;
}
def.enumName = def.name;
QByteArray alias = cdef->flagAliases.value(def.name);
if (cdef->enumDeclarations.contains(alias)) {
def.className = def.name;
def.name = alias;
enumList += def;
}
@ -370,7 +370,7 @@ void Generator::generateCode()
int enumsIndex = index;
for (int i = 0; i < cdef->enumList.count(); ++i)
index += 4 + (cdef->enumList.at(i).values.count() * 2);
index += 5 + (cdef->enumList.at(i).values.count() * 2);
fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? cdef->constructorList.count() : 0,
isConstructible ? index : 0);
@ -888,6 +888,8 @@ void Generator::registerEnumStrings()
for (int i = 0; i < cdef->enumList.count(); ++i) {
const EnumDef &e = cdef->enumList.at(i);
strreg(e.name);
if (!e.enumName.isNull())
strreg(e.enumName);
for (int j = 0; j < e.values.count(); ++j)
strreg(e.values.at(j));
}
@ -898,8 +900,8 @@ void Generator::generateEnums(int index)
if (cdef->enumDeclarations.isEmpty())
return;
fprintf(out, "\n // enums: name, flags, count, data\n");
index += 4 * cdef->enumList.count();
fprintf(out, "\n // enums: name, alias, flags, count, data\n");
index += 5 * cdef->enumList.count();
int i;
for (i = 0; i < cdef->enumList.count(); ++i) {
const EnumDef &e = cdef->enumList.at(i);
@ -908,8 +910,9 @@ void Generator::generateEnums(int index)
flags |= EnumIsFlag;
if (e.isEnumClass)
flags |= EnumIsScoped;
fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n",
fprintf(out, " %4d, %4d, 0x%.1x, %4d, %4d,\n",
stridx(e.name),
e.enumName.isNull() ? stridx(e.name) : stridx(e.enumName),
flags,
e.values.count(),
index);
@ -923,7 +926,7 @@ void Generator::generateEnums(int index)
const QByteArray &val = e.values.at(j);
QByteArray code = cdef->qualified.constData();
if (e.isEnumClass)
code += "::" + (e.className.isNull() ? e.name : e.className);
code += "::" + (e.enumName.isNull() ? e.name : e.enumName);
code += "::" + val;
fprintf(out, " %4d, uint(%s),\n",
stridx(val), code.constData());

View File

@ -64,7 +64,7 @@ Q_DECLARE_TYPEINFO(Type, Q_MOVABLE_TYPE);
struct EnumDef
{
QByteArray name;
QByteArray className;
QByteArray enumName;
QList<QByteArray> values;
bool isEnumClass; // c++11 enum class
EnumDef() : isEnumClass(false) {}

View File

@ -38,6 +38,13 @@
class tst_QDebug: public QObject
{
Q_OBJECT
public:
enum EnumType { EnumValue1 = 1, EnumValue2 = 2 };
enum FlagType { EnumFlag1 = 1, EnumFlag2 = 2 };
Q_ENUM(EnumType)
Q_DECLARE_FLAGS(Flags, FlagType)
Q_FLAG(Flags)
private slots:
void assignment() const;
void warningWithoutDebug() const;
@ -637,6 +644,15 @@ void tst_QDebug::qDebugQFlags() const
QCOMPARE(s_line, line);
QCOMPARE(QString::fromLatin1(s_function), function);
// Test the output of QFlags with an enum not declared with Q_DECLARE_FLAGS and Q_FLAGS
QFlags<EnumType> flags2(EnumValue2);
qDebug() << flags2;
QCOMPARE(s_msg, QString::fromLatin1("QFlags<tst_QDebug::EnumType>(EnumValue2)"));
// A now for one that was fully declared
tst_QDebug::Flags flags3(EnumFlag1);
qDebug() << flags3;
QCOMPARE(s_msg, QString::fromLatin1("QFlags<tst_QDebug::FlagType>(EnumFlag1)"));
}
void tst_QDebug::textStreamModifiers() const

View File

@ -37,7 +37,10 @@ class tst_QMetaEnum : public QObject
Q_OBJECT
public:
enum SuperEnum { SuperValue1 = 1 , SuperValue2 = 2 };
enum Flag { Flag1 = 1 , Flag2 = 2 };
Q_DECLARE_FLAGS(Flags, Flag)
Q_ENUM(SuperEnum)
Q_FLAG(Flags)
private slots:
void fromType();
@ -49,7 +52,17 @@ void tst_QMetaEnum::fromType()
{
QMetaEnum meta = QMetaEnum::fromType<SuperEnum>();
QVERIFY(meta.isValid());
QVERIFY(!meta.isFlag());
QCOMPARE(meta.name(), "SuperEnum");
QCOMPARE(meta.enumName(), "SuperEnum");
QCOMPARE(meta.enclosingMetaObject(), &staticMetaObject);
QCOMPARE(meta.keyCount(), 2);
meta = QMetaEnum::fromType<Flags>();
QVERIFY(meta.isValid());
QVERIFY(meta.isFlag());
QCOMPARE(meta.name(), "Flags");
QCOMPARE(meta.enumName(), "Flag");
QCOMPARE(meta.enclosingMetaObject(), &staticMetaObject);
QCOMPARE(meta.keyCount(), 2);
}

View File

@ -69,7 +69,13 @@ namespace MyNamespace {
MyFlag2 = 0x02,
MyFlag3 = 0x04
};
enum class MyScopedFlag {
MyFlag1 = 0x10,
MyFlag2 = 0x20,
MyFlag3 = 0x40
};
Q_DECLARE_FLAGS(MyFlags, MyFlag)
Q_DECLARE_FLAGS(MyScopedFlags, MyScopedFlag)
MyEnum myEnum() const { return m_enum; }
void setMyEnum(MyEnum val) { m_enum = val; }
@ -87,6 +93,7 @@ namespace MyNamespace {
Q_ENUM(MyScopedEnum)
Q_ENUM(MyAnotherEnum)
Q_FLAG(MyFlags)
Q_FLAG(MyScopedFlags)
MyEnum m_enum;
MyFlags m_flags;
@ -1745,13 +1752,21 @@ void tst_QMetaObject::enumDebugStream()
QTest::ignoreMessage(QtDebugMsg, "Qt::WindowTitleHint Qt::Window Qt::Desktop Qt::WindowSystemMenuHint");
qDebug() << Qt::WindowTitleHint << Qt::Window << Qt::Desktop << Qt::WindowSystemMenuHint;
QTest::ignoreMessage(QtDebugMsg, "hello QFlags<MyNamespace::MyClass::MyFlags>(MyFlag1) world");
QTest::ignoreMessage(QtDebugMsg, "hello QFlags<MyNamespace::MyClass::MyFlag>(MyFlag1) world");
MyNamespace::MyClass::MyFlags f1 = MyNamespace::MyClass::MyFlag1;
qDebug() << "hello" << f1 << "world";
MyNamespace::MyClass::MyFlags f2 = MyNamespace::MyClass::MyFlag2 | MyNamespace::MyClass::MyFlag3;
QTest::ignoreMessage(QtDebugMsg, "QFlags<MyNamespace::MyClass::MyFlags>(MyFlag1) QFlags<MyNamespace::MyClass::MyFlags>(MyFlag2|MyFlag3)");
QTest::ignoreMessage(QtDebugMsg, "QFlags<MyNamespace::MyClass::MyFlag>(MyFlag1) QFlags<MyNamespace::MyClass::MyFlag>(MyFlag2|MyFlag3)");
qDebug() << f1 << f2;
QTest::ignoreMessage(QtDebugMsg, "QFlags<MyNamespace::MyClass::MyScopedFlag>(MyFlag2)");
MyNamespace::MyClass::MyScopedFlags f3 = MyNamespace::MyClass::MyScopedFlag::MyFlag2;
qDebug() << f3;
QTest::ignoreMessage(QtDebugMsg, "QFlags<MyNamespace::MyClass::MyScopedFlag>(MyFlag2|MyFlag3)");
f3 |= MyNamespace::MyClass::MyScopedFlag::MyFlag3;
qDebug() << f3;
}
void tst_QMetaObject::inherits_data()

View File

@ -830,6 +830,7 @@ void tst_QMetaObjectBuilder::enumerator()
// Modify the attributes on enum1.
enum1.setIsFlag(true);
enum1.setIsScoped(true);
enum1.setEnumName(QByteArrayLiteral("fooFlag"));
QCOMPARE(enum1.addKey("ABC", 0), 0);
QCOMPARE(enum1.addKey("DEF", 1), 1);
QCOMPARE(enum1.addKey("GHI", -1), 2);
@ -838,6 +839,7 @@ void tst_QMetaObjectBuilder::enumerator()
QCOMPARE(enum1.name(), QByteArray("foo"));
QVERIFY(enum1.isFlag());
QVERIFY(enum1.isScoped());
QCOMPARE(enum1.enumName(), QByteArray("fooFlag"));
QCOMPARE(enum1.keyCount(), 3);
QCOMPARE(enum1.index(), 0);
QCOMPARE(enum1.key(0), QByteArray("ABC"));

View File

@ -39,7 +39,7 @@ public:
enum TypedEnum : char { B0, B1 , B2, B3 };
enum class TypedEnumClass : char { C0, C1, C2, C3 };
enum NormalEnum { D2 = 2, D3, D0 =0 , D1 };
enum class ClassFlag { F0, F1, F2, F3 };
enum class ClassFlag { F0 = 1, F1 = 2, F2 = 4, F3 = 8};
Q_DECLARE_FLAGS(ClassFlags, ClassFlag)
Q_ENUM(EnumClass)
@ -58,7 +58,7 @@ public:
enum TypedEnum : char { B0, B1 , B2, B3 };
enum class TypedEnumClass : char { C0, C1, C2, C3 };
enum NormalEnum { D2 = 2, D3, D0 =0 , D1 };
enum class ClassFlag { F0, F1, F2, F3 };
enum class ClassFlag { F0 = 1, F1 = 2, F2 = 4, F3 = 8 };
Q_DECLARE_FLAGS(ClassFlags, ClassFlag)
Q_ENUMS(EnumClass TypedEnum TypedEnumClass NormalEnum)
Q_FLAGS(ClassFlags)

View File

@ -2248,6 +2248,7 @@ void tst_Moc::privateClass()
void tst_Moc::cxx11Enums_data()
{
QTest::addColumn<const QMetaObject *>("meta");
QTest::addColumn<QByteArray>("typeName");
QTest::addColumn<QByteArray>("enumName");
QTest::addColumn<char>("prefix");
QTest::addColumn<bool>("isScoped");
@ -2255,16 +2256,16 @@ void tst_Moc::cxx11Enums_data()
const QMetaObject *meta1 = &CXX11Enums::staticMetaObject;
const QMetaObject *meta2 = &CXX11Enums2::staticMetaObject;
QTest::newRow("EnumClass") << meta1 << QByteArray("EnumClass") << 'A' << true;
QTest::newRow("EnumClass 2") << meta2 << QByteArray("EnumClass") << 'A' << true;
QTest::newRow("TypedEnum") << meta1 << QByteArray("TypedEnum") << 'B' << false;
QTest::newRow("TypedEnum 2") << meta2 << QByteArray("TypedEnum") << 'B' << false;
QTest::newRow("TypedEnumClass") << meta1 << QByteArray("TypedEnumClass") << 'C' << true;
QTest::newRow("TypedEnumClass 2") << meta2 << QByteArray("TypedEnumClass") << 'C' << true;
QTest::newRow("NormalEnum") << meta1 << QByteArray("NormalEnum") << 'D' << false;
QTest::newRow("NormalEnum 2") << meta2 << QByteArray("NormalEnum") << 'D' << false;
QTest::newRow("ClassFlags") << meta1 << QByteArray("ClassFlags") << 'F' << true;
QTest::newRow("ClassFlags 2") << meta2 << QByteArray("ClassFlags") << 'F' << true;
QTest::newRow("EnumClass") << meta1 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true;
QTest::newRow("EnumClass 2") << meta2 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true;
QTest::newRow("TypedEnum") << meta1 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false;
QTest::newRow("TypedEnum 2") << meta2 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false;
QTest::newRow("TypedEnumClass") << meta1 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true;
QTest::newRow("TypedEnumClass 2") << meta2 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true;
QTest::newRow("NormalEnum") << meta1 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false;
QTest::newRow("NormalEnum 2") << meta2 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false;
QTest::newRow("ClassFlags") << meta1 << QByteArray("ClassFlags") << QByteArray("ClassFlag") << 'F' << true;
QTest::newRow("ClassFlags 2") << meta2 << QByteArray("ClassFlags") << QByteArray("ClassFlag") << 'F' << true;
}
void tst_Moc::cxx11Enums()
@ -2272,21 +2273,26 @@ void tst_Moc::cxx11Enums()
QFETCH(const QMetaObject *,meta);
QCOMPARE(meta->enumeratorOffset(), 0);
QFETCH(QByteArray, typeName);
QFETCH(QByteArray, enumName);
QFETCH(char, prefix);
QFETCH(bool, isScoped);
int idx;
idx = meta->indexOfEnumerator(enumName);
int idx = meta->indexOfEnumerator(typeName);
QVERIFY(idx != -1);
QCOMPARE(meta->indexOfEnumerator(enumName), idx);
QCOMPARE(meta->enumerator(idx).enclosingMetaObject(), meta);
QCOMPARE(meta->enumerator(idx).isValid(), true);
QCOMPARE(meta->enumerator(idx).keyCount(), 4);
QCOMPARE(meta->enumerator(idx).name(), enumName.constData());
QCOMPARE(meta->enumerator(idx).name(), typeName.constData());
QCOMPARE(meta->enumerator(idx).enumName(), enumName.constData());
bool isFlag = meta->enumerator(idx).isFlag();
for (int i = 0; i < 4; i++) {
QByteArray v = prefix + QByteArray::number(i);
QCOMPARE(meta->enumerator(idx).keyToValue(v), i);
QCOMPARE(meta->enumerator(idx).valueToKey(i), v.constData());
const int value = isFlag ? (1 << i) : i;
QCOMPARE(meta->enumerator(idx).keyToValue(v), value);
QCOMPARE(meta->enumerator(idx).valueToKey(value), v.constData());
}
QCOMPARE(meta->enumerator(idx).isScoped(), isScoped);
}