QML: Before processing deep aliases, remove pending bindings
We may have additional bindings scheduled for the deep alias, but those are to be overridden by the alias. They should therefore be removed like bindings to target properties of shallow aliases. For QProperty bindings we have to apply a separate trick and set and clear the binding bit in the right places. We don't have access to the actual binding when writing the value, after all. Pick-to: 6.2 Fixes: QTBUG-115579 Change-Id: Ia915e59905d7e3185a17c5b6613926264ad9bc6b Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit0fdf9042ce
) (cherry picked from commitc07f63d064
) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
dc4bd4fb3f
commit
11045230c3
|
@ -913,10 +913,13 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
|
|||
&& !(bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
|
||||
&& !_valueTypeProperty;
|
||||
|
||||
if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && allowedToRemoveBinding) {
|
||||
QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
|
||||
} else if (bindingProperty->isBindable() && allowedToRemoveBinding) {
|
||||
removePendingBinding(_bindingTarget, bindingProperty->coreIndex());
|
||||
if (allowedToRemoveBinding) {
|
||||
if (bindingProperty->isBindable()) {
|
||||
removePendingBinding(_bindingTarget, bindingProperty->coreIndex());
|
||||
} else {
|
||||
QQmlPropertyPrivate::removeBinding(
|
||||
_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
if (bindingType == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
|
||||
|
@ -962,6 +965,9 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
|
|||
qmlBinding = QQmlPropertyBinding::create(bindingProperty, runtimeFunction, _scopeObject, context, currentQmlContext(), _bindingTarget, index);
|
||||
}
|
||||
sharedState.data()->allQPropertyBindings.push_back(DeferredQPropertyBinding {_bindingTarget, bindingProperty->coreIndex(), qmlBinding });
|
||||
|
||||
QQmlData *data = QQmlData::get(_bindingTarget, true);
|
||||
data->setBindingBit(_bindingTarget, bindingProperty->coreIndex());
|
||||
} else {
|
||||
// When writing bindings to grouped properties implemented as value types,
|
||||
// such as point.x: { someExpression; }, then the binding is installed on
|
||||
|
@ -1458,6 +1464,14 @@ bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
|
|||
|
||||
while (!sharedState->allQPropertyBindings.isEmpty()) {
|
||||
auto& [target, index, qmlBinding] = sharedState->allQPropertyBindings.first();
|
||||
|
||||
QQmlData *data = QQmlData::get(target);
|
||||
if (!data || !data->hasBindingBit(index)) {
|
||||
// The target property has been overwritten since we stashed the binding.
|
||||
sharedState->allQPropertyBindings.pop_front();
|
||||
continue;
|
||||
}
|
||||
|
||||
QUntypedBindable bindable;
|
||||
void *argv[] = { &bindable };
|
||||
// allow interception
|
||||
|
|
|
@ -1031,15 +1031,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
|
|||
int coreIndex = encodedIndex.coreIndex();
|
||||
const int valueTypePropertyIndex = encodedIndex.valueTypeIndex();
|
||||
|
||||
// Remove binding (if any) on write
|
||||
if(c == QMetaObject::WriteProperty) {
|
||||
int flags = *reinterpret_cast<int*>(a[3]);
|
||||
if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) {
|
||||
QQmlData *targetData = QQmlData::get(target);
|
||||
if (targetData && targetData->hasBindingBit(coreIndex))
|
||||
QQmlPropertyPrivate::removeBinding(target, encodedIndex);
|
||||
const auto removePendingBinding
|
||||
= [c, a](QObject *target, int coreIndex, QQmlPropertyIndex encodedIndex) {
|
||||
// Remove binding (if any) on write
|
||||
if (c == QMetaObject::WriteProperty) {
|
||||
int flags = *reinterpret_cast<int*>(a[3]);
|
||||
if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) {
|
||||
QQmlData *targetData = QQmlData::get(target);
|
||||
if (targetData && targetData->hasBindingBit(coreIndex)) {
|
||||
QQmlPropertyPrivate::removeBinding(target, encodedIndex);
|
||||
targetData->clearBindingBit(coreIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (valueTypePropertyIndex != -1) {
|
||||
if (!targetDData->propertyCache)
|
||||
|
@ -1049,6 +1054,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
|
|||
QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(
|
||||
ctxt->engine(), pd->propType());
|
||||
if (valueType) {
|
||||
removePendingBinding(target, coreIndex, encodedIndex);
|
||||
valueType->read(target, coreIndex);
|
||||
int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
|
||||
|
||||
|
@ -1061,10 +1067,14 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
|
|||
// deep alias
|
||||
void *argv[1] = { &target };
|
||||
QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
|
||||
removePendingBinding(
|
||||
target, valueTypePropertyIndex,
|
||||
QQmlPropertyIndex(valueTypePropertyIndex));
|
||||
return QMetaObject::metacall(target, c, valueTypePropertyIndex, a);
|
||||
}
|
||||
|
||||
} else {
|
||||
removePendingBinding(target, coreIndex, encodedIndex);
|
||||
return QMetaObject::metacall(target, c, coreIndex, a);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import QtQml
|
|||
|
||||
QtObject {
|
||||
id: root
|
||||
objectName: "theRoot"
|
||||
|
||||
component ObjectWithColor: QtObject {
|
||||
property string color
|
||||
|
@ -10,12 +11,14 @@ QtObject {
|
|||
|
||||
property ObjectWithColor border: ObjectWithColor {
|
||||
id: border
|
||||
objectName: root.objectName
|
||||
color: root.trueBorderColor
|
||||
varvar: root.trueBorderVarvar
|
||||
}
|
||||
|
||||
readonly property rect readonlyRect: ({x: 12, y: 13, width: 14, height: 15})
|
||||
|
||||
property alias borderObjectName: border.objectName
|
||||
property alias borderColor: border.color
|
||||
property alias borderVarvar: border.varvar
|
||||
property alias readonlyRectX: root.readonlyRect.x
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import QtQml
|
||||
|
||||
DeepAliasOnIC {
|
||||
borderObjectName: "theLeaf"
|
||||
borderColor: "black"
|
||||
borderVarvar: "mauve"
|
||||
}
|
||||
|
|
|
@ -8125,15 +8125,11 @@ void tst_qqmllanguage::deepAliasOnICOrReadonly()
|
|||
QScopedPointer<QObject> o(c.create());
|
||||
QVERIFY(!o.isNull());
|
||||
|
||||
// We are mostly testing that it doesn't crash here. The actual bug is fixed separately.
|
||||
|
||||
QEXPECT_FAIL("", "QTBUG-115579 is not fixed yet", Continue);
|
||||
QCOMPARE(o->property("borderColor").toString(), QLatin1String("black"));
|
||||
QCOMPARE(o->property("borderObjectName").toString(), QLatin1String("theLeaf"));
|
||||
|
||||
const QVariant var = o->property("borderVarvar");
|
||||
QEXPECT_FAIL("", "QTBUG-115579 is not fixed yet", Continue);
|
||||
QCOMPARE(var.metaType(), QMetaType::fromType<QString>());
|
||||
QEXPECT_FAIL("", "QTBUG-115579 is not fixed yet", Continue);
|
||||
QCOMPARE(var.toString(), QLatin1String("mauve"));
|
||||
|
||||
QQmlComponent c2(&engine, testFileUrl("deepAliasOnReadonly.qml"));
|
||||
|
|
Loading…
Reference in New Issue