aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp10
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h4
-rw-r--r--src/qml/types/qqmlbind.cpp101
-rw-r--r--tests/auto/qml/qqmlbinding/data/propertiesAttachedToBindingItself.qml18
-rw-r--r--tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp13
5 files changed, 121 insertions, 25 deletions
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index ea31ff0b56..42bac5d1d1 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -290,6 +290,16 @@ void QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
}
}
+void QQmlObjectCreator::populateDeferredInstance(
+ QObject *outerObject, int deferredIndex, int index, QObject *instance,
+ QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding)
+{
+ doPopulateDeferred(outerObject, deferredIndex, [&]() {
+ populateInstance(index, instance, bindingTarget, valueTypeProperty, binding);
+ });
+}
+
void QQmlObjectCreator::finalizePopulateDeferred()
{
phase = ObjectsCreated;
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 0a2f1ecda9..0e73feeac4 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -120,6 +120,10 @@ public:
void beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &context);
void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding);
+ void populateDeferredInstance(QObject *outerObject, int deferredIndex,
+ int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding = nullptr);
void finalizePopulateDeferred();
bool finalize(QQmlInstantiationInterrupt &interrupt);
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 8bfe9d4c4e..cdca6e89d4 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -3,28 +3,29 @@
#include "qqmlbind_p.h"
-#include <private/qqmlnullablevalue_p.h>
-#include <private/qqmlproperty_p.h>
+#include <private/qqmlanybinding_p.h>
#include <private/qqmlbinding_p.h>
+#include <private/qqmlcomponent_p.h>
#include <private/qqmlmetatype_p.h>
+#include <private/qqmlnullablevalue_p.h>
+#include <private/qqmlproperty_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qv4persistent_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4resolvedtypereference_p.h>
-#include <qqmlengine.h>
-#include <qqmlcontext.h>
-#include <qqmlproperty.h>
-#include <qqmlpropertymap.h>
-#include <qqmlinfo.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlproperty.h>
+#include <QtQml/qqmlpropertymap.h>
+
+#include <QtCore/private/qobject_p.h>
-#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
-#include <QtCore/qtimer.h>
+#include <QtCore/qfile.h>
#include <QtCore/qloggingcategory.h>
-#include <private/qqmlanybinding_p.h>
-#include <private/qv4qmlcontext_p.h>
-#include <private/qqmlcomponent_p.h>
-
-#include <private/qobject_p.h>
+#include <QtCore/qtimer.h>
QT_BEGIN_NAMESPACE
@@ -736,6 +737,20 @@ static QQmlAnyBinding createBinding(
return QQmlAnyBinding();
}
+static void initCreator(
+ QQmlData::DeferredData *deferredData,
+ const QQmlRefPointer<QQmlContextData> &contextData,
+ QQmlComponentPrivate::ConstructionState *immediateState)
+{
+ if (!immediateState->hasCreator()) {
+ immediateState->setCompletePending(true);
+ immediateState->initCreator(
+ deferredData->context->parent(), deferredData->compilationUnit,
+ contextData);
+ immediateState->creator()->beginPopulateDeferred(deferredData->context);
+ }
+}
+
void QQmlBindPrivate::decodeBinding(
QQmlBind *q, const QString &propertyPrefix,
QQmlData::DeferredData *deferredData,
@@ -744,12 +759,54 @@ void QQmlBindPrivate::decodeBinding(
{
const QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
= deferredData->compilationUnit;
- const QString propertyName = propertyPrefix
- + compilationUnit->stringAt(binding->propertyNameIndex);
+ const QString propertySuffix = compilationUnit->stringAt(binding->propertyNameIndex);
+ const QString propertyName = propertyPrefix + propertySuffix;
switch (binding->type()) {
- case QV4::CompiledData::Binding::Type_GroupProperty:
- case QV4::CompiledData::Binding::Type_AttachedProperty: {
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ if (propertyPrefix.isEmpty()) {
+ // Top-level attached properties cannot be generalized grouped properties.
+ // Treat them as regular properties.
+ // ... unless we're not supposed to handle regular properties. Then ignore them.
+ if (!immediateState)
+ return;
+
+ Q_ASSERT(compilationUnit->stringAt(compilationUnit->objectAt(binding->value.objectIndex)
+ ->inheritedTypeNameIndex).isEmpty());
+
+ const QV4::ResolvedTypeReference *typeReference
+ = compilationUnit->resolvedType(binding->propertyNameIndex);
+ Q_ASSERT(typeReference);
+ QQmlType attachedType = typeReference->type();
+ if (!attachedType.isValid()) {
+ const QQmlTypeNameCache::Result result
+ = deferredData->context->imports()->query(propertySuffix);
+ if (!result.isValid()) {
+ qmlWarning(q).nospace()
+ << "Unknown name " << propertySuffix << ". The binding is ignored.";
+ return;
+ }
+ attachedType = result.type;
+ }
+
+ QQmlContext *context = qmlContext(q);
+ QObject *attachedObject = qmlAttachedPropertiesObject(
+ q, attachedType.attachedPropertiesFunction(
+ QQmlEnginePrivate::get(context->engine())));
+ if (!attachedObject) {
+ qmlWarning(q).nospace() <<"Could not create attached properties object '"
+ << attachedType.typeName() << "'";
+ return;
+ }
+
+ initCreator(deferredData, QQmlContextData::get(context), immediateState);
+ immediateState->creator()->populateDeferredInstance(
+ q, deferredData->deferredIdx, binding->value.objectIndex, attachedObject,
+ attachedObject, /*value type property*/ nullptr, binding);
+ return;
+ }
+ Q_FALLTHROUGH();
+ case QV4::CompiledData::Binding::Type_GroupProperty: {
const QString pre = propertyName + u'.';
const QV4::CompiledData::Object *subObj
= compilationUnit->objectAt(binding->value.objectIndex);
@@ -776,13 +833,7 @@ void QQmlBindPrivate::decodeBinding(
QQmlProperty property = QQmlPropertyPrivate::create(
q, propertyName, contextData, QQmlPropertyPrivate::InitFlag::AllowSignal);
if (property.isValid()) {
- if (!immediateState->hasCreator()) {
- immediateState->setCompletePending(true);
- immediateState->initCreator(
- deferredData->context->parent(), deferredData->compilationUnit,
- contextData);
- immediateState->creator()->beginPopulateDeferred(deferredData->context);
- }
+ initCreator(deferredData, contextData, immediateState);
immediateState->creator()->populateDeferredBinding(
property, deferredData->deferredIdx, binding);
} else {
diff --git a/tests/auto/qml/qqmlbinding/data/propertiesAttachedToBindingItself.qml b/tests/auto/qml/qqmlbinding/data/propertiesAttachedToBindingItself.qml
new file mode 100644
index 0000000000..98b3aa6606
--- /dev/null
+++ b/tests/auto/qml/qqmlbinding/data/propertiesAttachedToBindingItself.qml
@@ -0,0 +1,18 @@
+import QtQml.Models
+import QtQuick
+
+Instantiator {
+ id: inst
+ model: 1
+ property int check: 0
+
+ delegate: Binding {
+ ListView.delayRemove: true
+ Component.onCompleted: inst.check += 1
+ }
+
+ Component.onCompleted: {
+ if (inst.objectAt(0))
+ inst.check += 2
+ }
+}
diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
index 237a92f070..fbb805d86a 100644
--- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
+++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
@@ -39,6 +39,7 @@ private slots:
void generalizedGroupedProperties();
void localSignalHandler();
void whenEvaluatedEarlyEnough();
+ void propertiesAttachedToBindingItself();
private:
QQmlEngine engine;
@@ -616,6 +617,18 @@ void tst_qqmlbinding::whenEvaluatedEarlyEnough()
root->setProperty("forceEnable", true);
}
+void tst_qqmlbinding::propertiesAttachedToBindingItself()
+{
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("propertiesAttachedToBindingItself.qml"));
+ QTest::failOnWarning(QRegularExpression(".*"));
+ std::unique_ptr<QObject> root { c.create() };
+ QVERIFY2(root, qPrintable(c.errorString()));
+ // 0 => everything broken; 1 => normal attached properties broken;
+ // 2 => Component.onCompleted broken, 3 => everything works
+ QTRY_COMPARE(root->property("check").toInt(), 3);
+}
+
QTEST_MAIN(tst_qqmlbinding)
#include "tst_qqmlbinding.moc"