diff options
author | Tamas Martinec <tamas.martinec@symbio.com> | 2021-03-25 12:06:20 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-03-26 15:25:52 +0000 |
commit | 0ea35a50f02c05a8122ce5b45602698c70efcf79 (patch) | |
tree | efecb35b9aa998356793099c28ad271cb86ea1bd | |
parent | 3ec9a4ad692734bdbb07206d23a3e607ccd89d4c (diff) |
Qt SCXML: Fix HistoryState crash
Use the initial state of the parent state as the transition of a
history state, if the parent state of the history state was not
entered before.
Task-number: QTBUG-89845
Fixes: QTBUG-76091
Change-Id: I4c8a5898406bdf2931424b3cf012e42e422431ae
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
(cherry picked from commit e868c6fa904a2b31b253c07739564fc9e7f1b76c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/scxml/qscxmlstatemachine.cpp | 12 | ||||
-rw-r--r-- | tests/auto/compiled/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/compiled/historyState.scxml | 57 | ||||
-rw-r--r-- | tests/auto/compiled/tst_compiled.cpp | 16 |
4 files changed, 84 insertions, 2 deletions
diff --git a/src/scxml/qscxmlstatemachine.cpp b/src/scxml/qscxmlstatemachine.cpp index a875a53..d90caa7 100644 --- a/src/scxml/qscxmlstatemachine.cpp +++ b/src/scxml/qscxmlstatemachine.cpp @@ -1247,7 +1247,15 @@ void QScxmlStateMachinePrivate::addDescendantStatesToEnter( addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent); } else { - const auto transitionIdx = m_stateTable->array(state.transitions)[0]; + int transitionIdx = StateTable::InvalidIndex; + if (state.transitions == StateTable::InvalidIndex) { + int parentInitialTransition = m_stateTable->state(state.parent).initialTransition; + if (parentInitialTransition == StateTable::InvalidIndex) + return; + transitionIdx = parentInitialTransition; + } else { + transitionIdx = m_stateTable->array(state.transitions)[0]; + } const auto &defaultHistoryTransition = m_stateTable->transition(transitionIdx); defaultHistoryContent->operator[](state.parent) = defaultHistoryTransition.transitionInstructions; @@ -1457,7 +1465,7 @@ void QScxmlStateMachinePrivate::getEffectiveTargetStates(OrderedSet *targets, for (int historyState : historyValueIter.value()) { targets->add(historyState); } - } else { + } else if (state.transitions != StateTable::InvalidIndex) { getEffectiveTargetStates(targets, m_stateTable->array(state.transitions)[0]); } } else { diff --git a/tests/auto/compiled/CMakeLists.txt b/tests/auto/compiled/CMakeLists.txt index 39ceb72..1a22044 100644 --- a/tests/auto/compiled/CMakeLists.txt +++ b/tests/auto/compiled/CMakeLists.txt @@ -39,6 +39,7 @@ qt6_add_statecharts(tst_compiled initialhistory.scxml connection.scxml topmachine.scxml + historyState.scxml ) #### Keys ignored in scope 1:.:.:compiled.pro:<TRUE>: diff --git a/tests/auto/compiled/historyState.scxml b/tests/auto/compiled/historyState.scxml new file mode 100644 index 0000000..c1f58ad --- /dev/null +++ b/tests/auto/compiled/historyState.scxml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" binding="early" xmlns:qt="http://www.qt.io/2015/02/scxml-ext" name="HistoryState" qt:editorversion="4.9.0"> + <state id="Off"> + <transition type="external" event="toOn" target="On"> + </transition> + <transition type="external" event="toHistory" target="History_1"> + </transition> + <onentry> + <log label="Off" expr="onentry"/> + </onentry> + <onexit> + <log label="Off" expr="onexit"/> + </onexit> + </state> + <state id="On" initial="Beta"> + <state id="Alpha"> + <transition type="external" event="toBeta" target="Beta"> + </transition> + <onentry> + <log label="Alpha" expr="onentry"/> + </onentry> + <onexit> + <log label="Alpha" expr="onexit"/> + </onexit> + </state> + <state id="Beta"> + <transition type="external" event="toDelta" target="Delta"> + </transition> + <onentry> + <log label="Beta" expr="onentry"/> + </onentry> + <onexit> + <log label="Beta" expr="onexit"/> + </onexit> + </state> + <history type="shallow" id="History_1"> + </history> + <state id="Delta"> + <transition type="external" event="toAlpha" target="Alpha"> + </transition> + <onentry> + <log label="Delta" expr="onentry"/> + </onentry> + <onexit> + <log label="Delta" expr="onexit"/> + </onexit> + </state> + <transition type="external" event="toOff" target="Off"> + </transition> + <onentry> + <log label="On" expr="onentry"/> + </onentry> + <onexit> + <log label="On" expr="onexit"/> + </onexit> + </state> +</scxml> diff --git a/tests/auto/compiled/tst_compiled.cpp b/tests/auto/compiled/tst_compiled.cpp index 3d6c071..a99688b 100644 --- a/tests/auto/compiled/tst_compiled.cpp +++ b/tests/auto/compiled/tst_compiled.cpp @@ -39,6 +39,7 @@ #include "eventnames1.h" #include "connection.h" #include "topmachine.h" +#include "historyState.h" enum { SpyWaitTime = 8000 }; @@ -56,6 +57,7 @@ private Q_SLOTS: void topMachine(); void topMachineDynamic(); void publicSignals(); + void historyState(); }; void tst_Compiled::stateNames() @@ -306,6 +308,20 @@ void tst_Compiled::publicSignals() QCOMPARE(aChanged.access(), QMetaMethod::Public); } +void tst_Compiled::historyState() +{ + HistoryState historyStateSM; + QSignalSpy stableStateSpy(&historyStateSM, SIGNAL(reachedStableState())); + historyStateSM.start(); + + stableStateSpy.wait(5000); + QCOMPARE(historyStateSM.activeStateNames(), QStringList(QLatin1String("Off"))); + + historyStateSM.submitEvent("toHistory"); + stableStateSpy.wait(5000); + QCOMPARE(historyStateSM.activeStateNames(), QStringList(QLatin1String("Beta"))); +} + QTEST_MAIN(tst_Compiled) #include "tst_compiled.moc" |