From 0292acf06df4444086586b951dd1567506e07fa0 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 8 Dec 2020 16:03:36 +0100 Subject: 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 (cherry picked from commit ddc585b7c773786045f3658d7da5425ed2f2f786) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/kernel/qproperty.cpp | 6 ++++++ src/corelib/kernel/qproperty_p.h | 3 +++ 2 files changed, 9 insertions(+) (limited to 'src/corelib/kernel') 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(oldBinding.data())); + if (existingBinding->isEagerlyUpdating()) { + existingBinding->setError({QPropertyBindingError::BindingLoop, QStringLiteral("Binding set during binding evaluation!")}); + return QUntypedPropertyBinding(static_cast(oldBinding.data())); + } oldBinding = QPropertyBindingPrivatePtr(existingBinding); observer = static_cast(oldBinding.data())->takeObservers(); static_cast(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) -- cgit v1.2.3