From 17076ecd2afc1e025c60169700e6802901dd0f92 Mon Sep 17 00:00:00 2001
From: Dominik Holland <dominik.holland@pelagicore.com>
Date: Mon, 24 Sep 2018 13:53:44 +0200
Subject: [PATCH] WIP: Fix the QMetaObjectBuilder to also allow NOTIFY from
 parent classes

Change-Id: I2520da809855918b41d0624702317981ea128100
---
 src/corelib/kernel/qmetaobjectbuilder.cpp     | 34 ++++++++---
 .../tst_qmetaobjectbuilder.cpp                | 56 +++++++++++++++++++
 2 files changed, 81 insertions(+), 9 deletions(-)

diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp
index d2030f0275..67fd8a5393 100644
--- a/src/corelib/kernel/qmetaobjectbuilder.cpp
+++ b/src/corelib/kernel/qmetaobjectbuilder.cpp
@@ -45,6 +45,8 @@
 #include <vector>
 #include <stdlib.h>
 
+#include <QDebug>
+
 QT_BEGIN_NAMESPACE
 
 /*!
@@ -512,6 +514,7 @@ QMetaMethodBuilder QMetaObjectBuilder::addSlot(const QByteArray& signature)
 */
 QMetaMethodBuilder QMetaObjectBuilder::addSignal(const QByteArray& signature)
 {
+    qDebug() << "ADD SIGNAL" << signature;
     int index = int(d->methods.size());
     d->methods.push_back(QMetaMethodBuilderPrivate
         (QMetaMethod::Signal, signature, QByteArray("void"), QMetaMethod::Public));
@@ -600,13 +603,20 @@ QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& protot
     property.setFinal(prototype.isFinal());
     property.setRevision(prototype.revision());
     if (prototype.hasNotifySignal()) {
-        // Find an existing method for the notify signal, or add a new one.
-        QMetaMethod method = prototype.notifySignal();
-        int index = indexOfMethod(method.methodSignature());
-        if (index == -1)
-            index = addMethod(method).index();
-        d->properties[property._index].notifySignal = index;
-        d->properties[property._index].setFlag(Notify, true);
+        if (d->superClass && d->superClass->method(prototype.notifySignalIndex()).isValid()) {
+            qDebug() << "ADD EXITING SIGNAL" << prototype.notifySignalIndex();
+            d->properties[property._index].notifySignal = prototype.notifySignalIndex();
+            d->properties[property._index].setFlag(Notify, true);
+        } else {
+            // Find an existing method for the notify signal, or add a new one.
+            QMetaMethod method = prototype.notifySignal();
+            //qDebug() << "SEARCH FOR: " << method.methodSignature() << method.methodIndex();
+            int index = indexOfMethod(method.methodSignature());
+            if (index == -1)
+                index = addMethod(method).index();
+            d->properties[property._index].notifySignal = index;
+            d->properties[property._index].setFlag(Notify, true);
+        }
     }
     return property;
 }
@@ -703,6 +713,7 @@ void QMetaObjectBuilder::addMetaObject
     if ((members & (Methods | Signals | Slots)) != 0) {
         for (index = prototype->methodOffset(); index < prototype->methodCount(); ++index) {
             QMetaMethod method = prototype->method(index);
+            qDebug() << "ADDING" << method.methodSignature();
             if (method.methodType() != QMetaMethod::Signal) {
                 if (method.access() == QMetaMethod::Public && (members & PublicMethods) == 0)
                     continue;
@@ -968,6 +979,7 @@ int QMetaObjectBuilder::indexOfMethod(const QByteArray& signature)
 {
     QByteArray sig = QMetaObject::normalizedSignature(signature);
     for (const auto &method : d->methods) {
+        qDebug() << "METHOD:" << method.signature;
         if (sig == method.signature)
             return int(&method - &d->methods.front());
     }
@@ -1310,6 +1322,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
     // Output the methods in the class.
     Q_ASSERT(!buf || dataIndex == pmeta->methodData);
     for (const auto &method : d->methods) {
+        qDebug() << "BUILD METHOD: " << method.name();
         int name = strings.enter(method.name());
         int argc = method.parameterCount();
         int tag = strings.enter(method.tag);
@@ -1392,10 +1405,13 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
     if (hasNotifySignals) {
         for (const auto &prop : d->properties) {
             if (buf) {
-                if (prop.notifySignal != -1)
+                if (prop.notifySignal >= -1)
                     data[dataIndex] = prop.notifySignal;
-                else
+                if (prop.notifySignal == -1)
                     data[dataIndex] = 0;
+                else {
+                    //TODO Add the string data here
+                }
             }
             ++dataIndex;
         }
diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
index 56623773a2..fc90a77e6e 100644
--- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
+++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
@@ -53,6 +53,7 @@ private slots:
     void serialize();
     void relocatableData();
     void removeNotifySignal();
+    void notifyInParentClass();
 
     void usage_signal();
     void usage_property();
@@ -72,6 +73,27 @@ private:
         (const QMetaObject *meta1, const QMetaObject *meta2);
 };
 
+class BaseClass : public QObject
+{
+    Q_OBJECT
+public:
+    BaseClass() {}
+
+signals:
+    void testPropertyChanged(bool testProperty=false);
+};
+
+class DerivedClass : public BaseClass
+{
+    Q_OBJECT
+    Q_PROPERTY(bool testProperty READ testProperty WRITE setTestProperty NOTIFY testPropertyChanged)
+public:
+    DerivedClass() {}
+    bool testProperty() const { return false; }
+public slots:
+    void setTestProperty(bool testProperty) { Q_UNUSED(testProperty)}
+};
+
 // Dummy class that has something of every type of thing moc can generate.
 class SomethingOfEverything : public QObject
 {
@@ -1131,6 +1153,40 @@ void tst_QMetaObjectBuilder::removeNotifySignal()
     QVERIFY(!prop.hasNotifySignal());
 }
 
+void tst_QMetaObjectBuilder::notifyInParentClass()
+{
+    QMetaObjectBuilder builder(&DerivedClass::staticMetaObject);
+    QMetaObject *meta = builder.toMetaObject();
+    
+    const QMetaObject* mo = &DerivedClass::staticMetaObject;
+    qDebug() << "ORIG";
+    for (int i=0; i < mo->methodCount(); i++) {
+        QMetaMethod method = mo->method(i);
+        qDebug() << "method: " << method.methodIndex() << method.name();
+    }
+    for (int i=0; i < mo->propertyCount(); i++) {
+        QMetaProperty prop = mo->property(i);
+        qDebug() << "property:" << prop.propertyIndex() << prop.name();
+        QMetaMethod method = prop.notifySignal();
+        qDebug() << "signal: " << method.methodIndex() << method.name();
+    }
+
+    qDebug() << "PROXY";
+    mo = meta;
+    for (int i=0; i < mo->methodCount(); i++) {
+        QMetaMethod method = mo->method(i);
+        qDebug() << "method: " << method.methodIndex() << method.name();
+    }
+    for (int i=0; i < mo->propertyCount(); i++) {
+        QMetaProperty prop = mo->property(i);
+        qDebug() << "property:" << prop.propertyIndex() << prop.name();
+        QMetaMethod method = prop.notifySignal();
+        qDebug() << "signal: " << method.methodIndex() << method.name();
+    }
+
+    QVERIFY(sameMetaObject(meta, &DerivedClass::staticMetaObject));
+}
+
 // Check that the only changes to a "builder" relative to the default
 // state is specified by "members".
 bool tst_QMetaObjectBuilder::checkForSideEffects
-- 
2.18.0

