diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2024-01-29 16:40:58 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-01-30 17:14:09 +0100 |
commit | 7ce3ce41b8cc657d31ee28de73d2962a149cd776 (patch) | |
tree | 30ef7efe143de2e597c4cb6bff1bc1ea51e13875 | |
parent | db8ae307ad452cef64443eee1ff4b82f957e169c (diff) |
QtQuick: Do not crash on broken states
States can be nullptr these days. Ideally we'd warn about this, but for
picking back to 6.5 it's enough to restore the pre-6.5.3 behavior and
not crash.
Amends commit f905876d6c3abda34dfd85cd40e300a31c1ebe52.
Pick-to: 6.7 6.6 6.5
Fixes: QTBUG-120301
Change-Id: I87021eb2dcbe7fc49f37c5d949d79466ae341a1c
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r-- | src/quick/util/qquickstategroup.cpp | 38 | ||||
-rw-r--r-- | tests/auto/quick/qquickstates/data/broken.qml | 5 | ||||
-rw-r--r-- | tests/auto/quick/qquickstates/tst_qquickstates.cpp | 16 |
3 files changed, 44 insertions, 15 deletions
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp index 9a469b8112..a111d4b543 100644 --- a/src/quick/util/qquickstategroup.cpp +++ b/src/quick/util/qquickstategroup.cpp @@ -181,19 +181,25 @@ void QQuickStateGroupPrivate::replace_states(QQmlListProperty<QQuickState> *list if (oldState != state) { if (oldState) oldState->setStateGroup(nullptr); - state->setStateGroup(self); + + if (state) + state->setStateGroup(self); d->states.replace(index, state); if (!oldState || d->currentState == oldState->name()) - d->setCurrentStateInternal(state->name(), true); + d->setCurrentStateInternal(state ? state->name() : QString(), true); } } void QQuickStateGroupPrivate::removeLast_states(QQmlListProperty<QQuickState> *list) { auto *d = static_cast<QQuickStateGroup *>(list->object)->d_func(); - if (d->currentState == d->states.last()->name()) - d->setCurrentStateInternal(d->states.size() > 1 ? d->states.first()->name() : QString(), true); - d->states.last()->setStateGroup(nullptr); + if (QQuickState *last = d->states.last()) { + if (d->currentState == last->name()) { + QQuickState *first = d->states.size() > 1 ? d->states.first() : nullptr; + d->setCurrentStateInternal(first ? first->name() : QString(), true); + } + last->setStateGroup(nullptr); + } d->states.removeLast(); } @@ -304,6 +310,9 @@ void QQuickStateGroup::componentComplete() names.reserve(d->states.size()); for (int ii = 0; ii < d->states.size(); ++ii) { QQuickState *state = d->states.at(ii); + if (!state) + continue; + if (!state->isNamed()) state->setName(QLatin1String("anonymousState") + QString::number(++d->unnamedCount)); @@ -342,7 +351,7 @@ bool QQuickStateGroupPrivate::updateAutoState() bool revert = false; for (int ii = 0; ii < states.size(); ++ii) { QQuickState *state = states.at(ii); - if (state->isWhenKnown()) { + if (state && state->isWhenKnown()) { if (state->isNamed()) { bool whenValue = state->when(); const QQmlPropertyIndex whenIndex(state->metaObject()->indexOfProperty("when")); @@ -477,9 +486,9 @@ void QQuickStateGroupPrivate::setCurrentStateInternal(const QString &state, QQuickState *oldState = nullptr; if (!currentState.isEmpty()) { - for (int ii = 0; ii < states.size(); ++ii) { - if (states.at(ii)->name() == currentState) { - oldState = states.at(ii); + for (QQuickState *state : std::as_const(states)) { + if (state && state->name() == currentState) { + oldState = state; break; } } @@ -489,9 +498,9 @@ void QQuickStateGroupPrivate::setCurrentStateInternal(const QString &state, emit q->stateChanged(currentState); QQuickState *newState = nullptr; - for (int ii = 0; ii < states.size(); ++ii) { - if (states.at(ii)->name() == currentState) { - newState = states.at(ii); + for (QQuickState *state : std::as_const(states)) { + if (state && state->name() == currentState) { + newState = state; break; } } @@ -513,9 +522,8 @@ void QQuickStateGroupPrivate::setCurrentStateInternal(const QString &state, QQuickState *QQuickStateGroup::findState(const QString &name) const { Q_D(const QQuickStateGroup); - for (int i = 0; i < d->states.size(); ++i) { - QQuickState *state = d->states.at(i); - if (state->name() == name) + for (QQuickState *state : std::as_const(d->states)) { + if (state && state->name() == name) return state; } diff --git a/tests/auto/quick/qquickstates/data/broken.qml b/tests/auto/quick/qquickstates/data/broken.qml new file mode 100644 index 0000000000..8813c8bb39 --- /dev/null +++ b/tests/auto/quick/qquickstates/data/broken.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + states: ["test"] +} diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 8d010595b5..be1361e4ab 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -191,6 +191,7 @@ private slots: void rewindAnchorChange(); void rewindAnchorChangeSize(); void bindingProperlyRemovedWithTransition(); + void doNotCrashOnBroken(); }; void tst_qquickstates::initTestCase() @@ -2036,6 +2037,21 @@ void tst_qquickstates::bindingProperlyRemovedWithTransition() QTRY_COMPARE(item->width(), 100); } +void tst_qquickstates::doNotCrashOnBroken() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("broken.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> root(c.create()); + QVERIFY(root); + QQuickItem *item = qobject_cast<QQuickItem *>(root.get()); + QVERIFY(item); + + QQmlListReference states(item, "states"); + QCOMPARE(states.size(), 1); + QCOMPARE(states.at(0), nullptr); +} + QTEST_MAIN(tst_qquickstates) #include "tst_qquickstates.moc" |