diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index dee9f26c80dbaab0c69ed0c32b24a4033a67ff5b..4712fbd6143625fe1a35e652b67d9093f4dd6f4c 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -1317,6 +1317,31 @@ QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QS Q_ASSERT(metaObject); QQmlPropertyData rv; + + /* It's important to check the method list before checking for properties; + * otherwise, if the meta object is dynamic, a property will be created even + * if not found and it might obscure a method having the same name. */ + + //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML + static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); + static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); + static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); + + int methodCount = metaObject->methodCount(); + for (int ii = methodCount - 1; ii >= 0; --ii) { + if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx) + continue; + QMetaMethod m = metaObject->method(ii); + if (m.access() == QMetaMethod::Private) + continue; + QString methodName = QString::fromUtf8(m.name().constData()); + + if (methodName == property) { + rv.load(m); + return rv; + } + } + { const QMetaObject *cmo = metaObject; const QByteArray propertyName = property.toUtf8(); @@ -1342,27 +1367,6 @@ QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QS } } } - - //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML - static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); - static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); - static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); - - int methodCount = metaObject->methodCount(); - for (int ii = methodCount - 1; ii >= 0; --ii) { - if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx) - continue; - QMetaMethod m = metaObject->method(ii); - if (m.access() == QMetaMethod::Private) - continue; - QString methodName = QString::fromUtf8(m.name().constData()); - - if (methodName == property) { - rv.load(m); - return rv; - } - } - return rv; } diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp index 2b772ba9c4767025a7054335240977209a03029d..ca212d333b353de75d248a176953a9d89186cd84 100644 --- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp +++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp @@ -67,6 +67,7 @@ private slots: void QTBUG_17868(); void metaObjectAccessibility(); void QTBUG_31226(); + void QTBUG_29836(); }; void tst_QQmlPropertyMap::insert() @@ -287,13 +288,17 @@ class MyEnhancedPropertyMap : public QQmlPropertyMap { Q_OBJECT public: - MyEnhancedPropertyMap() : QQmlPropertyMap(this, 0) {} + MyEnhancedPropertyMap() : QQmlPropertyMap(this, 0), m_testSlotCalled(false) {} + bool testSlotCalled() const { return m_testSlotCalled; } signals: void testSignal(); public slots: - void testSlot() {} + void testSlot() { m_testSlotCalled = true; } + +private: + bool m_testSlotCalled; }; void tst_QQmlPropertyMap::metaObjectAccessibility() @@ -341,6 +346,29 @@ void tst_QQmlPropertyMap::QTBUG_31226() } +void tst_QQmlPropertyMap::QTBUG_29836() +{ + MyEnhancedPropertyMap map; + QCOMPARE(map.testSlotCalled(), false); + + QQmlEngine engine; + QQmlContext context(&engine); + context.setContextProperty("enhancedMap", &map); + QQmlComponent c(&engine); + c.setData("import QtQuick 2.0\n" + "Item {\n" + " Timer { interval: 5; running: true; onTriggered: enhancedMap.testSlot() }\n" + "}", + QUrl()); + QObject *obj = c.create(&context); + QVERIFY(obj); + + QTRY_COMPARE(map.testSlotCalled(), true); + + delete obj; + +} + QTEST_MAIN(tst_QQmlPropertyMap) #include "tst_qqmlpropertymap.moc"