diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-12-08 16:03:36 +0100 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-12-09 12:48:36 +0100 |
commit | ddc585b7c773786045f3658d7da5425ed2f2f786 (patch) | |
tree | 9944ba0a9d6a4405310503c3741dbb21b80c94cf /src | |
parent | 55245c769b300b5ab11d56f05d86cbff80a8b508 (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.cpp | 6 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty_p.h | 3 |
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) |