diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-12-08 16:03:36 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2020-12-09 14:39:44 +0000 |
commit | 0292acf06df4444086586b951dd1567506e07fa0 (patch) | |
tree | 870aa71f12ac27624188e8af1689800ec26a5938 /src/corelib | |
parent | 2f60a68ca411d79b9a43a0a82dc25a88aabc6bff (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
Change-Id: I9f9915797d82eab820fc279baceaf89d7e5a3f4a
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
(cherry picked from commit ddc585b7c773786045f3658d7da5425ed2f2f786)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src/corelib')
-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 d2fd572b69..715e421295 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -246,6 +246,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(); @@ -265,9 +269,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 e88547569e..8cd4a9c6d0 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -208,6 +208,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) : hasBindingWrapper(false) |