summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-12-08 16:03:36 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2020-12-09 12:48:36 +0100
commitddc585b7c773786045f3658d7da5425ed2f2f786 (patch)
tree9944ba0a9d6a4405310503c3741dbb21b80c94cf /src
parent55245c769b300b5ab11d56f05d86cbff80a8b508 (diff)
QProperty: Handle eager binding calling setBinding
When an eager binding triggers a setBinding call, we end up with a special kind of binding loop: setBinding() -> evaluate -> notifyObserver ^ | | / ---------------------------- We now catch set condition, and set the binding status to BindingLoop (with a distinct description). Task-number: QTBUG-87153 Task-number: QTBUG-87733 Pick-to: 6.0 Change-Id: I9f9915797d82eab820fc279baceaf89d7e5a3f4a Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/kernel/qproperty.cpp6
-rw-r--r--src/corelib/kernel/qproperty_p.h3
2 files changed, 9 insertions, 0 deletions
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index e2c5c7bff3..f4c026235a 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -250,6 +250,10 @@ QUntypedPropertyBinding QPropertyBindingData::setBinding(const QUntypedPropertyB
if (auto *existingBinding = d.bindingPtr()) {
if (existingBinding == newBinding.data())
return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
+ if (existingBinding->isEagerlyUpdating()) {
+ existingBinding->setError({QPropertyBindingError::BindingLoop, QStringLiteral("Binding set during binding evaluation!")});
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
+ }
oldBinding = QPropertyBindingPrivatePtr(existingBinding);
observer = static_cast<QPropertyBindingPrivate *>(oldBinding.data())->takeObservers();
static_cast<QPropertyBindingPrivate *>(oldBinding.data())->unlinkAndDeref();
@@ -269,9 +273,11 @@ QUntypedPropertyBinding QPropertyBindingData::setBinding(const QUntypedPropertyB
newBindingRaw->prependObserver(observer);
newBindingRaw->setStaticObserver(staticObserverCallback, guardCallback);
if (newBindingRaw->requiresEagerEvaluation()) {
+ newBindingRaw->setEagerlyUpdating(true);
auto changed = newBindingRaw->evaluateIfDirtyAndReturnTrueIfValueChanged(propertyDataPtr);
if (changed)
observer.notify(newBindingRaw, propertyDataPtr, /*alreadyKnownToHaveChanged=*/true);
+ newBindingRaw->setEagerlyUpdating(false);
}
} else if (observer) {
d.setObservers(observer.ptr);
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h
index d5feef1008..13bd40fad7 100644
--- a/src/corelib/kernel/qproperty_p.h
+++ b/src/corelib/kernel/qproperty_p.h
@@ -226,6 +226,9 @@ public:
// public because the auto-tests access it, too.
size_t dependencyObserverCount = 0;
+ bool isEagerlyUpdating() {return eagerlyUpdating;}
+ void setEagerlyUpdating(bool b) {eagerlyUpdating = b;}
+
QPropertyBindingPrivate(QMetaType metaType, const QtPrivate::BindingFunctionVTable *vtable,
const QPropertyBindingSourceLocation &location, bool isQQmlPropertyBinding=false)
: hasBindingWrapper(false)