2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2014-10-07 12:30:54 +02:00
|
|
|
|
|
|
|
|
#include "testcodeparser.h"
|
2020-10-09 13:07:55 +02:00
|
|
|
|
|
|
|
|
#include "autotestconstants.h"
|
2022-07-13 18:31:56 +02:00
|
|
|
#include "autotesttr.h"
|
2020-10-09 13:07:55 +02:00
|
|
|
#include "testtreemodel.h"
|
2014-10-07 12:30:54 +02:00
|
|
|
|
2015-02-26 16:50:39 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2015-02-13 15:44:18 +01:00
|
|
|
#include <coreplugin/progressmanager/futureprogress.h>
|
2014-12-10 09:41:23 +01:00
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
2021-08-30 10:58:08 +02:00
|
|
|
#include <cppeditor/cppeditorconstants.h>
|
|
|
|
|
#include <cppeditor/cppmodelmanager.h>
|
2015-07-27 13:54:27 +02:00
|
|
|
#include <projectexplorer/project.h>
|
2014-10-07 12:30:54 +02:00
|
|
|
#include <projectexplorer/session.h>
|
2014-11-06 16:01:06 +01:00
|
|
|
#include <qmljstools/qmljsmodelmanager.h>
|
|
|
|
|
|
2016-05-04 16:41:15 +02:00
|
|
|
#include <utils/algorithm.h>
|
2016-11-11 11:11:10 +01:00
|
|
|
#include <utils/mapreduce.h>
|
2015-02-05 16:07:45 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2016-02-15 16:26:11 +01:00
|
|
|
#include <utils/runextensions.h>
|
2014-10-28 15:57:13 +01:00
|
|
|
|
2015-02-13 15:44:18 +01:00
|
|
|
#include <QFuture>
|
|
|
|
|
#include <QFutureInterface>
|
2015-07-28 14:02:52 +02:00
|
|
|
#include <QLoggingCategory>
|
2015-02-13 15:44:18 +01:00
|
|
|
|
2014-10-07 12:30:54 +02:00
|
|
|
namespace Autotest {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2023-01-17 12:09:18 +01:00
|
|
|
Q_LOGGING_CATEGORY(LOG, "qtc.autotest.testcodeparser", QtWarningMsg)
|
|
|
|
|
|
2017-05-10 22:44:28 +03:00
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
|
2020-03-16 12:59:23 +01:00
|
|
|
TestCodeParser::TestCodeParser()
|
|
|
|
|
: m_threadPool(new QThreadPool(this))
|
2014-10-07 12:30:54 +02:00
|
|
|
{
|
2015-02-27 14:16:07 +01:00
|
|
|
// connect to ProgressManager to postpone test parsing when CppModelManager is parsing
|
2015-01-27 15:22:17 +01:00
|
|
|
auto progressManager = qobject_cast<Core::ProgressManager *>(Core::ProgressManager::instance());
|
|
|
|
|
connect(progressManager, &Core::ProgressManager::taskStarted,
|
|
|
|
|
this, &TestCodeParser::onTaskStarted);
|
|
|
|
|
connect(progressManager, &Core::ProgressManager::allTasksFinished,
|
|
|
|
|
this, &TestCodeParser::onAllTasksFinished);
|
2016-04-12 12:44:56 +02:00
|
|
|
connect(&m_futureWatcher, &QFutureWatcher<TestParseResultPtr>::started,
|
2016-02-04 14:53:56 +01:00
|
|
|
this, &TestCodeParser::parsingStarted);
|
2016-04-12 12:44:56 +02:00
|
|
|
connect(&m_futureWatcher, &QFutureWatcher<TestParseResultPtr>::finished,
|
2016-01-27 13:52:33 +01:00
|
|
|
this, &TestCodeParser::onFinished);
|
2016-04-12 12:44:56 +02:00
|
|
|
connect(&m_futureWatcher, &QFutureWatcher<TestParseResultPtr>::resultReadyAt,
|
2022-12-07 14:45:43 +01:00
|
|
|
this, [this](int index) {
|
2016-02-03 15:59:59 +01:00
|
|
|
emit testParseResultReady(m_futureWatcher.resultAt(index));
|
2016-01-27 13:52:33 +01:00
|
|
|
});
|
2016-06-20 07:03:55 +02:00
|
|
|
connect(this, &TestCodeParser::parsingFinished, this, &TestCodeParser::releaseParserInternals);
|
2016-10-24 12:51:03 +02:00
|
|
|
m_reparseTimer.setSingleShot(true);
|
|
|
|
|
connect(&m_reparseTimer, &QTimer::timeout, this, &TestCodeParser::parsePostponedFiles);
|
2017-05-16 11:15:57 +02:00
|
|
|
m_threadPool->setMaxThreadCount(std::max(QThread::idealThreadCount()/4, 1));
|
2014-10-07 12:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-12 15:48:24 +01:00
|
|
|
void TestCodeParser::setState(State state)
|
|
|
|
|
{
|
2016-12-12 09:35:49 +01:00
|
|
|
if (m_parserState == Shutdown)
|
2016-07-08 12:53:57 +02:00
|
|
|
return;
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "setState(" << state << "), currentState:" << m_parserState;
|
2015-07-27 10:44:14 +02:00
|
|
|
// avoid triggering parse before code model parsing has finished, but mark as dirty
|
|
|
|
|
if (m_codeModelParsing) {
|
|
|
|
|
m_dirty = true;
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "Not setting new state - code model parsing is running, just marking dirty";
|
2015-03-30 10:44:54 +02:00
|
|
|
return;
|
2015-07-27 10:44:14 +02:00
|
|
|
}
|
2015-04-14 15:24:31 +02:00
|
|
|
|
2016-11-08 16:00:21 +01:00
|
|
|
if ((state == Idle) && (m_parserState == PartialParse || m_parserState == FullParse)) {
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "Not setting state, parse is running";
|
2015-04-14 15:24:31 +02:00
|
|
|
return;
|
2015-07-28 14:02:52 +02:00
|
|
|
}
|
2015-04-14 15:24:31 +02:00
|
|
|
m_parserState = state;
|
|
|
|
|
|
2017-05-10 22:44:28 +03:00
|
|
|
if (m_parserState == Idle && SessionManager::startupProject()) {
|
2021-07-02 08:11:03 +02:00
|
|
|
if (m_postponedUpdateType == UpdateType::FullUpdate || m_dirty) {
|
2015-07-27 10:44:14 +02:00
|
|
|
emitUpdateTestTree();
|
2021-07-02 08:11:03 +02:00
|
|
|
} else if (m_postponedUpdateType == UpdateType::PartialUpdate) {
|
|
|
|
|
m_postponedUpdateType = UpdateType::NoUpdate;
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "calling scanForTests with postponed files (setState)";
|
2016-10-24 12:51:03 +02:00
|
|
|
if (!m_reparseTimer.isActive())
|
2019-07-04 19:00:20 +02:00
|
|
|
scanForTests(Utils::toList(m_postponedFiles));
|
2015-07-27 10:44:14 +02:00
|
|
|
}
|
2015-02-12 15:48:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-01 19:19:33 +01:00
|
|
|
void TestCodeParser::syncTestFrameworks(const QList<ITestParser *> &parsers)
|
2016-06-01 16:22:50 +02:00
|
|
|
{
|
2016-12-12 09:35:49 +01:00
|
|
|
if (m_parserState != Idle) {
|
2016-06-01 16:22:50 +02:00
|
|
|
// there's a running parse
|
2021-07-02 08:11:03 +02:00
|
|
|
m_postponedUpdateType = UpdateType::NoUpdate;
|
2016-06-01 16:22:50 +02:00
|
|
|
m_postponedFiles.clear();
|
2020-11-27 13:12:23 +01:00
|
|
|
Core::ProgressManager::cancelTasks(Constants::TASK_PARSE);
|
2016-06-01 16:22:50 +02:00
|
|
|
}
|
2021-01-01 19:19:33 +01:00
|
|
|
qCDebug(LOG) << "Setting" << parsers << "as current parsers";
|
|
|
|
|
m_testCodeParsers = parsers;
|
2016-06-01 16:22:50 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-06 15:24:16 +01:00
|
|
|
void TestCodeParser::emitUpdateTestTree(ITestParser *parser)
|
2014-12-10 09:41:23 +01:00
|
|
|
{
|
2016-12-13 14:15:30 +01:00
|
|
|
if (m_testCodeParsers.isEmpty())
|
|
|
|
|
return;
|
2019-09-06 12:16:46 +02:00
|
|
|
if (parser)
|
2021-01-01 19:19:33 +01:00
|
|
|
m_updateParsers.insert(parser);
|
2019-09-06 12:16:46 +02:00
|
|
|
else
|
|
|
|
|
m_updateParsers.clear();
|
2015-07-28 14:02:52 +02:00
|
|
|
if (m_singleShotScheduled) {
|
|
|
|
|
qCDebug(LOG) << "not scheduling another updateTestTree";
|
2015-07-27 13:54:27 +02:00
|
|
|
return;
|
2015-07-28 14:02:52 +02:00
|
|
|
}
|
2015-07-27 13:54:27 +02:00
|
|
|
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "adding singleShot";
|
2015-07-27 13:54:27 +02:00
|
|
|
m_singleShotScheduled = true;
|
2022-12-07 14:45:43 +01:00
|
|
|
QTimer::singleShot(1000, this, [this] { updateTestTree(m_updateParsers); });
|
2014-12-10 09:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-01 19:19:33 +01:00
|
|
|
void TestCodeParser::updateTestTree(const QSet<ITestParser *> &parsers)
|
2014-10-07 12:30:54 +02:00
|
|
|
{
|
2015-07-27 13:54:27 +02:00
|
|
|
m_singleShotScheduled = false;
|
2015-07-23 15:51:38 +02:00
|
|
|
if (m_codeModelParsing) {
|
2021-07-02 08:11:03 +02:00
|
|
|
m_postponedUpdateType = UpdateType::FullUpdate;
|
2015-08-04 09:01:33 +02:00
|
|
|
m_postponedFiles.clear();
|
2021-01-01 19:19:33 +01:00
|
|
|
if (parsers.isEmpty()) {
|
2019-09-06 12:16:46 +02:00
|
|
|
m_updateParsers.clear();
|
|
|
|
|
} else {
|
2021-01-01 19:19:33 +01:00
|
|
|
for (ITestParser *parser : parsers)
|
|
|
|
|
m_updateParsers.insert(parser);
|
2019-09-06 12:16:46 +02:00
|
|
|
}
|
2014-12-10 09:41:23 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-10 22:44:28 +03:00
|
|
|
if (!SessionManager::startupProject())
|
2014-10-07 12:30:54 +02:00
|
|
|
return;
|
|
|
|
|
|
2021-07-02 08:11:03 +02:00
|
|
|
m_postponedUpdateType = UpdateType::NoUpdate;
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "calling scanForTests (updateTestTree)";
|
2022-10-21 14:05:12 +02:00
|
|
|
const QList<ITestParser *> sortedParsers = Utils::sorted(Utils::toList(parsers),
|
|
|
|
|
[](const ITestParser *lhs, const ITestParser *rhs) {
|
2021-01-01 19:19:33 +01:00
|
|
|
return lhs->framework()->priority() < rhs->framework()->priority();
|
|
|
|
|
});
|
2021-05-26 15:50:03 +02:00
|
|
|
scanForTests(Utils::FilePaths(), sortedParsers);
|
2014-10-07 12:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
2016-01-27 13:52:33 +01:00
|
|
|
/****** threaded parsing stuff *******/
|
2015-12-07 10:21:50 +01:00
|
|
|
|
2021-05-26 15:50:03 +02:00
|
|
|
void TestCodeParser::onDocumentUpdated(const Utils::FilePath &fileName, bool isQmlFile)
|
2014-10-07 12:30:54 +02:00
|
|
|
{
|
2021-07-02 08:11:03 +02:00
|
|
|
if (m_codeModelParsing || m_postponedUpdateType == UpdateType::FullUpdate)
|
2016-07-15 10:18:31 +02:00
|
|
|
return;
|
|
|
|
|
|
2017-05-10 22:44:28 +03:00
|
|
|
Project *project = SessionManager::startupProject();
|
2015-01-28 13:01:07 +01:00
|
|
|
if (!project)
|
2014-10-07 12:30:54 +02:00
|
|
|
return;
|
2017-08-08 15:42:03 +02:00
|
|
|
// Quick tests: qml files aren't necessarily listed inside project files
|
2021-05-26 15:50:03 +02:00
|
|
|
if (!isQmlFile && !project->isKnownFile(fileName))
|
2014-10-28 15:57:13 +01:00
|
|
|
return;
|
2016-02-04 14:48:09 +01:00
|
|
|
|
2021-05-26 15:50:03 +02:00
|
|
|
scanForTests(Utils::FilePaths{fileName});
|
2014-11-06 16:01:06 +01:00
|
|
|
}
|
|
|
|
|
|
2016-06-27 15:47:30 +02:00
|
|
|
void TestCodeParser::onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document)
|
|
|
|
|
{
|
2022-11-21 16:48:50 +01:00
|
|
|
onDocumentUpdated(document->filePath());
|
2016-06-27 15:47:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestCodeParser::onQmlDocumentUpdated(const QmlJS::Document::Ptr &document)
|
|
|
|
|
{
|
2022-06-20 12:35:13 +02:00
|
|
|
const Utils::FilePath fileName = document->fileName();
|
2016-07-07 13:26:27 +02:00
|
|
|
if (!fileName.endsWith(".qbs"))
|
2022-06-20 12:35:13 +02:00
|
|
|
onDocumentUpdated(fileName, true);
|
2016-06-27 15:47:30 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-10 22:44:28 +03:00
|
|
|
void TestCodeParser::onStartupProjectChanged(Project *project)
|
2015-07-27 10:44:14 +02:00
|
|
|
{
|
2016-06-27 15:47:30 +02:00
|
|
|
if (m_parserState == FullParse || m_parserState == PartialParse) {
|
|
|
|
|
qCDebug(LOG) << "Canceling scanForTest (startup project changed)";
|
2020-11-27 13:12:23 +01:00
|
|
|
Core::ProgressManager::cancelTasks(Constants::TASK_PARSE);
|
2016-06-27 15:47:30 +02:00
|
|
|
}
|
2016-12-02 09:05:46 +01:00
|
|
|
emit aboutToPerformFullParse();
|
2016-06-27 15:47:30 +02:00
|
|
|
if (project)
|
2015-07-27 10:44:14 +02:00
|
|
|
emitUpdateTestTree();
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-10 22:44:28 +03:00
|
|
|
void TestCodeParser::onProjectPartsUpdated(Project *project)
|
2015-04-02 12:16:55 +02:00
|
|
|
{
|
2017-05-10 22:44:28 +03:00
|
|
|
if (project != SessionManager::startupProject())
|
2015-04-02 12:16:55 +02:00
|
|
|
return;
|
2016-12-12 09:35:49 +01:00
|
|
|
if (m_codeModelParsing)
|
2021-07-02 08:11:03 +02:00
|
|
|
m_postponedUpdateType = UpdateType::FullUpdate;
|
2015-04-16 15:07:56 +02:00
|
|
|
else
|
|
|
|
|
emitUpdateTestTree();
|
2015-04-02 12:16:55 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-08 12:53:57 +02:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 15:50:03 +02:00
|
|
|
bool TestCodeParser::postponed(const Utils::FilePaths &fileList)
|
2015-02-10 14:20:43 +01:00
|
|
|
{
|
|
|
|
|
switch (m_parserState) {
|
|
|
|
|
case Idle:
|
2016-10-24 12:51:03 +02:00
|
|
|
if (fileList.size() == 1) {
|
|
|
|
|
if (m_reparseTimerTimedOut)
|
|
|
|
|
return false;
|
|
|
|
|
switch (m_postponedFiles.size()) {
|
|
|
|
|
case 0:
|
|
|
|
|
m_postponedFiles.insert(fileList.first());
|
|
|
|
|
m_reparseTimer.setInterval(1000);
|
|
|
|
|
m_reparseTimer.start();
|
|
|
|
|
return true;
|
|
|
|
|
case 1:
|
|
|
|
|
if (m_postponedFiles.contains(fileList.first())) {
|
|
|
|
|
m_reparseTimer.start();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-01-10 16:51:58 +01:00
|
|
|
Q_FALLTHROUGH();
|
2016-10-24 12:51:03 +02:00
|
|
|
default:
|
|
|
|
|
m_postponedFiles.insert(fileList.first());
|
|
|
|
|
m_reparseTimer.stop();
|
|
|
|
|
m_reparseTimer.setInterval(0);
|
|
|
|
|
m_reparseTimerTimedOut = false;
|
|
|
|
|
m_reparseTimer.start();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-10 14:20:43 +01:00
|
|
|
return false;
|
|
|
|
|
case PartialParse:
|
2015-07-27 10:49:40 +02:00
|
|
|
case FullParse:
|
|
|
|
|
// parse is running, postponing a full parse
|
2015-02-10 14:20:43 +01:00
|
|
|
if (fileList.isEmpty()) {
|
2015-02-27 14:16:07 +01:00
|
|
|
m_postponedFiles.clear();
|
2021-07-02 08:11:03 +02:00
|
|
|
m_postponedUpdateType = UpdateType::FullUpdate;
|
2016-06-27 15:47:30 +02:00
|
|
|
qCDebug(LOG) << "Canceling scanForTest (full parse triggered while running a scan)";
|
2020-11-27 13:12:23 +01:00
|
|
|
Core::ProgressManager::cancelTasks(Constants::TASK_PARSE);
|
2015-02-10 14:20:43 +01:00
|
|
|
} else {
|
|
|
|
|
// partial parse triggered, but full parse is postponed already, ignoring this
|
2021-07-02 08:11:03 +02:00
|
|
|
if (m_postponedUpdateType == UpdateType::FullUpdate)
|
2015-02-10 14:20:43 +01:00
|
|
|
return true;
|
|
|
|
|
// partial parse triggered, postpone or add current files to already postponed partial
|
2021-05-26 15:50:03 +02:00
|
|
|
for (const Utils::FilePath &file : fileList)
|
2015-02-27 14:16:07 +01:00
|
|
|
m_postponedFiles.insert(file);
|
2021-07-02 08:11:03 +02:00
|
|
|
m_postponedUpdateType = UpdateType::PartialUpdate;
|
2015-02-10 14:20:43 +01:00
|
|
|
}
|
|
|
|
|
return true;
|
2016-07-08 12:53:57 +02:00
|
|
|
case Shutdown:
|
2015-02-19 11:19:59 +01:00
|
|
|
break;
|
2015-02-10 14:20:43 +01:00
|
|
|
}
|
|
|
|
|
QTC_ASSERT(false, return false); // should not happen at all
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-06 12:16:46 +02:00
|
|
|
static void parseFileForTests(const QList<ITestParser *> &parsers,
|
2016-11-11 11:11:10 +01:00
|
|
|
QFutureInterface<TestParseResultPtr> &futureInterface,
|
2021-05-26 15:50:03 +02:00
|
|
|
const Utils::FilePath &fileName)
|
2016-11-11 11:11:10 +01:00
|
|
|
{
|
2017-02-13 10:05:06 +01:00
|
|
|
for (ITestParser *parser : parsers) {
|
2016-11-11 11:11:10 +01:00
|
|
|
if (futureInterface.isCanceled())
|
|
|
|
|
return;
|
|
|
|
|
if (parser->processDocument(futureInterface, fileName))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-26 15:50:03 +02:00
|
|
|
void TestCodeParser::scanForTests(const Utils::FilePaths &fileList,
|
|
|
|
|
const QList<ITestParser *> &parsers)
|
2014-10-07 12:30:54 +02:00
|
|
|
{
|
2016-12-12 09:35:49 +01:00
|
|
|
if (m_parserState == Shutdown || m_testCodeParsers.isEmpty())
|
2016-11-08 16:00:21 +01:00
|
|
|
return;
|
2015-02-19 11:19:59 +01:00
|
|
|
|
2015-02-10 14:20:43 +01:00
|
|
|
if (postponed(fileList))
|
|
|
|
|
return;
|
|
|
|
|
|
2016-10-24 12:51:03 +02:00
|
|
|
m_reparseTimer.stop();
|
|
|
|
|
m_reparseTimerTimedOut = false;
|
2015-07-27 13:54:27 +02:00
|
|
|
m_postponedFiles.clear();
|
2015-02-13 15:44:18 +01:00
|
|
|
bool isFullParse = fileList.isEmpty();
|
2017-05-10 22:44:28 +03:00
|
|
|
Project *project = SessionManager::startupProject();
|
2017-01-06 07:20:25 +01:00
|
|
|
if (!project)
|
|
|
|
|
return;
|
2021-05-26 15:50:03 +02:00
|
|
|
Utils::FilePaths list;
|
2015-02-13 15:44:18 +01:00
|
|
|
if (isFullParse) {
|
2021-05-26 15:50:03 +02:00
|
|
|
list = project->files(Project::SourceFiles);
|
2016-07-28 11:16:22 +02:00
|
|
|
if (list.isEmpty()) {
|
|
|
|
|
// at least project file should be there, but might happen if parsing current project
|
|
|
|
|
// takes too long, especially when opening sessions holding multiple projects
|
|
|
|
|
qCDebug(LOG) << "File list empty (FullParse) - trying again in a sec";
|
|
|
|
|
emitUpdateTestTree();
|
2015-02-10 14:20:43 +01:00
|
|
|
return;
|
2022-10-20 15:36:28 +02:00
|
|
|
} else if (list.size() == 1 && list.first() == project->projectFilePath()) {
|
|
|
|
|
qCDebug(LOG) << "File list contains only the project file.";
|
|
|
|
|
return;
|
2016-07-28 11:16:22 +02:00
|
|
|
}
|
2022-10-20 15:36:28 +02:00
|
|
|
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "setting state to FullParse (scanForTests)";
|
2015-02-10 14:20:43 +01:00
|
|
|
m_parserState = FullParse;
|
2014-11-25 09:32:13 +01:00
|
|
|
} else {
|
|
|
|
|
list << fileList;
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "setting state to PartialParse (scanForTests)";
|
2015-02-10 14:20:43 +01:00
|
|
|
m_parserState = PartialParse;
|
2014-11-25 09:32:13 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-01 19:18:40 +01:00
|
|
|
m_parsingHasFailed = false;
|
2020-06-03 14:27:01 +02:00
|
|
|
TestTreeModel::instance()->updateCheckStateCache();
|
2016-01-27 13:52:33 +01:00
|
|
|
if (isFullParse) {
|
2016-02-23 15:56:52 +01:00
|
|
|
// remove qml files as they will be found automatically by the referencing cpp file
|
2022-12-07 14:45:43 +01:00
|
|
|
list = Utils::filtered(list, [](const Utils::FilePath &fn) {
|
2016-09-29 12:15:43 +02:00
|
|
|
return !fn.endsWith(".qml");
|
2016-02-23 15:56:52 +01:00
|
|
|
});
|
2020-03-13 13:54:33 +01:00
|
|
|
if (!parsers.isEmpty()) {
|
2021-01-01 19:19:33 +01:00
|
|
|
for (ITestParser *parser : parsers) {
|
|
|
|
|
parser->framework()->rootNode()->markForRemovalRecursively(true);
|
2020-10-19 13:56:19 +02:00
|
|
|
}
|
2019-09-06 12:16:46 +02:00
|
|
|
} else {
|
2020-10-19 13:56:19 +02:00
|
|
|
emit requestRemoveAllFrameworkItems();
|
2019-09-06 12:16:46 +02:00
|
|
|
}
|
2020-03-13 13:54:33 +01:00
|
|
|
} else if (!parsers.isEmpty()) {
|
2021-01-01 19:19:33 +01:00
|
|
|
for (ITestParser *parser: parsers) {
|
2022-10-07 14:46:06 +02:00
|
|
|
for (const Utils::FilePath &filePath : std::as_const(list))
|
2021-01-01 19:19:33 +01:00
|
|
|
parser->framework()->rootNode()->markForRemovalRecursively(filePath);
|
2019-09-06 12:16:46 +02:00
|
|
|
}
|
2016-01-27 13:52:33 +01:00
|
|
|
} else {
|
2022-10-07 14:46:06 +02:00
|
|
|
for (const Utils::FilePath &filePath : std::as_const(list))
|
2020-03-16 12:59:23 +01:00
|
|
|
emit requestRemoval(filePath);
|
2014-10-07 12:30:54 +02:00
|
|
|
}
|
2015-02-13 15:44:18 +01:00
|
|
|
|
2019-09-17 14:59:28 +02:00
|
|
|
QTC_ASSERT(!(isFullParse && list.isEmpty()), onFinished(); return);
|
2017-03-06 15:24:16 +01:00
|
|
|
|
|
|
|
|
// use only a single parser or all current active?
|
2021-01-01 19:19:33 +01:00
|
|
|
const QList<ITestParser *> codeParsers = parsers.isEmpty() ? m_testCodeParsers : parsers;
|
2016-09-27 09:34:34 +02:00
|
|
|
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "StartParsing";
|
2017-03-06 15:24:16 +01:00
|
|
|
for (ITestParser *parser : codeParsers)
|
2018-01-08 15:14:33 +01:00
|
|
|
parser->init(list, isFullParse);
|
2016-05-09 13:57:35 +02:00
|
|
|
|
2016-11-11 11:11:10 +01:00
|
|
|
QFuture<TestParseResultPtr> future = Utils::map(list,
|
2021-05-26 15:50:03 +02:00
|
|
|
[codeParsers](QFutureInterface<TestParseResultPtr> &fi, const Utils::FilePath &file) {
|
2017-03-06 15:24:16 +01:00
|
|
|
parseFileForTests(codeParsers, fi, file);
|
2016-11-11 11:11:10 +01:00
|
|
|
},
|
2016-11-14 15:26:04 +01:00
|
|
|
Utils::MapReduceOption::Unordered,
|
2017-05-16 11:15:57 +02:00
|
|
|
m_threadPool,
|
2016-11-14 15:26:04 +01:00
|
|
|
QThread::LowestPriority);
|
2016-01-27 13:52:33 +01:00
|
|
|
m_futureWatcher.setFuture(future);
|
|
|
|
|
if (list.size() > 5) {
|
2022-07-13 18:31:56 +02:00
|
|
|
Core::ProgressManager::addTask(future, Tr::tr("Scanning for Tests"),
|
2016-01-27 13:52:33 +01:00
|
|
|
Autotest::Constants::TASK_PARSE);
|
|
|
|
|
}
|
2014-10-07 12:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
2020-06-26 13:59:38 +02:00
|
|
|
void TestCodeParser::onTaskStarted(Utils::Id type)
|
2014-12-10 09:41:23 +01:00
|
|
|
{
|
2021-08-30 10:58:08 +02:00
|
|
|
if (type == CppEditor::Constants::TASK_INDEX) {
|
2015-07-23 15:51:38 +02:00
|
|
|
m_codeModelParsing = true;
|
2016-06-27 15:47:30 +02:00
|
|
|
if (m_parserState == FullParse || m_parserState == PartialParse) {
|
2021-07-02 08:11:03 +02:00
|
|
|
m_postponedUpdateType = m_parserState == FullParse
|
|
|
|
|
? UpdateType::FullUpdate : UpdateType::PartialUpdate;
|
2016-06-27 15:47:30 +02:00
|
|
|
qCDebug(LOG) << "Canceling scan for test (CppModelParsing started)";
|
2021-01-01 19:18:40 +01:00
|
|
|
m_parsingHasFailed = true;
|
2020-11-27 13:12:23 +01:00
|
|
|
Core::ProgressManager::cancelTasks(Constants::TASK_PARSE);
|
2016-06-27 15:47:30 +02:00
|
|
|
}
|
|
|
|
|
}
|
2014-12-10 09:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
2020-06-26 13:59:38 +02:00
|
|
|
void TestCodeParser::onAllTasksFinished(Utils::Id type)
|
2014-12-10 09:41:23 +01:00
|
|
|
{
|
2016-09-27 09:32:48 +02:00
|
|
|
// if we cancel parsing ensure that progress animation is canceled as well
|
2021-01-01 19:18:40 +01:00
|
|
|
if (type == Constants::TASK_PARSE && m_parsingHasFailed)
|
2016-09-27 09:32:48 +02:00
|
|
|
emit parsingFailed();
|
|
|
|
|
|
2015-02-10 14:20:43 +01:00
|
|
|
// only CPP parsing is relevant as we trigger Qml parsing internally anyway
|
2021-08-30 10:58:08 +02:00
|
|
|
if (type != CppEditor::Constants::TASK_INDEX)
|
2014-12-10 09:41:23 +01:00
|
|
|
return;
|
2015-07-23 15:51:38 +02:00
|
|
|
m_codeModelParsing = false;
|
2015-04-14 15:24:31 +02:00
|
|
|
|
2015-07-27 10:44:14 +02:00
|
|
|
// avoid illegal parser state if respective widgets became hidden while parsing
|
|
|
|
|
setState(Idle);
|
2015-02-13 15:44:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestCodeParser::onFinished()
|
|
|
|
|
{
|
2016-11-11 11:11:10 +01:00
|
|
|
if (m_futureWatcher.isCanceled())
|
2021-01-01 19:18:40 +01:00
|
|
|
m_parsingHasFailed = true;
|
2015-02-13 15:44:18 +01:00
|
|
|
switch (m_parserState) {
|
|
|
|
|
case PartialParse:
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "setting state to Idle (onFinished, PartialParse)";
|
2015-02-13 15:44:18 +01:00
|
|
|
m_parserState = Idle;
|
2016-02-04 14:58:29 +01:00
|
|
|
onPartialParsingFinished();
|
2016-09-27 09:34:34 +02:00
|
|
|
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "PartParsingFin";
|
2015-02-13 15:44:18 +01:00
|
|
|
break;
|
|
|
|
|
case FullParse:
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "setting state to Idle (onFinished, FullParse)";
|
2015-02-13 15:44:18 +01:00
|
|
|
m_parserState = Idle;
|
2021-01-01 19:18:40 +01:00
|
|
|
m_dirty = m_parsingHasFailed;
|
2021-07-02 08:11:03 +02:00
|
|
|
if (m_postponedUpdateType != UpdateType::NoUpdate || m_parsingHasFailed) {
|
2016-02-04 14:58:29 +01:00
|
|
|
onPartialParsingFinished();
|
2015-07-28 14:02:52 +02:00
|
|
|
} else {
|
|
|
|
|
qCDebug(LOG) << "emitting parsingFinished"
|
|
|
|
|
<< "(onFinished, FullParse, nothing postponed, parsing succeeded)";
|
2019-09-06 12:16:46 +02:00
|
|
|
m_updateParsers.clear();
|
2015-07-27 13:54:27 +02:00
|
|
|
emit parsingFinished();
|
2016-09-27 09:34:34 +02:00
|
|
|
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "ParsingFin";
|
2015-07-28 14:02:52 +02:00
|
|
|
}
|
2015-02-19 11:19:59 +01:00
|
|
|
m_dirty = false;
|
2015-02-13 15:44:18 +01:00
|
|
|
break;
|
2016-07-08 12:53:57 +02:00
|
|
|
case Shutdown:
|
|
|
|
|
qCDebug(LOG) << "Shutdown complete - not emitting parsingFinished (onFinished)";
|
|
|
|
|
break;
|
2015-02-13 15:44:18 +01:00
|
|
|
default:
|
2015-03-09 10:57:40 +01:00
|
|
|
qWarning("I should not be here... State: %d", m_parserState);
|
2015-02-13 15:44:18 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2014-12-10 09:41:23 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-10 14:20:43 +01:00
|
|
|
void TestCodeParser::onPartialParsingFinished()
|
|
|
|
|
{
|
2021-07-02 08:11:03 +02:00
|
|
|
const UpdateType oldType = m_postponedUpdateType;
|
|
|
|
|
m_postponedUpdateType = UpdateType::NoUpdate;
|
|
|
|
|
switch (oldType) {
|
|
|
|
|
case UpdateType::FullUpdate:
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "calling updateTestTree (onPartialParsingFinished)";
|
2019-09-06 12:16:46 +02:00
|
|
|
updateTestTree(m_updateParsers);
|
2021-07-02 08:11:03 +02:00
|
|
|
break;
|
|
|
|
|
case UpdateType::PartialUpdate:
|
2015-07-28 14:02:52 +02:00
|
|
|
qCDebug(LOG) << "calling scanForTests with postponed files (onPartialParsingFinished)";
|
2016-10-24 12:51:03 +02:00
|
|
|
if (!m_reparseTimer.isActive())
|
2019-07-04 19:00:20 +02:00
|
|
|
scanForTests(Utils::toList(m_postponedFiles));
|
2021-07-02 08:11:03 +02:00
|
|
|
break;
|
|
|
|
|
case UpdateType::NoUpdate:
|
2015-07-27 13:54:27 +02:00
|
|
|
m_dirty |= m_codeModelParsing;
|
2015-07-28 14:02:52 +02:00
|
|
|
if (m_dirty) {
|
2015-07-27 13:54:27 +02:00
|
|
|
emit parsingFailed();
|
2016-09-27 09:34:34 +02:00
|
|
|
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "ParsingFail";
|
2015-07-28 14:02:52 +02:00
|
|
|
} else if (!m_singleShotScheduled) {
|
|
|
|
|
qCDebug(LOG) << "emitting parsingFinished"
|
|
|
|
|
<< "(onPartialParsingFinished, nothing postponed, not dirty)";
|
2019-09-06 12:16:46 +02:00
|
|
|
m_updateParsers.clear();
|
2015-07-27 13:54:27 +02:00
|
|
|
emit parsingFinished();
|
2016-09-27 09:34:34 +02:00
|
|
|
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "ParsingFin";
|
2015-07-28 14:02:52 +02:00
|
|
|
} else {
|
|
|
|
|
qCDebug(LOG) << "not emitting parsingFinished"
|
|
|
|
|
<< "(on PartialParsingFinished, singleshot scheduled)";
|
|
|
|
|
}
|
2021-07-02 08:11:03 +02:00
|
|
|
break;
|
2015-02-10 14:20:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-24 12:51:03 +02:00
|
|
|
void TestCodeParser::parsePostponedFiles()
|
|
|
|
|
{
|
|
|
|
|
m_reparseTimerTimedOut = true;
|
2019-07-05 11:53:01 +02:00
|
|
|
scanForTests(Utils::toList(m_postponedFiles));
|
2016-10-24 12:51:03 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-20 07:03:55 +02:00
|
|
|
void TestCodeParser::releaseParserInternals()
|
|
|
|
|
{
|
2022-10-07 14:46:06 +02:00
|
|
|
for (ITestParser *parser : std::as_const(m_testCodeParsers))
|
2016-06-20 07:03:55 +02:00
|
|
|
parser->release();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-07 12:30:54 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Autotest
|