aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/clangtools
diff options
context:
space:
mode:
authorJarek Kobus <[email protected]>2023-01-11 23:48:53 +0100
committerJarek Kobus <[email protected]>2023-01-12 10:11:44 +0000
commite7781e2a99bce1981ab4efab97e5df14b142238c (patch)
tree6d6f6e917c5522714e6b21e6a984d9fe374a0d6f /src/plugins/clangtools
parent1dad90ea451b763f8cf90ceb1d355206252c7255 (diff)
ClangTools: Reuse TaskTree
Reuse it in ClangToolRunControl and DocumentClangToolRunner. Get rid of ClangToolRunner and provide clangToolTask() method instead. Change-Id: I677940b325850849c5f5a60f2d320c031a4f0da0 Reviewed-by: David Schulz <[email protected]>
Diffstat (limited to 'src/plugins/clangtools')
-rw-r--r--src/plugins/clangtools/clangtoolruncontrol.cpp142
-rw-r--r--src/plugins/clangtools/clangtoolruncontrol.h24
-rw-r--r--src/plugins/clangtools/clangtoolrunner.cpp164
-rw-r--r--src/plugins/clangtools/clangtoolrunner.h36
-rw-r--r--src/plugins/clangtools/clangtoolsutils.cpp6
-rw-r--r--src/plugins/clangtools/clangtoolsutils.h1
-rw-r--r--src/plugins/clangtools/documentclangtoolrunner.cpp167
-rw-r--r--src/plugins/clangtools/documentclangtoolrunner.h9
8 files changed, 207 insertions, 342 deletions
diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp
index 7482868b3f3..ce9d1028d1c 100644
--- a/src/plugins/clangtools/clangtoolruncontrol.cpp
+++ b/src/plugins/clangtools/clangtoolruncontrol.cpp
@@ -5,40 +5,25 @@
#include "clangtool.h"
#include "clangtoolrunner.h"
-#include "clangtoolssettings.h"
#include "executableinfo.h"
-#include <debugger/analyzer/analyzerconstants.h>
+#include <coreplugin/progressmanager/taskprogress.h>
-#include <clangcodemodel/clangutils.h>
-
-#include <coreplugin/progressmanager/futureprogress.h>
-#include <coreplugin/progressmanager/progressmanager.h>
-
-#include <cppeditor/clangdiagnosticconfigsmodel.h>
-#include <cppeditor/compileroptionsbuilder.h>
#include <cppeditor/cppmodelmanager.h>
-#include <cppeditor/cppprojectfile.h>
-#include <cppeditor/projectinfo.h>
-#include <projectexplorer/abi.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/projectexplorericons.h>
-#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <utils/algorithm.h>
-#include <utils/environment.h>
-#include <utils/hostosinfo.h>
#include <utils/qtcprocess.h>
#include <utils/stringutils.h>
+#include <utils/tasktree.h>
-#include <QAction>
#include <QLoggingCategory>
using namespace CppEditor;
@@ -98,7 +83,6 @@ static QDebug operator<<(QDebug debug, const AnalyzeUnits &analyzeUnits)
return debug;
}
-
ClangToolRunWorker::ClangToolRunWorker(ClangTool *tool, RunControl *runControl,
const RunSettings &runSettings,
const CppEditor::ClangDiagnosticConfig &diagnosticConfig,
@@ -134,12 +118,7 @@ ClangToolRunWorker::ClangToolRunWorker(ClangTool *tool, RunControl *runControl,
m_toolChainType = toolChain->typeId();
}
-QList<RunnerCreator> ClangToolRunWorker::runnerCreators(const AnalyzeUnit &unit)
-{
- if (m_tool == ClangTidyTool::instance())
- return {[=] { return createRunner(ClangToolType::Tidy, unit); }};
- return {[=] { return createRunner(ClangToolType::Clazy, unit); }};
-}
+ClangToolRunWorker::~ClangToolRunWorker() = default;
void ClangToolRunWorker::start()
{
@@ -196,55 +175,42 @@ void ClangToolRunWorker::start()
qCDebug(LOG) << Q_FUNC_INFO << runControl()->commandLine().executable()
<< includeDir << clangVersion;
qCDebug(LOG) << "Files to process:" << unitsToProcess;
+ qCDebug(LOG) << "Environment:" << m_environment;
- m_runnerCreators.clear();
- for (const AnalyzeUnit &unit : std::as_const(unitsToProcess)) {
- for (const RunnerCreator &creator : runnerCreators(unit))
- m_runnerCreators << creator;
- }
- m_initialQueueSize = m_runnerCreators.count();
m_filesAnalyzed.clear();
m_filesNotAnalyzed.clear();
- // Set up progress information
- using namespace Core;
- m_progress = QFutureInterface<void>();
- FutureProgress *futureProgress
- = ProgressManager::addTask(m_progress.future(), tr("Analyzing"),
- toolName.toStdString().c_str());
- connect(futureProgress, &FutureProgress::canceled,
- this, &ClangToolRunWorker::onProgressCanceled);
- m_progress.setProgressRange(0, m_initialQueueSize);
- m_progress.reportStarted();
-
- // Start process(es)
- qCDebug(LOG) << "Environment:" << m_environment;
- m_runners.clear();
- const int parallelRuns = m_runSettings.parallelJobs();
- QTC_ASSERT(parallelRuns >= 1, reportFailure(); return);
-
- if (m_runnerCreators.isEmpty()) {
- finalize();
- return;
+ const ClangToolType tool = m_tool == ClangTidyTool::instance() ? ClangToolType::Tidy
+ : ClangToolType::Clazy;
+ using namespace Tasking;
+ QList<TaskItem> tasks{ParallelLimit(qMax(1, m_runSettings.parallelJobs()))};
+ for (const AnalyzeUnit &unit : std::as_const(unitsToProcess)) {
+ const AnalyzeInputData input{tool, m_diagnosticConfig, m_temporaryDir.path(),
+ m_environment, unit};
+ const auto setupHandler = [this, unit, tool] {
+ const QString filePath = FilePath::fromString(unit.file).toUserOutput();
+ appendMessage(tr("Analyzing \"%1\" [%2].").arg(filePath, clangToolName(tool)),
+ Utils::StdOutFormat);
+ return true;
+ };
+ const auto outputHandler = [this](const AnalyzeOutputData &output) { onDone(output); };
+ tasks.append(clangToolTask(input, setupHandler, outputHandler));
}
+ m_taskTree.reset(new TaskTree(tasks));
+ connect(m_taskTree.get(), &TaskTree::done, this, &ClangToolRunWorker::finalize);
+ connect(m_taskTree.get(), &TaskTree::errorOccurred, this, &ClangToolRunWorker::finalize);
+ auto progress = new Core::TaskProgress(m_taskTree.get());
+ progress->setDisplayName(tr("Analyzing"));
reportStarted();
m_elapsed.start();
-
- while (m_runners.size() < parallelRuns && !m_runnerCreators.isEmpty())
- analyzeNextFile();
+ m_taskTree->start();
}
void ClangToolRunWorker::stop()
{
- for (ClangToolRunner *runner : std::as_const(m_runners)) {
- QObject::disconnect(runner, nullptr, this, nullptr);
- delete runner;
- }
+ m_taskTree.reset();
m_projectFiles.clear();
- m_runners.clear();
- m_runnerCreators.clear();
- m_progress.reportFinished();
reportStopped();
@@ -253,26 +219,6 @@ void ClangToolRunWorker::stop()
appendMessage(elapsedTime, NormalMessageFormat);
}
-void ClangToolRunWorker::analyzeNextFile()
-{
- if (m_progress.isFinished())
- return; // The previous call already reported that we are finished.
-
- if (m_runnerCreators.isEmpty()) {
- if (m_runners.isEmpty())
- finalize();
- return;
- }
-
- const RunnerCreator runnerCreator = m_runnerCreators.takeFirst();
- ClangToolRunner *runner = runnerCreator();
- m_runners.insert(runner);
- if (!runner->run()) {
- reportFailure(tr("Failed to start runner \"%1\".").arg(runner->name()));
- stop();
- }
-}
-
void ClangToolRunWorker::onDone(const AnalyzeOutputData &output)
{
emit runnerFinished();
@@ -314,27 +260,10 @@ void ClangToolRunWorker::onDone(const AnalyzeOutputData &output)
}
}
-void ClangToolRunWorker::handleFinished(ClangToolRunner *runner)
-{
- m_runners.remove(runner);
- updateProgressValue();
- runner->deleteLater();
- analyzeNextFile();
-}
-
-void ClangToolRunWorker::onProgressCanceled()
-{
- m_progress.reportCanceled();
- runControl()->initiateStop();
-}
-
-void ClangToolRunWorker::updateProgressValue()
-{
- m_progress.setProgressValue(m_initialQueueSize - m_runnerCreators.size());
-}
-
void ClangToolRunWorker::finalize()
{
+ if (m_taskTree)
+ m_taskTree.release()->deleteLater();
const QString toolName = m_tool->name();
if (m_filesNotAnalyzed.size() != 0) {
appendMessage(tr("Error: Failed to analyze %n files.", nullptr, m_filesNotAnalyzed.size()),
@@ -356,23 +285,8 @@ void ClangToolRunWorker::finalize()
.arg(m_filesNotAnalyzed.size()),
Utils::NormalMessageFormat);
- m_progress.reportFinished();
runControl()->initiateStop();
}
-ClangToolRunner *ClangToolRunWorker::createRunner(ClangToolType tool, const AnalyzeUnit &unit)
-{
- auto runner = new ClangToolRunner(
- {tool, m_diagnosticConfig, m_temporaryDir.path(), m_environment, unit}, this);
- connect(runner, &ClangToolRunner::done, this, [this, runner](const AnalyzeOutputData &output) {
- onDone(output);
- handleFinished(runner);
- });
- const QString filePath = FilePath::fromString(unit.file).toUserOutput();
- appendMessage(tr("Analyzing \"%1\" [%2].").arg(filePath, runner->name()),
- Utils::StdOutFormat);
- return runner;
-}
-
} // namespace Internal
} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtoolruncontrol.h b/src/plugins/clangtools/clangtoolruncontrol.h
index 08ba1806021..63ffdf99c05 100644
--- a/src/plugins/clangtools/clangtoolruncontrol.h
+++ b/src/plugins/clangtools/clangtoolruncontrol.h
@@ -13,21 +13,17 @@
#include <utils/temporarydirectory.h>
#include <QElapsedTimer>
-#include <QFutureInterface>
#include <QSet>
-#include <QStringList>
+
+namespace Utils { class TaskTree; }
namespace ClangTools {
namespace Internal {
class AnalyzeOutputData;
-class AnalyzeUnit;
class ClangTool;
-class ClangToolRunner;
class ProjectBuilder;
-using RunnerCreator = std::function<ClangToolRunner*()>;
-
class ClangToolRunWorker : public ProjectExplorer::RunWorker
{
Q_OBJECT
@@ -39,6 +35,7 @@ public:
const CppEditor::ClangDiagnosticConfig &diagnosticConfig,
const FileInfos &fileInfos,
bool buildBeforeAnalysis);
+ ~ClangToolRunWorker();
int filesAnalyzed() const { return m_filesAnalyzed.size(); }
int filesNotAnalyzed() const { return m_filesNotAnalyzed.size(); }
@@ -53,16 +50,6 @@ private:
void start() final;
void stop() final;
void onDone(const AnalyzeOutputData &output);
-
- QList<RunnerCreator> runnerCreators(const AnalyzeUnit &unit);
- ClangToolRunner *createRunner(CppEditor::ClangToolType tool, const AnalyzeUnit &unit);
-
- void analyzeNextFile();
- void handleFinished(ClangToolRunner *runner);
-
- void onProgressCanceled();
- void updateProgressValue();
-
void finalize();
private:
@@ -80,11 +67,8 @@ private:
QString m_targetTriple;
Utils::Id m_toolChainType;
- QFutureInterface<void> m_progress;
- QList<RunnerCreator> m_runnerCreators;
+ std::unique_ptr<Utils::TaskTree> m_taskTree;
QSet<Utils::FilePath> m_projectFiles;
- QSet<ClangToolRunner *> m_runners;
- int m_initialQueueSize = 0;
QSet<QString> m_filesAnalyzed;
QSet<QString> m_filesNotAnalyzed;
diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp
index fcb310c07df..8adc889bec1 100644
--- a/src/plugins/clangtools/clangtoolrunner.cpp
+++ b/src/plugins/clangtools/clangtoolrunner.cpp
@@ -3,15 +3,14 @@
#include "clangtoolrunner.h"
+#include "clangtoolstr.h"
#include "clangtoolsutils.h"
#include <coreplugin/icore.h>
#include <cppeditor/clangdiagnosticconfigsmodel.h>
-#include <cppeditor/compileroptionsbuilder.h>
#include <cppeditor/cpptoolsreuse.h>
-#include <utils/environment.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/temporaryfile.h>
@@ -25,6 +24,7 @@ static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.runner", QtWarningMsg)
using namespace CppEditor;
using namespace Utils;
+using namespace Tasking;
namespace ClangTools {
namespace Internal {
@@ -85,30 +85,6 @@ static QStringList clangArguments(const ClangDiagnosticConfig &diagnosticConfig,
return arguments;
}
-ClangToolRunner::ClangToolRunner(const AnalyzeInputData &input, QObject *parent)
- : QObject(parent)
- , m_input(input)
-{
- m_name = input.tool == ClangToolType::Tidy ? tr("Clang-Tidy") : tr("Clazy");
- m_executable = toolExecutable(input.tool);
- QTC_CHECK(!m_input.outputDirPath.isEmpty());
-
- m_process.setEnvironment(input.environment);
- m_process.setUseCtrlCStub(true);
- m_process.setWorkingDirectory(m_input.outputDirPath); // Current clang-cl puts log file into working dir.
- connect(&m_process, &QtcProcess::done, this, &ClangToolRunner::onProcessDone);
-}
-
-QStringList ClangToolRunner::mainToolArguments() const
-{
- QStringList result;
- result << "-export-fixes=" + m_outputFilePath;
- if (!m_input.overlayFilePath.isEmpty() && isVFSOverlaySupported(m_executable))
- result << "--vfsoverlay=" + m_input.overlayFilePath;
- result << QDir::toNativeSeparators(m_input.unit.file);
- return result;
-}
-
static QString createOutputFilePath(const FilePath &dirPath, const QString &fileToAnalyze)
{
const QString fileName = QFileInfo(fileToAnalyze).fileName();
@@ -124,52 +100,98 @@ static QString createOutputFilePath(const FilePath &dirPath, const QString &file
return {};
}
-bool ClangToolRunner::run()
+TaskItem clangToolTask(const AnalyzeInputData &input,
+ const AnalyzeSetupHandler &setupHandler,
+ const AnalyzeOutputHandler &outputHandler)
{
- QTC_ASSERT(m_executable.isExecutableFile(),
- qWarning() << "Can't start:" << m_executable << "as" << m_name; return false);
- QTC_CHECK(!m_input.unit.arguments.contains(QLatin1String("-o")));
- QTC_CHECK(!m_input.unit.arguments.contains(m_input.unit.file));
- QTC_ASSERT(FilePath::fromString(m_input.unit.file).exists(), return false);
-
- m_outputFilePath = createOutputFilePath(m_input.outputDirPath, m_input.unit.file);
- QTC_ASSERT(!m_outputFilePath.isEmpty(), return false);
-
- const QStringList args = checksArguments(m_input.tool, m_input.config)
- + mainToolArguments()
- + QStringList{"--"}
- + clangArguments(m_input.config, m_input.unit.arguments);
- const CommandLine commandLine = {m_executable, args};
-
- qCDebug(LOG).noquote() << "Starting" << commandLine.toUserOutput();
- m_process.setCommand(commandLine);
- m_process.start();
- return true;
-}
-
-void ClangToolRunner::onProcessDone()
-{
- if (m_process.result() == ProcessResult::FinishedWithSuccess) {
- qCDebug(LOG).noquote() << "Output:\n" << m_process.cleanedStdOut();
- emit done({true, m_input.unit.file, m_outputFilePath, m_name});
- return;
- }
-
- const QString details = tr("Command line: %1\n"
- "Process Error: %2\n"
- "Output:\n%3")
- .arg(m_process.commandLine().toUserOutput())
- .arg(m_process.error())
- .arg(m_process.cleanedStdOut());
- QString message;
- if (m_process.result() == ProcessResult::StartFailed)
- message = tr("An error occurred with the %1 process.").arg(m_name);
- else if (m_process.result() == ProcessResult::FinishedWithError)
- message = tr("%1 finished with exit code: %2.").arg(m_name).arg(m_process.exitCode());
- else
- message = tr("%1 crashed.").arg(m_name);
-
- emit done({false, m_input.unit.file, m_outputFilePath, m_name, message, details});
+ struct ClangToolStorage {
+ QString name;
+ Utils::FilePath executable;
+ QString outputFilePath;
+ };
+ const TreeStorage<ClangToolStorage> storage;
+
+ const auto mainToolArguments = [=](const ClangToolStorage *data)
+ {
+ QStringList result;
+ result << "-export-fixes=" + data->outputFilePath;
+ if (!input.overlayFilePath.isEmpty() && isVFSOverlaySupported(data->executable))
+ result << "--vfsoverlay=" + input.overlayFilePath;
+ result << QDir::toNativeSeparators(input.unit.file);
+ return result;
+ };
+
+ const auto onGroupSetup = [=] {
+ const GroupConfig error = GroupConfig{GroupAction::StopWithError};
+ if (setupHandler && !setupHandler())
+ return error;
+
+ ClangToolStorage *data = storage.activeStorage();
+ data->name = clangToolName(input.tool);
+ data->executable = toolExecutable(input.tool);
+ if (!data->executable.isExecutableFile()) {
+ qWarning() << "Can't start:" << data->executable << "as" << data->name;
+ return error;
+ }
+
+ QTC_CHECK(!input.unit.arguments.contains(QLatin1String("-o")));
+ QTC_CHECK(!input.unit.arguments.contains(input.unit.file));
+ QTC_ASSERT(FilePath::fromString(input.unit.file).exists(), return error);
+ data->outputFilePath = createOutputFilePath(input.outputDirPath, input.unit.file);
+ QTC_ASSERT(!data->outputFilePath.isEmpty(), return error);
+
+ return GroupConfig{GroupAction::ContinueAll};
+ };
+ const auto onProcessSetup = [=](QtcProcess &process) {
+ process.setEnvironment(input.environment);
+ process.setUseCtrlCStub(true);
+ process.setWorkingDirectory(input.outputDirPath); // Current clang-cl puts log file into working dir.
+
+ const ClangToolStorage *data = storage.activeStorage();
+
+ const QStringList args = checksArguments(input.tool, input.config)
+ + mainToolArguments(data)
+ + QStringList{"--"}
+ + clangArguments(input.config, input.unit.arguments);
+ const CommandLine commandLine = {data->executable, args};
+
+ qCDebug(LOG).noquote() << "Starting" << commandLine.toUserOutput();
+ process.setCommand(commandLine);
+ };
+ const auto onProcessDone = [=](const QtcProcess &process) {
+ qCDebug(LOG).noquote() << "Output:\n" << process.cleanedStdOut();
+ if (!outputHandler)
+ return;
+ const ClangToolStorage *data = storage.activeStorage();
+ outputHandler({true, input.unit.file, data->outputFilePath, data->name});
+ };
+ const auto onProcessError = [=](const QtcProcess &process) {
+ if (!outputHandler)
+ return;
+ const QString details = Tr::tr("Command line: %1\nProcess Error: %2\nOutput:\n%3")
+ .arg(process.commandLine().toUserOutput())
+ .arg(process.error())
+ .arg(process.cleanedStdOut());
+ const ClangToolStorage *data = storage.activeStorage();
+ QString message;
+ if (process.result() == ProcessResult::StartFailed)
+ message = Tr::tr("An error occurred with the %1 process.").arg(data->name);
+ else if (process.result() == ProcessResult::FinishedWithError)
+ message = Tr::tr("%1 finished with exit code: %2.").arg(data->name).arg(process.exitCode());
+ else
+ message = Tr::tr("%1 crashed.").arg(data->name);
+ outputHandler({false, input.unit.file, data->outputFilePath, data->name, message, details});
+ };
+
+ const Group group {
+ Storage(storage),
+ DynamicSetup(onGroupSetup),
+ Group {
+ optional,
+ Process(onProcessSetup, onProcessDone, onProcessError)
+ }
+ };
+ return group;
}
} // namespace Internal
diff --git a/src/plugins/clangtools/clangtoolrunner.h b/src/plugins/clangtools/clangtoolrunner.h
index 37f6bdf915a..b9afb812127 100644
--- a/src/plugins/clangtools/clangtoolrunner.h
+++ b/src/plugins/clangtools/clangtoolrunner.h
@@ -8,9 +8,8 @@
#include <cppeditor/clangdiagnosticconfig.h>
#include <utils/environment.h>
-#include <utils/qtcprocess.h>
-#include <memory>
+namespace Utils::Tasking { class TaskItem; }
namespace ClangTools {
namespace Internal {
@@ -45,35 +44,12 @@ struct AnalyzeOutputData
QString errorDetails = {};
};
-class ClangToolRunner : public QObject
-{
- Q_OBJECT
-
-public:
- ClangToolRunner(const AnalyzeInputData &input, QObject *parent = nullptr);
-
- QString name() const { return m_name; }
-
- // compilerOptions is expected to contain everything except:
- // (1) file to analyze
- // (2) -o output-file
- bool run();
-
-signals:
- void done(const AnalyzeOutputData &output);
+using AnalyzeSetupHandler = std::function<bool()>;
+using AnalyzeOutputHandler = std::function<void(const AnalyzeOutputData &)>;
-private:
- void onProcessDone();
-
- QStringList mainToolArguments() const;
-
- const AnalyzeInputData m_input;
- Utils::QtcProcess m_process;
-
- QString m_name;
- Utils::FilePath m_executable;
- QString m_outputFilePath;
-};
+Utils::Tasking::TaskItem clangToolTask(const AnalyzeInputData &input,
+ const AnalyzeSetupHandler &setupHandler,
+ const AnalyzeOutputHandler &outputHandler);
} // namespace Internal
} // namespace ClangTools
diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp
index 8ec086d6c1a..eaebc68b6a7 100644
--- a/src/plugins/clangtools/clangtoolsutils.cpp
+++ b/src/plugins/clangtools/clangtoolsutils.cpp
@@ -7,6 +7,7 @@
#include "clangtoolsconstants.h"
#include "clangtoolsdiagnostic.h"
#include "clangtoolssettings.h"
+#include "clangtoolstr.h"
#include <coreplugin/icore.h>
#include <cppeditor/cppeditorconstants.h>
@@ -200,6 +201,11 @@ FilePath toolFallbackExecutable(ClangToolType tool)
return findValidExecutable({toolShippedExecutable(tool), fallback});
}
+QString clangToolName(CppEditor::ClangToolType tool)
+{
+ return tool == ClangToolType::Tidy ? Tr::tr("Clang-Tidy") : Tr::tr("Clazy");
+}
+
bool isVFSOverlaySupported(const FilePath &executable)
{
static QMap<FilePath, bool> vfsCapabilities;
diff --git a/src/plugins/clangtools/clangtoolsutils.h b/src/plugins/clangtools/clangtoolsutils.h
index 26421f0e8eb..6f4f2871a02 100644
--- a/src/plugins/clangtools/clangtoolsutils.h
+++ b/src/plugins/clangtools/clangtoolsutils.h
@@ -46,6 +46,7 @@ void showHintAboutBuildBeforeAnalysis();
Utils::FilePath toolShippedExecutable(CppEditor::ClangToolType tool);
Utils::FilePath toolExecutable(CppEditor::ClangToolType tool);
Utils::FilePath toolFallbackExecutable(CppEditor::ClangToolType tool);
+QString clangToolName(CppEditor::ClangToolType tool);
bool isVFSOverlaySupported(const Utils::FilePath &executable);
diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp
index 488770c38be..7409ea3bea5 100644
--- a/src/plugins/clangtools/documentclangtoolrunner.cpp
+++ b/src/plugins/clangtools/documentclangtoolrunner.cpp
@@ -3,18 +3,14 @@
#include "documentclangtoolrunner.h"
-#include "clangfileinfo.h"
-#include "clangtoolruncontrol.h"
#include "clangtoolsconstants.h"
#include "clangtoolslogfilereader.h"
-#include "clangtoolsprojectsettings.h"
#include "clangtoolrunner.h"
#include "clangtoolsutils.h"
#include "diagnosticmark.h"
#include "executableinfo.h"
#include "virtualfilesystemoverlay.h"
-#include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
@@ -27,12 +23,12 @@
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
-#include <texteditor/textmark.h>
#include <utils/qtcassert.h>
-#include <utils/utilsicons.h>
+#include <utils/tasktree.h>
#include <QLoggingCategory>
+#include <QScopeGuard>
static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.cftr", QtWarningMsg)
@@ -49,31 +45,20 @@ DocumentClangToolRunner::DocumentClangToolRunner(IDocument *document)
, m_document(document)
, m_temporaryDir("clangtools-single-XXXXXX")
{
-
m_runTimer.setInterval(500);
m_runTimer.setSingleShot(true);
- connect(m_document,
- &IDocument::contentsChanged,
- this,
- &DocumentClangToolRunner::scheduleRun);
- connect(CppModelManager::instance(),
- &CppModelManager::projectPartsUpdated,
- this,
- &DocumentClangToolRunner::scheduleRun);
- connect(ClangToolsSettings::instance(),
- &ClangToolsSettings::changed,
- this,
- &DocumentClangToolRunner::scheduleRun);
+ connect(m_document, &IDocument::contentsChanged,
+ this, &DocumentClangToolRunner::scheduleRun);
+ connect(CppModelManager::instance(), &CppModelManager::projectPartsUpdated,
+ this, &DocumentClangToolRunner::scheduleRun);
+ connect(ClangToolsSettings::instance(), &ClangToolsSettings::changed,
+ this, &DocumentClangToolRunner::scheduleRun);
connect(&m_runTimer, &QTimer::timeout, this, &DocumentClangToolRunner::run);
run();
}
-DocumentClangToolRunner::~DocumentClangToolRunner()
-{
- cancel();
- qDeleteAll(m_marks);
-}
+DocumentClangToolRunner::~DocumentClangToolRunner() = default;
FilePath DocumentClangToolRunner::filePath() const
{
@@ -168,78 +153,69 @@ static Environment projectBuildEnvironment(Project *project)
void DocumentClangToolRunner::run()
{
- cancel();
+ if (m_projectSettingsUpdate)
+ disconnect(m_projectSettingsUpdate);
+ m_taskTree.reset();
+ QScopeGuard guard([this] { finalize(); });
+
auto isEditorForCurrentDocument = [this](const IEditor *editor) {
return editor->document() == m_document;
};
- if (Utils::anyOf(EditorManager::visibleEditors(), isEditorForCurrentDocument)) {
- const FilePath filePath = m_document->filePath();
- if (Project *project = findProject(filePath)) {
- m_fileInfo = getFileInfo(filePath, project);
- if (m_fileInfo.file.exists()) {
- const auto projectSettings = ClangToolsProjectSettings::getSettings(project);
-
- const RunSettings &runSettings = projectSettings->useGlobalSettings()
- ? ClangToolsSettings::instance()->runSettings()
- : projectSettings->runSettings();
-
- m_suppressed = projectSettings->suppressedDiagnostics();
- m_lastProjectDirectory = project->projectDirectory();
- m_projectSettingsUpdate = connect(projectSettings.data(),
- &ClangToolsProjectSettings::changed,
- this,
- &DocumentClangToolRunner::run);
-
- if (runSettings.analyzeOpenFiles()) {
- vfso().update();
-
- const ClangDiagnosticConfig config
- = diagnosticConfig(runSettings.diagnosticConfigId());
-
- const Environment env = projectBuildEnvironment(project);
- const auto addClangTool = [this, config, env](ClangToolType tool) {
- if (!config.isEnabled(tool))
- return;
- const FilePath executable = toolExecutable(tool);
- const auto [includeDir, clangVersion]
- = getClangIncludeDirAndVersion(executable);
- if (!executable.isExecutableFile() || includeDir.isEmpty() || clangVersion.isEmpty())
- return;
- const AnalyzeUnit unit(m_fileInfo, includeDir, clangVersion);
- m_runnerCreators << [=]() -> ClangToolRunner * {
- if (m_document->isModified() && !isVFSOverlaySupported(executable))
- return nullptr;
- auto runner = new ClangToolRunner({tool, config, m_temporaryDir.path(),
- env, unit, vfso().overlayFilePath().toString()}, this);
- connect(runner, &ClangToolRunner::done,
- this, &DocumentClangToolRunner::onDone);
- return runner;
- };
- };
- addClangTool(ClangToolType::Tidy);
- addClangTool(ClangToolType::Clazy);
- }
- }
- }
- } else {
+ if (!Utils::anyOf(EditorManager::visibleEditors(), isEditorForCurrentDocument)) {
deleteLater();
+ return;
}
+ const FilePath filePath = m_document->filePath();
+ Project *project = findProject(filePath);
+ if (!project)
+ return;
- runNext();
-}
+ m_fileInfo = getFileInfo(filePath, project);
+ if (!m_fileInfo.file.exists())
+ return;
-void DocumentClangToolRunner::runNext()
-{
- if (m_currentRunner)
- m_currentRunner.release()->deleteLater();
+ const auto projectSettings = ClangToolsProjectSettings::getSettings(project);
+ const RunSettings &runSettings = projectSettings->useGlobalSettings()
+ ? ClangToolsSettings::instance()->runSettings()
+ : projectSettings->runSettings();
+ m_suppressed = projectSettings->suppressedDiagnostics();
+ m_lastProjectDirectory = project->projectDirectory();
+ m_projectSettingsUpdate = connect(projectSettings.data(), &ClangToolsProjectSettings::changed,
+ this, &DocumentClangToolRunner::run);
+ if (!runSettings.analyzeOpenFiles())
+ return;
- if (m_runnerCreators.isEmpty()) {
- finalize();
+ vfso().update();
+ const ClangDiagnosticConfig config = diagnosticConfig(runSettings.diagnosticConfigId());
+ const Environment env = projectBuildEnvironment(project);
+ using namespace Tasking;
+ QList<TaskItem> tasks{parallel};
+ const auto addClangTool = [this, &config, &env, &tasks](ClangToolType tool) {
+ if (!config.isEnabled(tool))
+ return;
+ const FilePath executable = toolExecutable(tool);
+ const auto [includeDir, clangVersion] = getClangIncludeDirAndVersion(executable);
+ if (!executable.isExecutableFile() || includeDir.isEmpty() || clangVersion.isEmpty())
+ return;
+ const AnalyzeUnit unit(m_fileInfo, includeDir, clangVersion);
+ const AnalyzeInputData input{tool, config, m_temporaryDir.path(), env, unit,
+ vfso().overlayFilePath().toString()};
+ const auto setupHandler = [this, executable] {
+ return !m_document->isModified() || isVFSOverlaySupported(executable);
+ };
+ const auto outputHandler = [this](const AnalyzeOutputData &output) { onDone(output); };
+ tasks.append(Group{optional, clangToolTask(input, setupHandler, outputHandler)});
+ };
+ addClangTool(ClangToolType::Tidy);
+ addClangTool(ClangToolType::Clazy);
+ if (tasks.isEmpty())
return;
- }
- m_currentRunner.reset(m_runnerCreators.takeFirst()());
- if (!m_currentRunner || !m_currentRunner->run())
- runNext();
+
+ guard.dismiss();
+ m_taskTree.reset(new TaskTree(tasks));
+ connect(m_taskTree.get(), &TaskTree::done, this, &DocumentClangToolRunner::finalize);
+ connect(m_taskTree.get(), &TaskTree::errorOccurred, this, &DocumentClangToolRunner::finalize);
+ m_taskTree->start();
}
static void updateLocation(Debugger::DiagnosticLocation &location)
@@ -252,7 +228,6 @@ void DocumentClangToolRunner::onDone(const AnalyzeOutputData &output)
if (!output.success) {
qCDebug(LOG) << "Failed to analyze " << m_fileInfo.file
<< ":" << output.errorMessage << output.errorDetails;
- runNext();
return;
}
@@ -316,26 +291,18 @@ void DocumentClangToolRunner::onDone(const AnalyzeOutputData &output)
m_editorsWithMarkers << widget;
}
}
-
- runNext();
}
void DocumentClangToolRunner::finalize()
{
- // remove all disabled textMarks
- auto [newMarks, toDelete] = Utils::partition(m_marks, &DiagnosticMark::enabled);
+ if (m_taskTree)
+ m_taskTree.release()->deleteLater();
+ // remove all disabled marks
+ const auto [newMarks, toDelete] = Utils::partition(m_marks, &DiagnosticMark::enabled);
m_marks = newMarks;
qDeleteAll(toDelete);
}
-void DocumentClangToolRunner::cancel()
-{
- if (m_projectSettingsUpdate)
- disconnect(m_projectSettingsUpdate);
- m_runnerCreators.clear();
- m_currentRunner.reset(nullptr);
-}
-
bool DocumentClangToolRunner::isSuppressed(const Diagnostic &diagnostic) const
{
auto equalsSuppressed = [this, &diagnostic](const SuppressedDiagnostic &suppressed) {
diff --git a/src/plugins/clangtools/documentclangtoolrunner.h b/src/plugins/clangtools/documentclangtoolrunner.h
index 2bf555e65a8..e3c274ce9cd 100644
--- a/src/plugins/clangtools/documentclangtoolrunner.h
+++ b/src/plugins/clangtools/documentclangtoolrunner.h
@@ -15,12 +15,12 @@
namespace Core { class IDocument; }
namespace TextEditor { class TextEditorWidget; }
+namespace Utils { class TaskTree; }
namespace ClangTools {
namespace Internal {
class AnalyzeOutputData;
-class ClangToolRunner;
class DiagnosticMark;
class DocumentClangToolRunner : public QObject
@@ -36,27 +36,22 @@ public:
private:
void scheduleRun();
void run();
- void runNext();
void onDone(const AnalyzeOutputData &output);
-
void finalize();
- void cancel();
-
bool isSuppressed(const Diagnostic &diagnostic) const;
QTimer m_runTimer;
Core::IDocument *m_document = nullptr;
Utils::TemporaryDirectory m_temporaryDir;
- std::unique_ptr<ClangToolRunner> m_currentRunner;
- QList<std::function<ClangToolRunner *()>> m_runnerCreators;
QList<DiagnosticMark *> m_marks;
FileInfo m_fileInfo;
QMetaObject::Connection m_projectSettingsUpdate;
QList<QPointer<TextEditor::TextEditorWidget>> m_editorsWithMarkers;
SuppressedDiagnosticsList m_suppressed;
Utils::FilePath m_lastProjectDirectory;
+ std::unique_ptr<Utils::TaskTree> m_taskTree;
};
} // namespace Internal