Add support to moc for registering non-local enums via Q_ENUMS.
authorGlenn Watson <glenn.watson@nokia.com>
Fri, 25 Nov 2011 01:58:37 +0000 (11:58 +1000)
committerQt by Nokia <qt-info@nokia.com>
Sun, 27 Nov 2011 21:51:39 +0000 (22:51 +0100)
When using the Q_ENUMS macro to register an enumeration in a class
with moc, it's now possible to provide a scoped enumeration that
exists in another class. This adds the enum class scope to
a metaobject's list of related classes stored in the extradata
field.

This allows the declarative code to handle non-local enums in
signal and slot functions that are exposed to QML.

Task-number: QTBUG-20639
Change-Id: I94f5292818095fda75762bd1508ba5c69de19503
Reviewed-by: Martin Jones <martin.jones@nokia.com>
Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
src/tools/moc/generator.cpp
tests/auto/tools/moc/tst_moc.cpp

index bf9c451..81508d1 100644 (file)
@@ -313,6 +313,21 @@ void Generator::generateCode()
             }
         }
     }
+
+    // QTBUG-20639 - Accept non-local enums for QML signal/slot parameters.
+    // Look for any scoped enum declarations, and add those to the list
+    // of extra/related metaobjects for this object.
+    QList<QByteArray> enumKeys = cdef->enumDeclarations.keys();
+    for (int i = 0; i < enumKeys.count(); ++i) {
+        const QByteArray &enumKey = enumKeys[i];
+        int s = enumKey.lastIndexOf("::");
+        if (s > 0) {
+            QByteArray scope = enumKey.left(s);
+            if (scope != "Qt" && scope != cdef->classname && !extraList.contains(scope))
+                extraList += scope;
+        }
+    }
+
     if (!extraList.isEmpty()) {
         fprintf(out, "#ifdef Q_NO_DATA_RELOCATION\n");
         fprintf(out, "static const QMetaObjectAccessor qt_meta_extradata_%s[] = {\n    ", qualifiedClassNameIdentifier.constData());
index cfe516d..6d3ee26 100644 (file)
@@ -410,6 +410,24 @@ public:
     inline PropertyTestClass::TestEnum foo() const { return PropertyTestClass::One; }
 };
 
+class EnumSourceClass : public QObject
+{
+    Q_OBJECT
+
+public:
+    enum TestEnum { Value = 37 };
+
+    Q_ENUMS(TestEnum)
+};
+
+class EnumUserClass : public QObject
+{
+    Q_OBJECT
+
+public:
+    Q_ENUMS(EnumSourceClass::TestEnum)
+};
+
 #if defined(Q_MOC_RUN)
 // Task #119503
 #define _TASK_119503
@@ -483,6 +501,7 @@ private slots:
     void blackslashNewlines();
     void slotWithSillyConst();
     void testExtraData();
+    void testExtraDataForEnum();
     void namespaceTypeProperty();
     void slotsWithVoidTemplate();
     void structQObject();
@@ -810,6 +829,25 @@ void tst_Moc::testExtraData()
     QCOMPARE(QByteArray(en.name()), QByteArray("TestEnum"));
 }
 
+// QTBUG-20639 - Accept non-local enums for QML signal/slot parameters.
+void tst_Moc::testExtraDataForEnum()
+{
+    const QMetaObject *mobjSource = &EnumSourceClass::staticMetaObject;
+    QCOMPARE(mobjSource->enumeratorCount(), 1);
+    QCOMPARE(QByteArray(mobjSource->enumerator(0).name()), QByteArray("TestEnum"));
+
+    const QMetaObject *mobjUser = &EnumUserClass::staticMetaObject;
+    QCOMPARE(mobjUser->enumeratorCount(), 0);
+
+    const QMetaObjectExtraData *extra = reinterpret_cast<const QMetaObjectExtraData *>(mobjUser->d.extradata);
+    QVERIFY(extra);
+
+    const QMetaObject **objects = extra->objects;
+    QVERIFY(objects);
+    QVERIFY(objects[0] == mobjSource);
+    QVERIFY(objects[1] == 0);
+}
+
 void tst_Moc::namespaceTypeProperty()
 {
     qRegisterMetaType<myNS::Points>("myNS::Points");