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 f905876d6c.

Pick-to: 6.5
Fixes: QTBUG-120301
Change-Id: I87021eb2dcbe7fc49f37c5d949d79466ae341a1c
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 7ce3ce41b8)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 42a1ab50c5)
This commit is contained in:
Ulf Hermann 2024-01-29 16:40:58 +01:00 committed by Qt Cherry-pick Bot
parent 06fc186371
commit 787e794af8
3 changed files with 44 additions and 15 deletions

View File

@ -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 QQmlProperty whenProp(state, u"when"_s);
@ -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;
}

View File

@ -0,0 +1,5 @@
import QtQuick
Item {
states: ["test"]
}

View File

@ -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"