QPropertyBindingPrivate: Enable QML engine error handling

The QPropertyBindingSourceLocation is only useful for C++ bindings; for
QML bindings we store the binding location in the V4 function. As the
QML binding needs to store some additional information for error
handling, we allow that memory to be reused by putting it into a union
with an array of byte.

Moreover, we use some of the space to store a callback pointer, which
gets called when an error occurs during binding evaluation. That
callback is only called when we know that the binding actually was set
up from the QML engine, in which case a bitflag is set.

Task-number: QTBUG-87733
Change-Id: I4387a4bd59d4d1ccfe75756ce81f4608319e0490
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Fabian Kosmale 2020-12-04 10:16:54 +01:00
parent 1ee2558b23
commit c7443d2e11
2 changed files with 25 additions and 2 deletions

View File

@ -105,6 +105,8 @@ void QPropertyBindingPrivate::markDirtyAndNotifyObservers()
dirty = true;
if (eagerlyUpdating) {
error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
if (isQQmlPropertyBinding)
errorCallBack(this);
return;
}
@ -129,6 +131,8 @@ bool QPropertyBindingPrivate::evaluateIfDirtyAndReturnTrueIfValueChanged_helper(
if (updating) {
error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
if (isQQmlPropertyBinding)
errorCallBack(this);
return false;
}

View File

@ -176,6 +176,7 @@ private:
bool hasBindingWrapper:1;
// used to detect binding loops for eagerly evaluated properties
bool eagerlyUpdating:1;
bool isQQmlPropertyBinding:1;
const QtPrivate::BindingFunctionVTable *vtable;
@ -190,7 +191,24 @@ private:
QUntypedPropertyData *propertyDataPtr = nullptr;
QPropertyBindingSourceLocation location;
/* For bindings set up from C++, location stores where the binding was created in the C++ source
For QQmlPropertyBinding that information does not make sense, and the location in the QML file
is stored somewhere else. To make efficient use of the space, we instead provide a scratch space
for QQmlPropertyBinding (which stores further binding information there).
Anything stored in the union must be trivially destructible.
*/
static_assert(std::is_trivially_destructible_v<QPropertyBindingSourceLocation>);
static_assert(std::is_trivially_destructible_v<std::byte[sizeof(QPropertyBindingSourceLocation)]>);
protected:
using DeclarativeErrorCallback = void(*)(QPropertyBindingPrivate *);
union {
QPropertyBindingSourceLocation location;
struct {
std::byte declarativeExtraData[sizeof(QPropertyBindingSourceLocation) - sizeof(DeclarativeErrorCallback)];
DeclarativeErrorCallback errorCallBack;
};
};
private:
QPropertyBindingError error;
QMetaType metaType;
@ -209,9 +227,10 @@ public:
size_t dependencyObserverCount = 0;
QPropertyBindingPrivate(QMetaType metaType, const QtPrivate::BindingFunctionVTable *vtable,
const QPropertyBindingSourceLocation &location)
const QPropertyBindingSourceLocation &location, bool isQQmlPropertyBinding=false)
: hasBindingWrapper(false)
, eagerlyUpdating(false)
, isQQmlPropertyBinding(isQQmlPropertyBinding)
, vtable(vtable)
, inlineDependencyObservers() // Explicit initialization required because of union
, location(location)