summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-05-10 13:17:50 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-05-12 15:06:42 +0200
commitc8cba48b92575d0e7ffcdc910b38e02d232f6c21 (patch)
tree0cd3ccf97102ad09b77a1479d3247d957a4eecc2
parentd88b52b541a0482b69639dbea8976287db9ca52b (diff)
downloadqtdeclarative-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.cpp75
-rw-r--r--src/qml/qml/qqmlcomponent_p.h5
-rw-r--r--src/quicktemplates/qquickstackelement.cpp4
-rw-r--r--tests/auto/qml/qqmlcomponent/data/removeBinding.qml11
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp12
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()