From c407d79f79c67f2f2bb84efc93061fd57fe4cf54 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 14 Oct 2010 18:22:57 +1000 Subject: Correctly splice properties from derived metaobjects together Task-number: QTBUG-14449 --- src/declarative/qml/qdeclarativepropertycache.cpp | 77 ++++++---------------- src/declarative/qml/qdeclarativepropertycache_p.h | 9 ++- .../data/propertySplicing.qml | 10 +++ .../qdeclarativeecmascript/testtypes.cpp | 1 + .../declarative/qdeclarativeecmascript/testtypes.h | 9 +++ .../tst_qdeclarativeecmascript.cpp | 13 ++++ 6 files changed, 61 insertions(+), 58 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/propertySplicing.qml diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp index 9e1ceb8..82fa98f 100644 --- a/src/declarative/qml/qdeclarativepropertycache.cpp +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -252,7 +252,8 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb } int methodCount = metaObject->methodCount(); - int methodOffset = qMax(2, metaObject->methodOffset()); // 2 to block the destroyed signal + // 3 to block the destroyed signal and the deleteLater() slot + int methodOffset = qMax(3, metaObject->methodOffset()); methodIndexCache.resize(methodCount); for (int ii = methodOffset; ii < methodCount; ++ii) { @@ -268,17 +269,17 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb RData *data = new RData; data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName); - if (stringCache.contains(methodName)) { - stringCache[methodName]->release(); - identifierCache[data->identifier.identifier]->release(); - } - data->load(m); if (m.methodType() == QMetaMethod::Slot || m.methodType() == QMetaMethod::Method) data->flags |= methodFlags; else if (m.methodType() == QMetaMethod::Signal) data->flags |= signalFlags; + if (stringCache.contains(methodName)) { + stringCache[methodName]->release(); + identifierCache[data->identifier.identifier]->release(); + } + methodIndexCache[ii] = data; stringCache.insert(methodName, data); @@ -287,6 +288,16 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb } } +void QDeclarativePropertyCache::updateRecur(QDeclarativeEngine *engine, const QMetaObject *metaObject) +{ + if (!metaObject) + return; + + updateRecur(engine, metaObject->superClass()); + + append(engine, metaObject); +} + void QDeclarativePropertyCache::update(QDeclarativeEngine *engine, const QMetaObject *metaObject) { Q_ASSERT(engine); @@ -295,57 +306,11 @@ void QDeclarativePropertyCache::update(QDeclarativeEngine *engine, const QMetaOb clear(); - // ### The properties/methods should probably be spliced on a per-metaobject basis - int propCount = metaObject->propertyCount(); - - indexCache.resize(propCount); - for (int ii = propCount - 1; ii >= 0; --ii) { - QMetaProperty p = metaObject->property(ii); - if (!p.isScriptable()) { - indexCache[ii] = 0; - continue; - } - QString propName = QString::fromUtf8(p.name()); + // Optimization to prevent unnecessary reallocation of lists + indexCache.reserve(metaObject->propertyCount()); + methodIndexCache.reserve(metaObject->methodCount()); - RData *data = new RData; - data->identifier = enginePriv->objectClass->createPersistentIdentifier(propName); - - data->load(p, engine); - - indexCache[ii] = data; - - if (stringCache.contains(propName)) - continue; - - stringCache.insert(propName, data); - identifierCache.insert(data->identifier.identifier, data); - data->addref(); - data->addref(); - } - - int methodCount = metaObject->methodCount(); - for (int ii = methodCount - 1; ii >= 3; --ii) { // >=3 to block the destroyed signal and deleteLater() slot - QMetaMethod m = metaObject->method(ii); - if (m.access() == QMetaMethod::Private) - continue; - QString methodName = QString::fromUtf8(m.signature()); - - int parenIdx = methodName.indexOf(QLatin1Char('(')); - Q_ASSERT(parenIdx != -1); - methodName = methodName.left(parenIdx); - - if (stringCache.contains(methodName)) - continue; - - RData *data = new RData; - data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName); - - data->load(m); - - stringCache.insert(methodName, data); - identifierCache.insert(data->identifier.identifier, data); - data->addref(); - } + updateRecur(engine,metaObject); } QDeclarativePropertyCache::Data * diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h index 79b126d..922010d 100644 --- a/src/declarative/qml/qdeclarativepropertycache_p.h +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -96,7 +96,7 @@ public: IsVMEFunction = 0x00000400, HasArguments = 0x00000800, IsSignal = 0x00001000, - IsVMESignal = 0x00002000, + IsVMESignal = 0x00002000 }; Q_DECLARE_FLAGS(Flags, Flag) @@ -105,7 +105,10 @@ public: Flags flags; int propType; int coreIndex; - int notifyIndex; + union { + int notifyIndex; // When !IsFunction + int relatedIndex; // When IsFunction + }; static Flags flagsForProperty(const QMetaProperty &, QDeclarativeEngine *engine = 0); void load(const QMetaProperty &, QDeclarativeEngine *engine = 0); @@ -152,6 +155,8 @@ private: typedef QHash StringCache; typedef QHash IdentifierCache; + void updateRecur(QDeclarativeEngine *, const QMetaObject *); + QDeclarativeEngine *engine; IndexCache indexCache; IndexCache methodIndexCache; diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/propertySplicing.qml b/tests/auto/declarative/qdeclarativeecmascript/data/propertySplicing.qml new file mode 100644 index 0000000..7deb84a --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/propertySplicing.qml @@ -0,0 +1,10 @@ +import Qt.test 1.0 +import QtQuick 1.0 + +MyDerivedObject { + property bool test: false + + Component.onCompleted: { + test = intProperty() + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp index 810a0f7..94135f9 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp @@ -109,6 +109,7 @@ void registerTypes() qmlRegisterExtendedType("Qt.test", 1,0, "MyBaseExtendedObject"); qmlRegisterExtendedType("Qt.test", 1,0, "MyExtendedObject"); qmlRegisterType("Qt.test", 1,0, "MyTypeObject"); + qmlRegisterType("Qt.test", 1,0, "MyDerivedObject"); qmlRegisterType("Qt.test", 1,0, "NumberAssignment"); qmlRegisterExtendedType("Qt.test", 1,0, "DefaultPropertyExtendedObject"); qmlRegisterType("Qt.test", 1,0, "OverrideDefaultPropertyObject"); diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h index 220318d..182c4fa 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h @@ -562,6 +562,15 @@ signals: }; Q_DECLARE_OPERATORS_FOR_FLAGS(MyTypeObject::MyFlags) +class MyDerivedObject : public MyTypeObject +{ + Q_OBJECT +public: + Q_INVOKABLE bool intProperty() const { + return true; + } +}; + Q_DECLARE_METATYPE(QScriptValue); class MyInvokableObject : public QObject { diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 02832f3..66dc160 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -139,6 +139,7 @@ private slots: void strictlyEquals(); void compiled(); void numberAssignment(); + void propertySplicing(); void bug1(); void bug2(); @@ -2175,6 +2176,18 @@ void tst_qdeclarativeecmascript::numberAssignment() delete object; } +void tst_qdeclarativeecmascript::propertySplicing() +{ + QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml")); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("test").toBool(), true); + + delete object; +} + // Test that assigning a null object works // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4 void tst_qdeclarativeecmascript::nullObjectBinding() -- cgit v0.12