diff options
| author | Fabian Kosmale <fabian.kosmale@qt.io> | 2025-10-27 13:48:49 +0100 |
|---|---|---|
| committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2025-10-28 15:17:35 +0000 |
| commit | 6bec88d1e2da15d24c5af7f80e9a62fe7feeca69 (patch) | |
| tree | 0ededc6d1c126b7b2355f0dd2ffe2f7627a6a24b | |
| parent | d97e7ebdbce7083b71a68ef6f8f3b7c1a29dcef1 (diff) | |
QQmlValueTypeWrapper: Mark as dirty if gadgetPtr goes away
In QQmlValueTypeWrapper::write, we clear the gadgetPtr if it didn't
exist before, and it was only created for write. That however leads to
an inconsistent isDirty state: The wrapper assumes it still has data
which is up-to-date, but that data is actually gone.
Avoid that issue by also marking the wrapper as dirty when the gadgetPtr
is reset in write.
Fixes: QTBUG-140414
Change-Id: Ie73b47ae49d4a26a43e2dbcc47365ae71a343109
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
(cherry picked from commit c920059cbc0098b6218e814d445eac7da345b0e0)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
| -rw-r--r-- | src/qml/qml/qqmlvaluetypewrapper.cpp | 1 | ||||
| -rw-r--r-- | tests/auto/qml/qqmlecmascript/data/valueTypeReadAfterWrite.qml | 25 | ||||
| -rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 17 |
3 files changed, 43 insertions, 0 deletions
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 10de6f85af..9349db0614 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -545,6 +545,7 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const bool destructGadgetOnExit = false; auto cleanup = qScopeGuard([&]() { if (destructGadgetOnExit) { + d()->setDirty(true); d()->metaType().destruct(d()->gadgetPtr()); d()->setGadgetPtr(nullptr); } diff --git a/tests/auto/qml/qqmlecmascript/data/valueTypeReadAfterWrite.qml b/tests/auto/qml/qqmlecmascript/data/valueTypeReadAfterWrite.qml new file mode 100644 index 0000000000..a8c05b6585 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/valueTypeReadAfterWrite.qml @@ -0,0 +1,25 @@ +import QtQuick + +Item { + id: rootRectangle + width: 500 + height: 500 + + readonly property color myBlue: "#1010FF" + readonly property color myRed: "#ff1010" + property string result: "" + + property var themes: { + "blueTheme": { + bgColor: rootRectangle.myBlue + }, + "redTheme": { + bgColor: rootRectangle.myRed + } + } + + Component.onCompleted: { + result = JSON.stringify(rootRectangle.themes) + } +} + diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 807b040f79..7995f0df58 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -103,6 +103,7 @@ private slots: void attachedProperties(); void enums(); void valueTypeFunctions(); + void valueTypeReadAfterWrite(); void constantsOverrideBindings(); void outerBindingOverridesInnerBinding(); void groupPropertyBindingOrder(); @@ -1646,6 +1647,22 @@ void tst_qqmlecmascript::valueTypeFunctions() QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5)); } +void tst_qqmlecmascript::valueTypeReadAfterWrite() +{ + QQmlEngine engine; + { + QQmlComponent testComponent(&engine); + testComponent.loadFromModule("QtQuick", "Item"); + if (!testComponent.isReady()) + QSKIP("Test requires QtQuick"); + } + QQmlComponent component(&engine, testFileUrl("valueTypeReadAfterWrite.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY2(object, qPrintable(component.errorString())); + QString result = object->property("result").toString(); + QVERIFY2(result.contains("\"b\":1"), result.toUtf8().constData()); +} + /* Tests that writing a constant to a property with a binding on it disables the binding. |
