diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index e7b2030bed6..6fe9c8122db 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -577,8 +577,7 @@ void Generator::generateCode() // metatypes for enums for (const EnumDef &e : std::as_const(cdef->enumList)) { fprintf(out, "%s\n // enum '%s'\n %s", - comma, e.name.constData(), - stringForType(cdef->classname % "::" % e.name, true).constData()); + comma, e.name.constData(), stringForType(e.qualifiedType(cdef), true).constData()); comma = ","; } diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 49278ef0aeb..9e38ec23c52 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -2147,4 +2147,23 @@ QJsonObject EnumDef::toJson(const ClassDef &cdef) const return def; } +QByteArray EnumDef::qualifiedType(const ClassDef *cdef) const +{ + if (name == cdef->classname) { + // The name of the enclosing namespace is the same as the enum class name + if (cdef->qualified.contains("::")) { + // QTBUG-112996, fully qualify by using cdef->qualified to disambiguate enum + // class name and enclosing namespace, e.g.: + // namespace A { namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) } } + return cdef->qualified % "::" % name; + } else { + // Just "B"; otherwise the compiler complains about the type "B::B" inside + // "B::staticMetaObject" in the generated code; e.g.: + // namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) } + return name; + } + } + return cdef->classname % "::" % name; +} + QT_END_NAMESPACE diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index d6b7d7664d7..b2de6d45e4a 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -48,6 +48,7 @@ struct EnumDef bool isEnumClass; // c++11 enum class EnumDef() : isEnumClass(false) {} QJsonObject toJson(const ClassDef &cdef) const; + QByteArray qualifiedType(const ClassDef *cdef) const; }; Q_DECLARE_TYPEINFO(EnumDef, Q_RELOCATABLE_TYPE); diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 77316aa43ea..0cd33288fcf 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -203,6 +203,27 @@ namespace TestQNamespace { Q_FLAG_NS(TestFlag2) } +namespace TestSameEnumNamespace { + Q_NAMESPACE + + enum class TestSameEnumNamespace { + Key1 = 1, + Key2 = 2, + }; + Q_ENUM_NS(TestSameEnumNamespace) +} + +namespace TestNestedSameEnumNamespace { +namespace a { + Q_NAMESPACE + // enum class with the same name as the enclosing nested namespace + enum class a { + Key11 = 11, + Key12 = 12, + }; + Q_ENUM_NS(a) +} +} namespace TestExportNamespace { Q_NAMESPACE_EXPORT(TESTEXPORTMACRO) @@ -794,6 +815,7 @@ private slots: void optionsFileError_data(); void optionsFileError(); void testQNamespace(); + void testNestedQNamespace(); void cxx17Namespaces(); void cxxAttributes(); void mocJsonOutput(); @@ -4086,6 +4108,28 @@ public: FooNamespace::Enum1 prop() { return FooNamespace::Enum1::Key2; } }; +void tst_Moc::testNestedQNamespace() +{ + QCOMPARE(TestSameEnumNamespace::staticMetaObject.enumeratorCount(), 1); + checkEnum(TestSameEnumNamespace::staticMetaObject.enumerator(0), "TestSameEnumNamespace", + {{"Key1", 1}, {"Key2", 2}}); + QMetaEnum meta1 = QMetaEnum::fromType(); + QVERIFY(meta1.isValid()); + QCOMPARE(meta1.name(), "TestSameEnumNamespace"); + QCOMPARE(meta1.enclosingMetaObject(), &TestSameEnumNamespace::staticMetaObject); + QCOMPARE(meta1.keyCount(), 2); + + // QTBUG-112996 + QCOMPARE(TestNestedSameEnumNamespace::a::staticMetaObject.enumeratorCount(), 1); + checkEnum(TestNestedSameEnumNamespace::a::staticMetaObject.enumerator(0), "a", + {{"Key11", 11}, {"Key12", 12}}); + QMetaEnum meta2 = QMetaEnum::fromType(); + QVERIFY(meta2.isValid()); + QCOMPARE(meta2.name(), "a"); + QCOMPARE(meta2.enclosingMetaObject(), &TestNestedSameEnumNamespace::a::staticMetaObject); + QCOMPARE(meta2.keyCount(), 2); +} + void tst_Moc::testQNamespace() { QCOMPARE(TestQNamespace::staticMetaObject.enumeratorCount(), 5);