forked from qt-creator/qt-creator
AutoTest: Cancel possible running tasks on shutdown
If tasks are running while shutting down we might end up in a crash, so cancel all tasks and handle possible invalid accesses of the current running processing. Change-Id: I69f7cac5f44390e322fa301af6d6794270c95c2a Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -154,6 +154,7 @@ void AutotestPlugin::extensionsInitialized()
|
|||||||
|
|
||||||
ExtensionSystem::IPlugin::ShutdownFlag AutotestPlugin::aboutToShutdown()
|
ExtensionSystem::IPlugin::ShutdownFlag AutotestPlugin::aboutToShutdown()
|
||||||
{
|
{
|
||||||
|
TestTreeModel::instance()->parser()->aboutToShutdown();
|
||||||
return SynchronousShutdown;
|
return SynchronousShutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -90,6 +90,8 @@ static bool handleGTest(QFutureInterface<TestParseResultPtr> futureInterface,
|
|||||||
const QList<CppTools::ProjectPart::Ptr> &ppList = modelManager->projectPart(filePath);
|
const QList<CppTools::ProjectPart::Ptr> &ppList = modelManager->projectPart(filePath);
|
||||||
if (ppList.size())
|
if (ppList.size())
|
||||||
proFile = ppList.first()->projectFile;
|
proFile = ppList.first()->projectFile;
|
||||||
|
else
|
||||||
|
return false; // happens if shutting down while parsing
|
||||||
|
|
||||||
foreach (const GTestCaseSpec &testSpec, result.keys()) {
|
foreach (const GTestCaseSpec &testSpec, result.keys()) {
|
||||||
GTestParseResult *parseResult = new GTestParseResult(id);
|
GTestParseResult *parseResult = new GTestParseResult(id);
|
||||||
|
@@ -199,7 +199,10 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
|
|||||||
parseResult->displayName = testCaseName;
|
parseResult->displayName = testCaseName;
|
||||||
parseResult->line = line;
|
parseResult->line = line;
|
||||||
parseResult->column = column;
|
parseResult->column = column;
|
||||||
parseResult->proFile = modelManager->projectPart(fileName).first()->projectFile;
|
QList<CppTools::ProjectPart::Ptr> projectParts = modelManager->projectPart(fileName);
|
||||||
|
if (projectParts.isEmpty()) // happens if shutting down while parsing
|
||||||
|
return false;
|
||||||
|
parseResult->proFile = projectParts.first()->projectFile;
|
||||||
QMap<QString, TestCodeLocationAndType>::ConstIterator it = testFunctions.begin();
|
QMap<QString, TestCodeLocationAndType>::ConstIterator it = testFunctions.begin();
|
||||||
const QMap<QString, TestCodeLocationAndType>::ConstIterator end = testFunctions.end();
|
const QMap<QString, TestCodeLocationAndType>::ConstIterator end = testFunctions.end();
|
||||||
for ( ; it != end; ++it) {
|
for ( ; it != end; ++it) {
|
||||||
|
@@ -202,7 +202,8 @@ static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterfa
|
|||||||
|
|
||||||
const QString cppFileName = document->fileName();
|
const QString cppFileName = document->fileName();
|
||||||
QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(cppFileName);
|
QList<CppTools::ProjectPart::Ptr> ppList = modelManager->projectPart(cppFileName);
|
||||||
QTC_ASSERT(!ppList.isEmpty(), return false);
|
if (ppList.isEmpty()) // happens if shutting down while parsing
|
||||||
|
return false;
|
||||||
const QString &proFile = ppList.at(0)->projectFile;
|
const QString &proFile = ppList.at(0)->projectFile;
|
||||||
|
|
||||||
const QString srcDir = quickTestSrcDir(modelManager, cppFileName);
|
const QString srcDir = quickTestSrcDir(modelManager, cppFileName);
|
||||||
|
@@ -85,6 +85,8 @@ TestCodeParser::~TestCodeParser()
|
|||||||
|
|
||||||
void TestCodeParser::setState(State state)
|
void TestCodeParser::setState(State state)
|
||||||
{
|
{
|
||||||
|
if (m_parserState == Shutdown)
|
||||||
|
return;
|
||||||
qCDebug(LOG) << "setState(" << state << "), currentState:" << m_parserState;
|
qCDebug(LOG) << "setState(" << state << "), currentState:" << m_parserState;
|
||||||
// avoid triggering parse before code model parsing has finished, but mark as dirty
|
// avoid triggering parse before code model parsing has finished, but mark as dirty
|
||||||
if (m_codeModelParsing) {
|
if (m_codeModelParsing) {
|
||||||
@@ -175,6 +177,8 @@ static bool checkDocumentForTestCode(QFutureInterface<TestParseResultPtr> &futur
|
|||||||
const QVector<ITestParser *> &parsers)
|
const QVector<ITestParser *> &parsers)
|
||||||
{
|
{
|
||||||
foreach (ITestParser *currentParser, parsers) {
|
foreach (ITestParser *currentParser, parsers) {
|
||||||
|
if (futureInterface.isCanceled())
|
||||||
|
return false;
|
||||||
if (currentParser->processDocument(futureInterface, fileName))
|
if (currentParser->processDocument(futureInterface, fileName))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -253,6 +257,17 @@ void TestCodeParser::onProjectPartsUpdated(ProjectExplorer::Project *project)
|
|||||||
emitUpdateTestTree();
|
emitUpdateTestTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestCodeParser::aboutToShutdown()
|
||||||
|
{
|
||||||
|
qCDebug(LOG) << "Disabling (immediately) - shutting down";
|
||||||
|
State oldState = m_parserState;
|
||||||
|
m_parserState = Shutdown;
|
||||||
|
if (oldState == PartialParse || oldState == FullParse) {
|
||||||
|
m_futureWatcher.cancel();
|
||||||
|
m_futureWatcher.waitForFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool TestCodeParser::postponed(const QStringList &fileList)
|
bool TestCodeParser::postponed(const QStringList &fileList)
|
||||||
{
|
{
|
||||||
switch (m_parserState) {
|
switch (m_parserState) {
|
||||||
@@ -278,6 +293,7 @@ bool TestCodeParser::postponed(const QStringList &fileList)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case Disabled:
|
case Disabled:
|
||||||
|
case Shutdown:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
QTC_ASSERT(false, return false); // should not happen at all
|
QTC_ASSERT(false, return false); // should not happen at all
|
||||||
@@ -285,7 +301,7 @@ bool TestCodeParser::postponed(const QStringList &fileList)
|
|||||||
|
|
||||||
void TestCodeParser::scanForTests(const QStringList &fileList)
|
void TestCodeParser::scanForTests(const QStringList &fileList)
|
||||||
{
|
{
|
||||||
if (m_parserState == Disabled) {
|
if (m_parserState == Disabled || m_parserState == Shutdown) {
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
if (fileList.isEmpty()) {
|
if (fileList.isEmpty()) {
|
||||||
m_fullUpdatePostponed = true;
|
m_fullUpdatePostponed = true;
|
||||||
@@ -390,6 +406,9 @@ void TestCodeParser::onFinished()
|
|||||||
qCDebug(LOG) << "emitting parsingFinished (onFinished, Disabled)";
|
qCDebug(LOG) << "emitting parsingFinished (onFinished, Disabled)";
|
||||||
emit parsingFinished();
|
emit parsingFinished();
|
||||||
break;
|
break;
|
||||||
|
case Shutdown:
|
||||||
|
qCDebug(LOG) << "Shutdown complete - not emitting parsingFinished (onFinished)";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning("I should not be here... State: %d", m_parserState);
|
qWarning("I should not be here... State: %d", m_parserState);
|
||||||
break;
|
break;
|
||||||
|
@@ -48,7 +48,8 @@ public:
|
|||||||
Idle,
|
Idle,
|
||||||
PartialParse,
|
PartialParse,
|
||||||
FullParse,
|
FullParse,
|
||||||
Disabled
|
Disabled,
|
||||||
|
Shutdown
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit TestCodeParser(TestTreeModel *parent = 0);
|
explicit TestCodeParser(TestTreeModel *parent = 0);
|
||||||
@@ -77,6 +78,7 @@ public:
|
|||||||
void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document);
|
void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document);
|
||||||
void onStartupProjectChanged(ProjectExplorer::Project *project);
|
void onStartupProjectChanged(ProjectExplorer::Project *project);
|
||||||
void onProjectPartsUpdated(ProjectExplorer::Project *project);
|
void onProjectPartsUpdated(ProjectExplorer::Project *project);
|
||||||
|
void aboutToShutdown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool postponed(const QStringList &fileList);
|
bool postponed(const QStringList &fileList);
|
||||||
|
Reference in New Issue
Block a user