AutoTest: Allow re-parsing with a sub-set of parsers

Avoid expanding parsing over all parsers if we trigger a
re-parse for a different parser and there is already a
re-parse postponed.

Change-Id: If74480fea2c671b32083fb7cf3f4dc4c418e6e33
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Stenger
2019-09-06 12:16:46 +02:00
parent c5f7de0a99
commit 42edcc5771
2 changed files with 45 additions and 37 deletions

View File

@@ -81,10 +81,6 @@ TestCodeParser::TestCodeParser(TestTreeModel *parent)
m_threadPool->setMaxThreadCount(std::max(QThread::idealThreadCount()/4, 1)); m_threadPool->setMaxThreadCount(std::max(QThread::idealThreadCount()/4, 1));
} }
TestCodeParser::~TestCodeParser()
{
}
void TestCodeParser::setState(State state) void TestCodeParser::setState(State state)
{ {
if (m_parserState == Shutdown) if (m_parserState == Shutdown)
@@ -138,28 +134,33 @@ void TestCodeParser::emitUpdateTestTree(ITestParser *parser)
{ {
if (m_testCodeParsers.isEmpty()) if (m_testCodeParsers.isEmpty())
return; return;
if (parser)
m_updateParsers.insert(parser->id());
else
m_updateParsers.clear();
if (m_singleShotScheduled) { if (m_singleShotScheduled) {
if (m_updateParser && parser != m_updateParser)
m_updateParser = nullptr;
qCDebug(LOG) << "not scheduling another updateTestTree"; qCDebug(LOG) << "not scheduling another updateTestTree";
return; return;
} }
qCDebug(LOG) << "adding singleShot"; qCDebug(LOG) << "adding singleShot";
m_singleShotScheduled = true; m_singleShotScheduled = true;
m_updateParser = parser; QTimer::singleShot(1000, this, [this]() { updateTestTree(m_updateParsers); });
QTimer::singleShot(1000, this, [this](){ updateTestTree(m_updateParser); });
} }
void TestCodeParser::updateTestTree(ITestParser *parser) void TestCodeParser::updateTestTree(const QSet<Core::Id> &frameworkIds)
{ {
m_singleShotScheduled = false; m_singleShotScheduled = false;
if (m_codeModelParsing) { if (m_codeModelParsing) {
m_fullUpdatePostponed = true; m_fullUpdatePostponed = true;
m_partialUpdatePostponed = false; m_partialUpdatePostponed = false;
m_postponedFiles.clear(); m_postponedFiles.clear();
if (!parser || parser != m_updateParser) if (frameworkIds.isEmpty()) {
m_updateParser = nullptr; m_updateParsers.clear();
} else {
for (const Core::Id &id : frameworkIds)
m_updateParsers.insert(id);
}
return; return;
} }
@@ -168,7 +169,12 @@ void TestCodeParser::updateTestTree(ITestParser *parser)
m_fullUpdatePostponed = false; m_fullUpdatePostponed = false;
qCDebug(LOG) << "calling scanForTests (updateTestTree)"; qCDebug(LOG) << "calling scanForTests (updateTestTree)";
scanForTests(QStringList(), parser); QList<Core::Id> sortedFrameworks = Utils::toList(frameworkIds);
Utils::sort(sortedFrameworks, [manager = TestFrameworkManager::instance()]
(const Core::Id &lhs, const Core::Id &rhs) {
return manager->priority(lhs) < manager->priority(rhs);
});
scanForTests(QStringList(), sortedFrameworks);
} }
// used internally to indicate a parse that failed due to having triggered a parse for a file that // used internally to indicate a parse that failed due to having triggered a parse for a file that
@@ -291,7 +297,7 @@ bool TestCodeParser::postponed(const QStringList &fileList)
QTC_ASSERT(false, return false); // should not happen at all QTC_ASSERT(false, return false); // should not happen at all
} }
static void parseFileForTests(const QVector<ITestParser *> &parsers, static void parseFileForTests(const QList<ITestParser *> &parsers,
QFutureInterface<TestParseResultPtr> &futureInterface, QFutureInterface<TestParseResultPtr> &futureInterface,
const QString &fileName) const QString &fileName)
{ {
@@ -303,12 +309,10 @@ static void parseFileForTests(const QVector<ITestParser *> &parsers,
} }
} }
void TestCodeParser::scanForTests(const QStringList &fileList, ITestParser *parser) void TestCodeParser::scanForTests(const QStringList &fileList, const QList<Core::Id> &parserIds)
{ {
if (m_parserState == Shutdown || m_testCodeParsers.isEmpty()) if (m_parserState == Shutdown || m_testCodeParsers.isEmpty())
return; return;
if (parser && !m_testCodeParsers.contains(parser))
return;
if (postponed(fileList)) if (postponed(fileList))
return; return;
@@ -339,20 +343,24 @@ void TestCodeParser::scanForTests(const QStringList &fileList, ITestParser *pars
} }
parsingHasFailed = false; parsingHasFailed = false;
TestFrameworkManager *manager = TestFrameworkManager::instance();
if (isFullParse) { if (isFullParse) {
// remove qml files as they will be found automatically by the referencing cpp file // remove qml files as they will be found automatically by the referencing cpp file
list = Utils::filtered(list, [] (const QString &fn) { list = Utils::filtered(list, [] (const QString &fn) {
return !fn.endsWith(".qml"); return !fn.endsWith(".qml");
}); });
if (parser) if (!parserIds.isEmpty()) {
TestFrameworkManager::instance()->rootNodeForTestFramework(parser->id())->markForRemovalRecursively(true); for (const Core::Id &id : parserIds)
else manager->rootNodeForTestFramework(id)->markForRemovalRecursively(true);
} else {
m_model->markAllForRemoval(); m_model->markAllForRemoval();
} else if (parser) { }
TestTreeItem *root = TestFrameworkManager::instance()->rootNodeForTestFramework(parser->id()); } else if (!parserIds.isEmpty()) {
for (const QString &filePath : list) for (const Core::Id &id : parserIds) {
root->markForRemovalRecursively(filePath); TestTreeItem *root = manager->rootNodeForTestFramework(id);
for (const QString &filePath : list)
root->markForRemovalRecursively(filePath);
}
} else { } else {
for (const QString &filePath : list) for (const QString &filePath : list)
m_model->markForRemoval(filePath); m_model->markForRemoval(filePath);
@@ -370,11 +378,11 @@ void TestCodeParser::scanForTests(const QStringList &fileList, ITestParser *pars
} }
// use only a single parser or all current active? // use only a single parser or all current active?
QVector<ITestParser *> codeParsers; const QList<ITestParser *> codeParsers
if (parser) = parserIds.isEmpty() ? m_testCodeParsers
codeParsers.append(parser); : Utils::transform(parserIds, [](const Core::Id &id) {
else return TestFrameworkManager::instance()->testParserForTestFramework(id);
codeParsers.append(m_testCodeParsers); });
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "StartParsing"; qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "StartParsing";
for (ITestParser *parser : codeParsers) for (ITestParser *parser : codeParsers)
parser->init(list, isFullParse); parser->init(list, isFullParse);
@@ -442,7 +450,7 @@ void TestCodeParser::onFinished()
} else { } else {
qCDebug(LOG) << "emitting parsingFinished" qCDebug(LOG) << "emitting parsingFinished"
<< "(onFinished, FullParse, nothing postponed, parsing succeeded)"; << "(onFinished, FullParse, nothing postponed, parsing succeeded)";
m_updateParser = nullptr; m_updateParsers.clear();
emit parsingFinished(); emit parsingFinished();
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "ParsingFin"; qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "ParsingFin";
} }
@@ -465,7 +473,7 @@ void TestCodeParser::onPartialParsingFinished()
if (m_fullUpdatePostponed) { if (m_fullUpdatePostponed) {
m_fullUpdatePostponed = false; m_fullUpdatePostponed = false;
qCDebug(LOG) << "calling updateTestTree (onPartialParsingFinished)"; qCDebug(LOG) << "calling updateTestTree (onPartialParsingFinished)";
updateTestTree(m_updateParser); updateTestTree(m_updateParsers);
} else if (m_partialUpdatePostponed) { } else if (m_partialUpdatePostponed) {
m_partialUpdatePostponed = false; m_partialUpdatePostponed = false;
qCDebug(LOG) << "calling scanForTests with postponed files (onPartialParsingFinished)"; qCDebug(LOG) << "calling scanForTests with postponed files (onPartialParsingFinished)";
@@ -479,7 +487,7 @@ void TestCodeParser::onPartialParsingFinished()
} else if (!m_singleShotScheduled) { } else if (!m_singleShotScheduled) {
qCDebug(LOG) << "emitting parsingFinished" qCDebug(LOG) << "emitting parsingFinished"
<< "(onPartialParsingFinished, nothing postponed, not dirty)"; << "(onPartialParsingFinished, nothing postponed, not dirty)";
m_updateParser = nullptr; m_updateParsers.clear();
emit parsingFinished(); emit parsingFinished();
qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "ParsingFin"; qCDebug(LOG) << QDateTime::currentDateTime().toString("hh:mm:ss.zzz") << "ParsingFin";
} else { } else {

View File

@@ -57,7 +57,6 @@ public:
}; };
explicit TestCodeParser(TestTreeModel *parent = nullptr); explicit TestCodeParser(TestTreeModel *parent = nullptr);
virtual ~TestCodeParser();
void setState(State state); void setState(State state);
State state() const { return m_parserState; } State state() const { return m_parserState; }
bool isParsing() const { return m_parserState == PartialParse || m_parserState == FullParse; } bool isParsing() const { return m_parserState == PartialParse || m_parserState == FullParse; }
@@ -77,7 +76,7 @@ signals:
public: public:
void emitUpdateTestTree(ITestParser *parser = nullptr); void emitUpdateTestTree(ITestParser *parser = nullptr);
void updateTestTree(ITestParser *parser = nullptr); void updateTestTree(const QSet<Core::Id> &frameworkIds = {});
void onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document); void onCppDocumentUpdated(const CPlusPlus::Document::Ptr &document);
void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document); void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document);
void onStartupProjectChanged(ProjectExplorer::Project *project); void onStartupProjectChanged(ProjectExplorer::Project *project);
@@ -86,7 +85,8 @@ public:
private: private:
bool postponed(const QStringList &fileList); bool postponed(const QStringList &fileList);
void scanForTests(const QStringList &fileList = QStringList(), ITestParser *parser = nullptr); void scanForTests(const QStringList &fileList = QStringList(),
const QList<Core::Id> &parserIds = {});
// qml files must be handled slightly different // qml files must be handled slightly different
void onDocumentUpdated(const QString &fileName, bool isQmlFile = false); void onDocumentUpdated(const QString &fileName, bool isQmlFile = false);
@@ -108,9 +108,9 @@ private:
QSet<QString> m_postponedFiles; QSet<QString> m_postponedFiles;
State m_parserState = Idle; State m_parserState = Idle;
QFutureWatcher<TestParseResultPtr> m_futureWatcher; QFutureWatcher<TestParseResultPtr> m_futureWatcher;
QVector<ITestParser *> m_testCodeParsers; // ptrs are still owned by TestFrameworkManager QList<ITestParser *> m_testCodeParsers; // ptrs are still owned by TestFrameworkManager
QTimer m_reparseTimer; QTimer m_reparseTimer;
ITestParser *m_updateParser = nullptr; QSet<Core::Id> m_updateParsers;
QThreadPool *m_threadPool = nullptr; QThreadPool *m_threadPool = nullptr;
}; };