diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 09692600c31..63577aab2ea 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -419,10 +419,30 @@ QMetaType QMetaObject::metaType() const return QMetaType::fromName(className()); } else { /* in the metatype array, we store - idx: 0 propertyCount - 1 propertyCount - data:QMetaType(prop0), ..., QMetaType(propPropCount-1), QMetaType(class),... - */ - auto iface = this->d.metaTypes[d->propertyCount]; + + | index | data | + |----------------------------------------------------------------------| + | 0 | QMetaType(property0) | + | ... | ... | + | propertyCount - 1 | QMetaType(propertyCount - 1) | + | propertyCount | QMetaType(enumerator0) | + | ... | ... | + | propertyCount + enumeratorCount - 1 | QMetaType(enumeratorCount - 1) | + | propertyCount + enumeratorCount | QMetaType(class) | + + */ +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + // Before revision 12 we only stored metatypes for enums if they showed + // up as types of properties or method arguments or return values. + // From revision 12 on, we always store them in a predictable place. + const qsizetype offset = d->revision < 12 + ? d->propertyCount + : d->propertyCount + d->enumeratorCount; +#else + const qsizetype offset = d->propertyCount + d->enumeratorCount; +#endif + + auto iface = this->d.metaTypes[offset]; if (iface && QtMetaTypePrivate::isInterfaceFor(iface)) return QMetaType(); // return invalid meta-type for namespaces if (iface) @@ -3036,6 +3056,33 @@ const char *QMetaEnum::enumName() const return rawStringData(mobj, data.alias()); } +/*! + Returns the meta type of the enum. + + If the QMetaObject this enum is part of was generated with Qt 6.5 or + earlier this will be the invalid metatype. + + \note This is the meta type of the enum itself, not of its underlying + numeric type. You can retrieve the meta type of the underlying type of the + enum using \l{QMetaType::underlyingType()}. + + \since 6.6 + \sa QMetaType::underlyingType() +*/ +QMetaType QMetaEnum::metaType() const +{ + if (!mobj) + return {}; + + const QMetaObjectPrivate *p = priv(mobj->d.data); +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + if (p->revision < 12) + QMetaType(); +#endif + + return QMetaType(mobj->d.metaTypes[data.index(mobj) + p->propertyCount]); +} + /*! Returns the number of keys. @@ -3285,6 +3332,11 @@ QMetaEnum::QMetaEnum(const QMetaObject *mobj, int index) Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->enumeratorCount); } +int QMetaEnum::Data::index(const QMetaObject *mobj) const +{ + return (d - mobj->d.data - priv(mobj->d.data)->enumeratorData) / Size; +} + /*! \fn QMetaEnum QMetaEnum::fromType() \since 5.5 diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index 3aa3a687c4f..b27a8636eb5 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -265,6 +265,8 @@ public: const char *name() const; const char *enumName() const; + QMetaType metaType() const; + bool isFlag() const; bool isScoped() const; @@ -302,6 +304,7 @@ private: quint32 flags() const { return d[2]; } qint32 keyCount() const { return static_cast(d[3]); } quint32 data() const { return d[4]; } + int index(const QMetaObject *mobj) const; const uint *d; }; diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index d05b727f521..224c9d53541 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -175,7 +175,8 @@ struct QMetaObjectPrivate // revision 10 is Qt 6.2: The metatype of the metaobject is stored in the metatypes array // and metamethods store a flag stating whether they are const // revision 11 is Qt 6.5: The metatype for void is stored in the metatypes array - enum { OutputRevision = 11 }; // Used by moc, qmetaobjectbuilder and qdbus + // revision 12 is Qt 6.6: It adds the metatype for enums + enum { OutputRevision = 12 }; // Used by moc, qmetaobjectbuilder and qdbus enum { IntsPerMethod = QMetaMethod::Data::Size }; enum { IntsPerEnum = QMetaEnum::Data::Size }; enum { IntsPerProperty = QMetaProperty::Data::Size }; diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index e61065f42f4..b471bf65466 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -159,6 +159,7 @@ public: QByteArray name; QByteArray enumName; + QMetaType metaType; bool isFlag; bool isScoped; QList keys; @@ -597,6 +598,7 @@ QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum &prototype) { QMetaEnumBuilder en = addEnumerator(prototype.name()); en.setEnumName(prototype.enumName()); + en.setMetaType(prototype.metaType()); en.setIsFlag(prototype.isFlag()); en.setIsScoped(prototype.isScoped()); int count = prototype.keyCount(); @@ -1170,7 +1172,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 constexpr (mode == Construct) { - static_assert(QMetaObjectPrivate::OutputRevision == 11, "QMetaObjectBuilder should generate the same version as moc"); + static_assert(QMetaObjectPrivate::OutputRevision == 12, "QMetaObjectBuilder should generate the same version as moc"); pmeta->revision = QMetaObjectPrivate::OutputRevision; pmeta->flags = d->flags.toInt(); pmeta->className = 0; // Class name is always the first string. @@ -2305,6 +2307,31 @@ void QMetaEnumBuilder::setEnumName(const QByteArray &alias) d->enumName = alias; } +/*! + Returns the meta type of the enumerator. + + \since 6.6 +*/ +QMetaType QMetaEnumBuilder::metaType() const +{ + if (QMetaEnumBuilderPrivate *d = d_func()) + return d->metaType; + return QMetaType(); +} + +/*! + Sets this enumerator to have the given \c metaType. + + \since 6.6 + \sa metaType() +*/ +void QMetaEnumBuilder::setMetaType(QMetaType metaType) +{ + QMetaEnumBuilderPrivate *d = d_func(); + if (d) + d->metaType = metaType; +} + /*! Returns \c true if this enumerator is used as a flag; otherwise returns false. diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h index 99eaca2ac9e..b52487986ce 100644 --- a/src/corelib/kernel/qmetaobjectbuilder_p.h +++ b/src/corelib/kernel/qmetaobjectbuilder_p.h @@ -258,6 +258,9 @@ public: QByteArray enumName() const; void setEnumName(const QByteArray &alias); + QMetaType metaType() const; + void setMetaType(QMetaType metaType); + bool isFlag() const; void setIsFlag(bool value); diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index 054bc448e6a..d2ca9df8690 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -391,7 +391,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) - methods.size(); // ditto QDBusMetaObjectPrivate *header = reinterpret_cast(idata.data()); - static_assert(QMetaObjectPrivate::OutputRevision == 11, "QtDBus meta-object generator should generate the same version as moc"); + static_assert(QMetaObjectPrivate::OutputRevision == 12, "QtDBus meta-object generator should generate the same version as moc"); header->revision = QMetaObjectPrivate::OutputRevision; header->className = 0; header->classInfoCount = 0; diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index ca6a4181b60..cef460b7ddb 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -378,7 +378,7 @@ void Generator::generateCode() int enumsIndex = index; for (int i = 0; i < cdef->enumList.size(); ++i) - index += 5 + (cdef->enumList.at(i).values.size() * 2); + index += QMetaObjectPrivate::IntsPerEnum + (cdef->enumList.at(i).values.size() * 2); fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? int(cdef->constructorList.size()) : 0, isConstructible ? index : 0); @@ -397,8 +397,8 @@ void Generator::generateCode() // generateClassInfos(); - // all property metatypes, + 1 for the type of the current class itself - int initialMetaTypeOffset = cdef->propertyList.size() + 1; + // all property metatypes + all enum metatypes + 1 for the type of the current class itself + int initialMetaTypeOffset = cdef->propertyList.size() + cdef->enumList.size() + 1; // // Build signals array first, otherwise the signal indices would be wrong @@ -576,6 +576,15 @@ void Generator::generateCode() comma = ","; } + // metatypes for enums + for (int i = 0; i < cdef->enumList.size(); ++i) { + const EnumDef &e = cdef->enumList.at(i); + fprintf(out, "%s\n // enum '%s'\n %s", + comma, e.name.constData(), + stringForType(cdef->classname % "::" % e.name, true).constData()); + comma = ","; + } + // type name for the Q_OJBECT/GADGET itself, void for namespaces auto ownType = !cdef->hasQNamespace ? cdef->classname.data() : "void"; fprintf(out, "%s\n // Q_OBJECT / Q_GADGET\n %s", @@ -943,7 +952,7 @@ void Generator::generateEnums(int index) return; fprintf(out, "\n // enums: name, alias, flags, count, data\n"); - index += 5 * cdef->enumList.size(); + index += QMetaObjectPrivate::IntsPerEnum * cdef->enumList.size(); int i; for (i = 0; i < cdef->enumList.size(); ++i) { const EnumDef &e = cdef->enumList.at(i); diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 64e98ae63be..743742ba970 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -243,7 +243,7 @@ bool Moc::parseEnum(EnumDef *def) } if (test(COLON)) { // C++11 strongly typed enum // enum Foo : unsigned long { ... }; - parseType(); //ignore the result + def->type = normalizeType(parseType().name); } if (!test(LBRACE)) return false; @@ -2107,6 +2107,8 @@ QJsonObject EnumDef::toJson(const ClassDef &cdef) const def["name"_L1] = QString::fromUtf8(name); if (!enumName.isEmpty()) def["alias"_L1] = QString::fromUtf8(enumName); + if (!type.isEmpty()) + def["type"_L1] = QString::fromUtf8(type); def["isFlag"_L1] = cdef.enumDeclarations.value(name); def["isClass"_L1] = isEnumClass; diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index edeac03b82b..5df15409a7c 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -43,6 +43,7 @@ struct EnumDef { QByteArray name; QByteArray enumName; + QByteArray type; QList values; bool isEnumClass; // c++11 enum class EnumDef() : isEnumClass(false) {} diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp index 38c896b6a35..42df2987700 100644 --- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp +++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp @@ -779,6 +779,26 @@ void tst_QMetaObjectBuilder::notifySignal() void tst_QMetaObjectBuilder::enumerator() { + static const QtPrivate::QMetaTypeInterface fooFlagMetaType = { + 0, + 8, + 8, + QMetaType::IsEnumeration | QMetaType::IsUnsignedEnumeration | QMetaType::RelocatableType, + {}, + nullptr, + "fooFlag", + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + }; + QMetaObjectBuilder builder; // Add an enumerator and check its attributes. @@ -810,6 +830,7 @@ void tst_QMetaObjectBuilder::enumerator() enum1.setIsFlag(true); enum1.setIsScoped(true); enum1.setEnumName(QByteArrayLiteral("fooFlag")); + enum1.setMetaType(QMetaType(&fooFlagMetaType)); QCOMPARE(enum1.addKey("ABC", 0), 0); QCOMPARE(enum1.addKey("DEF", 1), 1); QCOMPARE(enum1.addKey("GHI", -1), 2); @@ -819,6 +840,7 @@ void tst_QMetaObjectBuilder::enumerator() QVERIFY(enum1.isFlag()); QVERIFY(enum1.isScoped()); QCOMPARE(enum1.enumName(), QByteArray("fooFlag")); + QCOMPARE(enum1.metaType(), QMetaType(&fooFlagMetaType)); QCOMPARE(enum1.keyCount(), 3); QCOMPARE(enum1.index(), 0); QCOMPARE(enum1.key(0), QByteArray("ABC")); diff --git a/tests/auto/tools/moc/allmocs_baseline_in.json b/tests/auto/tools/moc/allmocs_baseline_in.json index 46f643d09b0..50dbb200d2d 100644 --- a/tests/auto/tools/moc/allmocs_baseline_in.json +++ b/tests/auto/tools/moc/allmocs_baseline_in.json @@ -91,6 +91,7 @@ "isClass": false, "isFlag": false, "name": "TypedEnum", + "type": "char", "values": [ "B0", "B1", @@ -102,6 +103,7 @@ "isClass": true, "isFlag": false, "name": "TypedEnumClass", + "type": "char", "values": [ "C0", "C1", @@ -147,6 +149,7 @@ "isClass": true, "isFlag": false, "name": "TypedEnumStruct", + "type": "char", "values": [ "H0", "H1", @@ -188,6 +191,7 @@ "isClass": false, "isFlag": false, "name": "TypedEnum", + "type": "char", "values": [ "B0", "B1", @@ -199,6 +203,7 @@ "isClass": true, "isFlag": false, "name": "TypedEnumClass", + "type": "char", "values": [ "C0", "C1", @@ -232,6 +237,65 @@ ], "gadget": true, "qualifiedClassName": "CXX11Enums2" + }, + { + "className": "CXX11Enums3", + "enums": [ + { + "isClass": true, + "isFlag": false, + "name": "EnumClass", + "values": [ + "A0", + "A1", + "A2", + "A3" + ] + }, + { + "isClass": false, + "isFlag": false, + "name": "TypedEnum", + "type": "char", + "values": [ + "B0", + "B1", + "B2", + "B3" + ] + }, + { + "isClass": true, + "isFlag": false, + "name": "TypedEnumClass", + "type": "char", + "values": [ + "C0", + "C1", + "C2", + "C3" + ] + }, + { + "isClass": false, + "isFlag": false, + "name": "NormalEnum", + "values": [ + "D2", + "D3", + "D0", + "D1" + ] + } + ], + "object": true, + "qualifiedClassName": "CXX11Enums3", + "superClasses": [ + { + "access": "public", + "name": "QObject" + } + ] } ], "inputFile": "cxx11-enums.h", diff --git a/tests/auto/tools/moc/cxx11-enums.h b/tests/auto/tools/moc/cxx11-enums.h index cd82a5df6d2..821cd038636 100644 --- a/tests/auto/tools/moc/cxx11-enums.h +++ b/tests/auto/tools/moc/cxx11-enums.h @@ -47,4 +47,20 @@ public: Q_FLAGS(ClassFlags) }; +class CXX11Enums3 : public QObject +{ + Q_OBJECT +public: + enum class EnumClass { A0, A1, A2, A3 }; + 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 = 1, F1 = 2, F2 = 4, F3 = 8 }; + + Q_ENUM(EnumClass) + Q_ENUM(TypedEnum) + Q_ENUM(TypedEnumClass) + Q_ENUM(NormalEnum) +}; + #endif // CXX11_ENUMS_H diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index e2844e29d1d..6a2962d609e 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -98,6 +98,12 @@ public: Key2 }; Q_ENUM(TestGEnum2) + + enum TestGEnum3: quint8 { + Key1 = 23, + Key2 + }; + Q_ENUM(TestGEnum3) }; } @@ -116,6 +122,12 @@ namespace TestQNamespace { }; Q_ENUM_NS(TestEnum2) + enum TestEnum3: qint8 { + Key1 = 23, + Key2 + }; + Q_ENUM_NS(TestEnum3) + // try to dizzy moc by adding a struct in between struct TestGadget { Q_GADGET @@ -128,8 +140,13 @@ namespace TestQNamespace { Key1 = 23, Key2 }; + enum TestGEnum3: qint16 { + Key1 = 33, + Key2 + }; Q_ENUM(TestGEnum1) Q_ENUM(TestGEnum2) + Q_ENUM(TestGEnum3) }; struct TestGadgetExport { @@ -146,6 +163,12 @@ namespace TestQNamespace { Key2 }; Q_ENUM(TestGeEnum2) + enum TestGeEnum3: quint16 { + Key1 = 26, + Key2 + }; + Q_ENUM(TestGeEnum3) + }; enum class TestFlag1 { @@ -2428,23 +2451,29 @@ void tst_Moc::cxx11Enums_data() QTest::addColumn("enumName"); QTest::addColumn("prefix"); QTest::addColumn("isScoped"); + QTest::addColumn("isTyped"); const QMetaObject *meta1 = &CXX11Enums::staticMetaObject; const QMetaObject *meta2 = &CXX11Enums2::staticMetaObject; + const QMetaObject *meta3 = &CXX11Enums3::staticMetaObject; - 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; - QTest::newRow("EnumStruct") << meta1 << QByteArray("EnumStruct") << QByteArray("EnumStruct") << 'G' << true; - QTest::newRow("TypedEnumStruct") << meta1 << QByteArray("TypedEnumStruct") << QByteArray("TypedEnumStruct") << 'H' << true; - QTest::newRow("StructFlags") << meta1 << QByteArray("StructFlags") << QByteArray("StructFlag") << 'I' << true; + QTest::newRow("EnumClass") << meta1 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true << false; + QTest::newRow("EnumClass 2") << meta2 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true << false; + QTest::newRow("EnumClass 3") << meta3 << QByteArray("EnumClass") << QByteArray("EnumClass") << 'A' << true << false; + QTest::newRow("TypedEnum") << meta1 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false << true; + QTest::newRow("TypedEnum 2") << meta2 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false << true; + QTest::newRow("TypedEnum 3") << meta3 << QByteArray("TypedEnum") << QByteArray("TypedEnum") << 'B' << false << true; + QTest::newRow("TypedEnumClass") << meta1 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true << true; + QTest::newRow("TypedEnumClass 2") << meta2 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true << true; + QTest::newRow("TypedEnumClass 3") << meta3 << QByteArray("TypedEnumClass") << QByteArray("TypedEnumClass") << 'C' << true << true; + QTest::newRow("NormalEnum") << meta1 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false << false; + QTest::newRow("NormalEnum 2") << meta2 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false << false; + QTest::newRow("NormalEnum 3") << meta3 << QByteArray("NormalEnum") << QByteArray("NormalEnum") << 'D' << false << false; + QTest::newRow("ClassFlags") << meta1 << QByteArray("ClassFlags") << QByteArray("ClassFlag") << 'F' << true << false; + QTest::newRow("ClassFlags 2") << meta2 << QByteArray("ClassFlags") << QByteArray("ClassFlag") << 'F' << true << false; + QTest::newRow("EnumStruct") << meta1 << QByteArray("EnumStruct") << QByteArray("EnumStruct") << 'G' << true << false; + QTest::newRow("TypedEnumStruct") << meta1 << QByteArray("TypedEnumStruct") << QByteArray("TypedEnumStruct") << 'H' << true << true; + QTest::newRow("StructFlags") << meta1 << QByteArray("StructFlags") << QByteArray("StructFlag") << 'I' << true << false; } void tst_Moc::cxx11Enums() @@ -2456,24 +2485,39 @@ void tst_Moc::cxx11Enums() QFETCH(QByteArray, enumName); QFETCH(char, prefix); QFETCH(bool, isScoped); + QFETCH(bool, isTyped); 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(), typeName.constData()); - QCOMPARE(meta->enumerator(idx).enumName(), enumName.constData()); - bool isFlag = meta->enumerator(idx).isFlag(); + const QMetaEnum metaEnum = meta->enumerator(idx); + QCOMPARE(metaEnum.enclosingMetaObject(), meta); + QCOMPARE(metaEnum.isValid(), true); + QCOMPARE(metaEnum.keyCount(), 4); + QCOMPARE(metaEnum.name(), typeName.constData()); + QCOMPARE(metaEnum.enumName(), enumName.constData()); + + const QMetaType metaType = metaEnum.metaType(); + const bool isUnsigned = metaType.flags() & QMetaType::IsUnsignedEnumeration; + if (isTyped) { + QCOMPARE(metaType.sizeOf(), sizeof(char)); + QCOMPARE(isUnsigned, !std::is_signed_v); + } else if (isScoped) { + QCOMPARE(metaType.sizeOf(), sizeof(int)); + QCOMPARE(isUnsigned, !std::is_signed_v); + } else { + // underlying type is implementation defined + } + + bool isFlag = metaEnum.isFlag(); for (int i = 0; i < 4; i++) { QByteArray v = prefix + QByteArray::number(i); const int value = isFlag ? (1 << i) : i; - QCOMPARE(meta->enumerator(idx).keyToValue(v), value); - QCOMPARE(meta->enumerator(idx).valueToKey(value), v.constData()); + QCOMPARE(metaEnum.keyToValue(v), value); + QCOMPARE(metaEnum.valueToKey(value), v.constData()); } - QCOMPARE(meta->enumerator(idx).isScoped(), isScoped); + QCOMPARE(metaEnum.isScoped(), isScoped); } void tst_Moc::cxx11TrailingReturn() @@ -3994,10 +4038,12 @@ void tst_Moc::optionsFileError() } static void checkEnum(const QMetaEnum &enumerator, const QByteArray &name, - const QList> &keys) + const QList> &keys, + const QMetaType underlyingType = QMetaType::fromType()) { QCOMPARE(name, QByteArray{enumerator.name()}); QCOMPARE(keys.size(), enumerator.keyCount()); + QCOMPARE(underlyingType, enumerator.metaType().underlyingType()); for (int i = 0; i < enumerator.keyCount(); ++i) { QCOMPARE(keys[i].first, QByteArray{enumerator.key(i)}); QCOMPARE(keys[i].second, enumerator.value(i)); @@ -4014,27 +4060,33 @@ public: void tst_Moc::testQNamespace() { - QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 4); + QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 5); checkEnum(TestQNamespace::staticMetaObject.enumerator(0), "TestEnum1", {{"Key1", 11}, {"Key2", 12}}); checkEnum(TestQNamespace::staticMetaObject.enumerator(1), "TestEnum2", {{"Key1", 17}, {"Key2", 18}}); - checkEnum(TestQNamespace::staticMetaObject.enumerator(2), "TestFlag1", + checkEnum(TestQNamespace::staticMetaObject.enumerator(2), "TestEnum3", + {{"Key1", 23}, {"Key2", 24}}, QMetaType::fromType()); + checkEnum(TestQNamespace::staticMetaObject.enumerator(3), "TestFlag1", {{"None", 0}, {"Flag1", 1}, {"Flag2", 2}, {"Any", 1 | 2}}); - checkEnum(TestQNamespace::staticMetaObject.enumerator(3), "TestFlag2", + checkEnum(TestQNamespace::staticMetaObject.enumerator(4), "TestFlag2", {{"None", 0}, {"Flag1", 4}, {"Flag2", 8}, {"Any", 4 | 8}}); - QCOMPARE(TestQNamespace::TestGadget::staticMetaObject.enumeratorCount(), 2); + QCOMPARE(TestQNamespace::TestGadget::staticMetaObject.enumeratorCount(), 3); checkEnum(TestQNamespace::TestGadget::staticMetaObject.enumerator(0), "TestGEnum1", {{"Key1", 13}, {"Key2", 14}}); checkEnum(TestQNamespace::TestGadget::staticMetaObject.enumerator(1), "TestGEnum2", {{"Key1", 23}, {"Key2", 24}}); + checkEnum(TestQNamespace::TestGadget::staticMetaObject.enumerator(2), "TestGEnum3", + {{"Key1", 33}, {"Key2", 34}}, QMetaType::fromType()); - QCOMPARE(TestQNamespace::TestGadgetExport::staticMetaObject.enumeratorCount(), 2); + QCOMPARE(TestQNamespace::TestGadgetExport::staticMetaObject.enumeratorCount(), 3); checkEnum(TestQNamespace::TestGadgetExport::staticMetaObject.enumerator(0), "TestGeEnum1", {{"Key1", 20}, {"Key2", 21}}); checkEnum(TestQNamespace::TestGadgetExport::staticMetaObject.enumerator(1), "TestGeEnum2", {{"Key1", 23}, {"Key2", 24}}); + checkEnum(TestQNamespace::TestGadgetExport::staticMetaObject.enumerator(2), "TestGeEnum3", + {{"Key1", 26}, {"Key2", 27}}, QMetaType::fromType()); QMetaEnum meta = QMetaEnum::fromType(); QVERIFY(meta.isValid());