diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-05-10 13:17:50 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-05-12 15:06:42 +0200 |
commit | c8cba48b92575d0e7ffcdc910b38e02d232f6c21 (patch) | |
tree | 0cd3ccf97102ad09b77a1479d3247d957a4eecc2 | |
parent | d88b52b541a0482b69639dbea8976287db9ca52b (diff) | |
download | qtdeclarative-c8cba48b92575d0e7ffcdc910b38e02d232f6c21.tar.gz |
QQmlComponent: Remove pending QProperty bindings in old createObject()
When calling the QQmlV4Function overload of createObject() we end up in
a different code path. The problem is the same, though.
Amends commit ef6e9f6b75848dfdacdd98cf9e7530f651b3dfca.
Pick-to: 6.5
Task-number: QTBUG-99363
Change-Id: I6341243b75d9db1e0fcb80d8d73dab6932d85fd2
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 75 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent_p.h | 5 | ||||
-rw-r--r-- | src/quicktemplates/qquickstackelement.cpp | 4 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/data/removeBinding.qml | 11 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp | 12 |
5 files changed, 78 insertions, 29 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 5ad5a1e742..bb1642bc8e 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -335,6 +335,35 @@ QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *cont return q->beginCreate(context); } +static void removePendingQPropertyBinding( + QV4::Value *object, const QString &propertyName, QQmlObjectCreator *creator) +{ + if (!creator) + return; + + QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>(); + if (!wrapper) + return; + + QObject *o = wrapper->object(); + if (!o) + return; + + if (QQmlData *ddata = QQmlData::get(o)) { + const QQmlPropertyData *propData = ddata->propertyCache->property( + propertyName, o, ddata->outerContext); + if (propData && propData->isBindable()) + creator->removePendingBinding(o, propData->coreIndex()); + return; + } + + const QMetaObject *meta = o->metaObject(); + Q_ASSERT(meta); + const int index = meta->indexOfProperty(propertyName.toUtf8()); + if (index != -1 && meta->property(index).isBindable()) + creator->removePendingBinding(o, index); +} + bool QQmlComponentPrivate::setInitialProperty( QObject *base, const QString &name, const QVariant &value) { @@ -359,25 +388,8 @@ bool QQmlComponentPrivate::setInitialProperty( scope.engine->hasException = false; return false; } - if (QQmlObjectCreator *creator = state.creator()) { - if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) { - if (QObject *o = wrapper->object()) { - if (QQmlData *ddata = QQmlData::get(o)) { - if (const QQmlPropertyData *propData = ddata->propertyCache->property( - lastProperty, o, ddata->outerContext)) { - if (propData->isBindable()) - creator->removePendingBinding(o, propData->coreIndex()); - } - } else { - const QMetaObject *meta = o->metaObject(); - Q_ASSERT(meta); - const int index = meta->indexOfProperty(lastProperty.toUtf8()); - if (index != -1 && meta->property(index).isBindable()) - creator->removePendingBinding(o, index); - } - } - } - } + + removePendingQPropertyBinding(object, lastProperty, state.creator()); return true; } @@ -1588,7 +1600,10 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) */ -void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent) +void QQmlComponentPrivate::setInitialProperties( + QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, + const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent, + QQmlObjectCreator *creator) { QV4::Scope scope(engine); QV4::ScopedObject object(scope); @@ -1628,7 +1643,8 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV qmlWarning(createdComponent, error); continue; } - name = engine->newString(properties.last()); + const QString lastProperty = properties.last(); + name = engine->newString(lastProperty); object->put(name, val); if (engine->hasException) { qmlWarning(createdComponent, engine->catchExceptionAsQmlError()); @@ -1637,6 +1653,8 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV auto prop = removePropertyFromRequired(createdComponent, name->toQString(), requiredProperties, engine->qmlEngine()); } + + removePendingQPropertyBinding(object, lastProperty, creator); } engine->hasException = false; @@ -1722,8 +1740,9 @@ void QQmlComponent::createObject(QQmlV4Function *args) if (!valuemap->isUndefined()) { QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext()); - QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap, - d->state.requiredProperties(), rv); + QQmlComponentPrivate::setInitialProperties( + v4, qmlContext, object, valuemap, d->state.requiredProperties(), rv, + d->state.creator()); } if (d->state.hasUnsetRequiredProperties()) { QList<QQmlError> errors; @@ -1892,8 +1911,10 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(v4engine, toCreate)); Q_ASSERT(object->as<QV4::Object>()); - if (!valuemap.isUndefined()) - setInitialProperties(v4engine, qmlContext, object, valuemap, requiredProperties, toCreate); + if (!valuemap.isUndefined()) { + setInitialProperties( + v4engine, qmlContext, object, valuemap, requiredProperties, toCreate, state.creator()); + } } QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4) @@ -1992,7 +2013,9 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties *re QV4::Scope scope(v4); QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o)); QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext); - QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap, requiredProperties, o); + QQmlComponentPrivate::setInitialProperties( + v4, qmlCtxt, obj, d()->valuemap, requiredProperties, o, + QQmlIncubatorPrivate::get(d()->incubator)->creator.data()); } } diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index 31cbf0a4fc..09c3965c2a 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -49,7 +49,10 @@ public: QObject *beginCreate(QQmlRefPointer<QQmlContextData>); void completeCreate(); void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties *requiredProperties); - static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent); + static void setInitialProperties( + QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, + const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent, + QQmlObjectCreator *creator); static QQmlError unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty); virtual void incubateObject( diff --git a/src/quicktemplates/qquickstackelement.cpp b/src/quicktemplates/qquickstackelement.cpp index 417aa41643..12c3fbdd94 100644 --- a/src/quicktemplates/qquickstackelement.cpp +++ b/src/quicktemplates/qquickstackelement.cpp @@ -187,7 +187,9 @@ void QQuickStackElement::initialize(RequiredProperties *requiredProperties) QV4::ScopedValue ipv(scope, properties.value()); QV4::Scoped<QV4::QmlContext> qmlContext(scope, qmlCallingContext.value()); QV4::ScopedValue qmlObject(scope, QV4::QObjectWrapper::wrap(v4, item)); - QQmlComponentPrivate::setInitialProperties(v4, qmlContext, qmlObject, ipv, requiredProperties, item); + QQmlComponentPrivate::setInitialProperties( + v4, qmlContext, qmlObject, ipv, requiredProperties, item, + component ? QQmlComponentPrivate::get(component)->state.creator() : nullptr); properties.clear(); } diff --git a/tests/auto/qml/qqmlcomponent/data/removeBinding.qml b/tests/auto/qml/qqmlcomponent/data/removeBinding.qml index 08126a1db2..091f6991be 100644 --- a/tests/auto/qml/qqmlcomponent/data/removeBinding.qml +++ b/tests/auto/qml/qqmlcomponent/data/removeBinding.qml @@ -18,4 +18,15 @@ QtObject { const item = customItem.createObject(root, properties) return item.objectName; } + + property string result2: { + const properties = { + "objectName": "43", + } + + // add some junk argument to trigger the QQmlV4Function overload + const item = customItem.createObject(root, properties, 13) + + return item.objectName; + } } diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index d6a14cd3ef..8e46b38b5a 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -1450,11 +1450,21 @@ void tst_qqmlcomponent::loadFromQrc() void tst_qqmlcomponent::removeBinding() { QQmlEngine e; - QQmlComponent c(&e, testFileUrl("removeBinding.qml")); + const QUrl url = testFileUrl("removeBinding.qml"); + QQmlComponent c(&e, url); QVERIFY2(c.isReady(), qPrintable(c.errorString())); + + QTest::ignoreMessage( + QtWarningMsg, + qPrintable(url.toString() + QStringLiteral(":7:27: QML Component: Unsuitable arguments " + "passed to createObject(). The first argument " + "should be a QObject* or null, and the second " + "argument should be a JavaScript object or a " + "QVariantMap"))); QScopedPointer<QObject> o(c.create()); QVERIFY(!o.isNull()); QCOMPARE(o->property("result"), QStringLiteral("42")); + QCOMPARE(o->property("result2"), QStringLiteral("43")); } void tst_qqmlcomponent::complexObjectArgument() |