From e26fee092b175c242537839c5e7e6b1bf930cd21 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 25 Aug 2023 14:10:10 +0200 Subject: [PATCH] AutoTest: Allow temporarily disabling of functionality Especially when touching headers included centrally while refactoring bigger projects the retriggered parsing of large (depending) parts of the project can become rather annoying. Adds an action for immediate disabling parsing and respectively other test related functions. Change-Id: I553615cce90bc88d636a4519718887306ee5215b Reviewed-by: David Schulz --- src/plugins/autotest/autotestconstants.h | 1 + src/plugins/autotest/autotestplugin.cpp | 43 ++++++++++++++++--- src/plugins/autotest/testcodeparser.cpp | 25 ++++++++--- src/plugins/autotest/testcodeparser.h | 5 ++- src/plugins/autotest/testnavigationwidget.cpp | 4 +- 5 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/plugins/autotest/autotestconstants.h b/src/plugins/autotest/autotestconstants.h index 007e81b00ee..0610216bbda 100644 --- a/src/plugins/autotest/autotestconstants.h +++ b/src/plugins/autotest/autotestconstants.h @@ -8,6 +8,7 @@ namespace Autotest { namespace Constants { +const char ACTION_DISABLE_TMP[] = "AutoTest.DisableTemp"; const char ACTION_SCAN_ID[] = "AutoTest.ScanAction"; const char ACTION_RUN_ALL_ID[] = "AutoTest.RunAll"; const char ACTION_RUN_ALL_NODEPLOY_ID[] = "AutoTest.RunAllNoDeploy"; diff --git a/src/plugins/autotest/autotestplugin.cpp b/src/plugins/autotest/autotestplugin.cpp index b3fccb48d20..edfac7559a4 100644 --- a/src/plugins/autotest/autotestplugin.cpp +++ b/src/plugins/autotest/autotestplugin.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -93,6 +94,7 @@ public: void onRunFailedTriggered(); void onRunFileTriggered(); void onRunUnderCursorTriggered(TestRunMode mode); + void onDisableTemporarily(bool disable); TestSettingsPage m_testSettingPage; @@ -254,12 +256,25 @@ void AutotestPluginPrivate::initializeMenuEntries() action->setEnabled(false); menu->addAction(command); + action = new QAction(Tr::tr("Disable Temporarily"), this); + action->setToolTip(Tr::tr("Disable scanning and other actions until explicitly rescanning, " + "re-enabling, or restarting Qt Creator.")); + action->setCheckable(true); + command = ActionManager::registerAction(action, Constants::ACTION_DISABLE_TMP); + connect(action, &QAction::triggered, this, &AutotestPluginPrivate::onDisableTemporarily); + menu->addAction(command); + action = new QAction(Tr::tr("Re&scan Tests"), this); command = ActionManager::registerAction(action, Constants::ACTION_SCAN_ID); command->setDefaultKeySequence( QKeySequence(useMacShortcuts ? Tr::tr("Ctrl+Meta+T, Ctrl+Meta+S") : Tr::tr("Alt+Shift+T,Alt+S"))); - connect(action, &QAction::triggered, this, [] { dd->m_testCodeParser.updateTestTree(); }); + connect(action, &QAction::triggered, this, [] { + if (dd->m_testCodeParser.state() == TestCodeParser::DisabledTemporarily) + dd->onDisableTemporarily(false); // Rescan Test should explicitly re-enable + else + dd->m_testCodeParser.updateTestTree(); + }); menu->addAction(command); ActionContainer *toolsMenu = ActionManager::actionContainer(Core::Constants::M_TOOLS); @@ -333,7 +348,7 @@ void AutotestPlugin::extensionsInitialized() ExtensionSystem::IPlugin::ShutdownFlag AutotestPlugin::aboutToShutdown() { - dd->m_testCodeParser.aboutToShutdown(); + dd->m_testCodeParser.aboutToShutdown(true); dd->m_testTreeModel.disconnect(); return SynchronousShutdown; } @@ -467,6 +482,23 @@ void AutotestPluginPrivate::onRunUnderCursorTriggered(TestRunMode mode) m_testRunner.runTests(mode, testsToRun); } +void AutotestPluginPrivate::onDisableTemporarily(bool disable) +{ + if (disable) { + // cancel running parse + m_testCodeParser.aboutToShutdown(false); + // clear model + m_testTreeModel.removeAllTestItems(); + m_testTreeModel.removeAllTestToolItems(); + AutotestPlugin::updateMenuItemsEnabledState(); + } else { + // re-enable + m_testCodeParser.setState(TestCodeParser::Idle); + // trigger scan + m_testCodeParser.updateTestTree(); + } +} + TestFrameworks AutotestPlugin::activeTestFrameworks() { ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); @@ -489,11 +521,12 @@ void AutotestPlugin::updateMenuItemsEnabledState() { const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); const ProjectExplorer::Target *target = project ? project->activeTarget() : nullptr; - const bool canScan = !dd->m_testRunner.isTestRunning() - && dd->m_testCodeParser.state() == TestCodeParser::Idle; + const bool disabled = dd->m_testCodeParser.state() == TestCodeParser::DisabledTemporarily; + const bool canScan = disabled || (!dd->m_testRunner.isTestRunning() + && dd->m_testCodeParser.state() == TestCodeParser::Idle); const bool hasTests = dd->m_testTreeModel.hasTests(); // avoid expensive call to PE::canRunStartupProject() - limit to minimum necessary checks - const bool canRun = hasTests && canScan + const bool canRun = !disabled && hasTests && canScan && project && !project->needsConfiguration() && target && target->activeRunConfiguration() && !ProjectExplorer::BuildManager::isBuilding(); diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index 840ae613dc7..cfcd740f04f 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -64,6 +64,12 @@ void TestCodeParser::setState(State state) if (m_parserState == Shutdown) return; qCDebug(LOG) << "setState(" << state << "), currentState:" << m_parserState; + if (m_parserState == DisabledTemporarily && state == Idle) { + m_parserState = Idle; + qCDebug(LOG) << "Just re-enabling parser."; + return; + } + // avoid triggering parse before code model parsing has finished, but mark as dirty if (isProjectParsing() || m_codeModelParsing) { m_dirty = true; @@ -202,12 +208,15 @@ void TestCodeParser::onProjectPartsUpdated(Project *project) emitUpdateTestTree(); } -void TestCodeParser::aboutToShutdown() +void TestCodeParser::aboutToShutdown(bool isFinal) { - qCDebug(LOG) << "Disabling (immediately) - shutting down"; - m_parserState = Shutdown; + qCDebug(LOG) << "Disabling (immediately) -" + << (isFinal ? "shutting down" : "disabled temporarily"); + m_parserState = isFinal ? Shutdown : DisabledTemporarily; m_taskTree.reset(); m_futureSynchronizer.waitForFinished(); + if (!isFinal) + onFinished(false); } bool TestCodeParser::postponed(const QSet &filePaths) @@ -258,6 +267,7 @@ bool TestCodeParser::postponed(const QSet &filePaths) } return true; case Shutdown: + case DisabledTemporarily: break; } QTC_ASSERT(false, return false); // should not happen at all @@ -277,7 +287,7 @@ static void parseFileForTests(QPromise &promise, void TestCodeParser::scanForTests(const QSet &filePaths, const QList &parsers) { - if (m_parserState == Shutdown || m_testCodeParsers.isEmpty()) + if (m_parserState == Shutdown || m_parserState == DisabledTemporarily || m_testCodeParsers.isEmpty()) return; if (postponed(filePaths)) @@ -419,7 +429,8 @@ void TestCodeParser::onAllTasksFinished(Id type) m_codeModelParsing = false; // avoid illegal parser state if respective widgets became hidden while parsing - setState(Idle); + if (m_parserState != DisabledTemporarily) + setState(Idle); } void TestCodeParser::onFinished(bool success) @@ -451,6 +462,10 @@ void TestCodeParser::onFinished(bool success) case Shutdown: qCDebug(LOG) << "Shutdown complete - not emitting parsingFinished (onFinished)"; break; + case DisabledTemporarily: + qCDebug(LOG) << "Disabling complete - emitting parsingFinished"; + emit parsingFinished(); // ensure hidden progress indicator + break; default: qWarning("I should not be here... State: %d", m_parserState); break; diff --git a/src/plugins/autotest/testcodeparser.h b/src/plugins/autotest/testcodeparser.h index 2dd81d93d60..49e123ba496 100644 --- a/src/plugins/autotest/testcodeparser.h +++ b/src/plugins/autotest/testcodeparser.h @@ -31,7 +31,8 @@ public: Idle, PartialParse, FullParse, - Shutdown + Shutdown, + DisabledTemporarily }; TestCodeParser(); @@ -63,7 +64,7 @@ public: void onQmlDocumentUpdated(const QmlJS::Document::Ptr &document); void onStartupProjectChanged(ProjectExplorer::Project *project); void onProjectPartsUpdated(ProjectExplorer::Project *project); - void aboutToShutdown(); + void aboutToShutdown(bool isFinal); private: bool postponed(const QSet &fileList); diff --git a/src/plugins/autotest/testnavigationwidget.cpp b/src/plugins/autotest/testnavigationwidget.cpp index d7f26e655fa..1908af8203b 100644 --- a/src/plugins/autotest/testnavigationwidget.cpp +++ b/src/plugins/autotest/testnavigationwidget.cpp @@ -190,8 +190,8 @@ void TestNavigationWidget::contextMenuEvent(QContextMenuEvent *event) QAction *runSelectedNoDeploy = ActionManager::command(Constants::ACTION_RUN_SELECTED_NODEPLOY_ID)->action(); QAction *selectAll = new QAction(Tr::tr("Select All"), &menu); QAction *deselectAll = new QAction(Tr::tr("Deselect All"), &menu); - // TODO remove? QAction *rescan = ActionManager::command(Constants::ACTION_SCAN_ID)->action(); + QAction *disable = ActionManager::command(Constants::ACTION_DISABLE_TMP)->action(); connect(selectAll, &QAction::triggered, m_view, &TestTreeView::selectAll); connect(deselectAll, &QAction::triggered, m_view, &TestTreeView::deselectAll); @@ -216,6 +216,8 @@ void TestNavigationWidget::contextMenuEvent(QContextMenuEvent *event) menu.addAction(deselectAll); menu.addSeparator(); menu.addAction(rescan); + menu.addSeparator(); + menu.addAction(disable); menu.exec(mapToGlobal(event->pos())); }