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 commitf905876d6c
. 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 commit7ce3ce41b8
) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit42a1ab50c5
)
This commit is contained in:
parent
06fc186371
commit
787e794af8
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import QtQuick
|
||||
|
||||
Item {
|
||||
states: ["test"]
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue