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 <david.schulz@qt.io>
This commit is contained in:
Jarek Kobus
2023-01-11 23:48:53 +01:00
parent 1dad90ea45
commit e7781e2a99
8 changed files with 204 additions and 339 deletions

View File

@@ -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);
struct ClangToolStorage {
QString name;
Utils::FilePath executable;
QString outputFilePath;
};
const TreeStorage<ClangToolStorage> storage;
m_outputFilePath = createOutputFilePath(m_input.outputDirPath, m_input.unit.file);
QTC_ASSERT(!m_outputFilePath.isEmpty(), return false);
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 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};
const auto onGroupSetup = [=] {
const GroupConfig error = GroupConfig{GroupAction::StopWithError};
if (setupHandler && !setupHandler())
return error;
qCDebug(LOG).noquote() << "Starting" << commandLine.toUserOutput();
m_process.setCommand(commandLine);
m_process.start();
return true;
}
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;
}
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;
}
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);
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);
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.
emit done({false, m_input.unit.file, m_outputFilePath, m_name, message, details});
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