summaryrefslogtreecommitdiff
path: root/src/plugins/clangtools/clangtoolruncontrol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/clangtools/clangtoolruncontrol.cpp')
-rw-r--r--src/plugins/clangtools/clangtoolruncontrol.cpp258
1 files changed, 146 insertions, 112 deletions
diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp
index 6467293417..da8e9f053c 100644
--- a/src/plugins/clangtools/clangtoolruncontrol.cpp
+++ b/src/plugins/clangtools/clangtoolruncontrol.cpp
@@ -25,12 +25,12 @@
#include "clangtoolruncontrol.h"
+#include "clangtidyclazyrunner.h"
+#include "clangtidyclazytool.h"
#include "clangtool.h"
#include "clangtoolslogfilereader.h"
-#include "clangtoolsprojectsettings.h"
#include "clangtoolssettings.h"
#include "clangtoolsutils.h"
-#include "clangtoolrunner.h"
#include <debugger/analyzer/analyzerconstants.h>
@@ -81,8 +81,7 @@ static QStringList splitArgs(QString &argsString)
return result;
}
-template<size_t Size>
-static QStringList extraOptions(const char(&environment)[Size])
+static QStringList extraOptions(const char *environment)
{
if (!qEnvironmentVariableIsSet(environment))
return QStringList();
@@ -90,7 +89,8 @@ static QStringList extraOptions(const char(&environment)[Size])
return splitArgs(arguments);
}
-static QStringList extraClangToolsPrependOptions() {
+static QStringList extraClangToolsPrependOptions()
+{
constexpr char csaPrependOptions[] = "QTC_CLANG_CSA_CMD_PREPEND";
constexpr char toolsPrependOptions[] = "QTC_CLANG_TOOLS_CMD_PREPEND";
static const QStringList options = extraOptions(csaPrependOptions)
@@ -100,7 +100,8 @@ static QStringList extraClangToolsPrependOptions() {
return options;
}
-static QStringList extraClangToolsAppendOptions() {
+static QStringList extraClangToolsAppendOptions()
+{
constexpr char csaAppendOptions[] = "QTC_CLANG_CSA_CMD_APPEND";
constexpr char toolsAppendOptions[] = "QTC_CLANG_TOOLS_CMD_APPEND";
static const QStringList options = extraOptions(csaAppendOptions)
@@ -113,29 +114,26 @@ static QStringList extraClangToolsAppendOptions() {
namespace ClangTools {
namespace Internal {
+static ClangTool *tool()
+{
+ return ClangTidyClazyTool::instance();
+}
+
class ProjectBuilder : public RunWorker
{
public:
- ProjectBuilder(RunControl *runControl, Project *project, ClangToolRunControl *parent)
- : RunWorker(runControl), m_project(project), m_parent(parent)
+ ProjectBuilder(RunControl *runControl)
+ : RunWorker(runControl)
{
setId("ProjectBuilder");
}
- void setEnabled(bool enabled) { m_enabled = enabled; }
-
bool success() const { return m_success; }
private:
void start() final
{
- if (!m_enabled) {
- ProjectExplorerPlugin::saveModifiedFiles();
- onBuildFinished(true);
- return;
- }
-
- Target *target = m_project->activeTarget();
+ Target *target = runControl()->target();
QTC_ASSERT(target, reportFailure(); return);
BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown;
@@ -143,14 +141,14 @@ private:
buildType = buildConfig->buildType();
if (buildType == BuildConfiguration::Release) {
- const QString wrongMode = ClangToolRunControl::tr("Release");
- const QString toolName = m_parent->tool()->name();
- const QString title = ClangToolRunControl::tr("Run %1 in %2 Mode?").arg(toolName, wrongMode);
- const QString problem = ClangToolRunControl::tr(
+ const QString wrongMode = ClangToolRunWorker::tr("Release");
+ const QString toolName = tool()->name();
+ const QString title = ClangToolRunWorker::tr("Run %1 in %2 Mode?").arg(toolName, wrongMode);
+ const QString problem = ClangToolRunWorker::tr(
"You are trying to run the tool \"%1\" on an application in %2 mode. The tool is "
"designed to be used in Debug mode since enabled assertions can reduce the number of "
"false positives.").arg(toolName, wrongMode);
- const QString question = ClangToolRunControl::tr(
+ const QString question = ClangToolRunWorker::tr(
"Do you want to continue and run the tool in %1 mode?").arg(wrongMode);
const QString message = QString("<html><head/><body>"
"<p>%1</p>"
@@ -168,7 +166,7 @@ private:
connect(BuildManager::instance(), &BuildManager::buildQueueFinished,
this, &ProjectBuilder::onBuildFinished, Qt::QueuedConnection);
- ProjectExplorerPlugin::buildProject(m_project);
+ ProjectExplorerPlugin::buildProject(target->project());
}
void onBuildFinished(bool success)
@@ -180,9 +178,6 @@ private:
}
private:
- QPointer<Project> m_project;
- ClangToolRunControl *m_parent;
- bool m_enabled = true;
bool m_success = false;
};
@@ -207,7 +202,7 @@ static AnalyzeUnits toAnalyzeUnits(const FileInfos &fileInfos)
return unitsToAnalyze;
}
-AnalyzeUnits ClangToolRunControl::unitsToAnalyze()
+AnalyzeUnits ClangToolRunWorker::unitsToAnalyze()
{
QTC_ASSERT(m_projectInfo.isValid(), return AnalyzeUnits());
@@ -216,79 +211,82 @@ AnalyzeUnits ClangToolRunControl::unitsToAnalyze()
static QDebug operator<<(QDebug debug, const Utils::Environment &environment)
{
- foreach (const QString &entry, environment.toStringList())
+ for (const QString &entry : environment.toStringList())
debug << "\n " << entry;
return debug;
}
static QDebug operator<<(QDebug debug, const AnalyzeUnits &analyzeUnits)
{
- foreach (const AnalyzeUnit &unit, analyzeUnits)
+ for (const AnalyzeUnit &unit : analyzeUnits)
debug << "\n " << unit.file;
return debug;
}
-ClangToolRunControl::ClangToolRunControl(RunControl *runControl,
- Target *target,
- const FileInfos &fileInfos)
+ClangToolRunWorker::ClangToolRunWorker(RunControl *runControl,
+ const ClangDiagnosticConfig &diagnosticConfig,
+ const FileInfos &fileInfos,
+ bool preventBuild)
: RunWorker(runControl)
- , m_projectBuilder(new ProjectBuilder(runControl, target->project(), this))
- , m_clangExecutable(Core::ICore::clangExecutable(CLANG_BINDIR))
, m_temporaryDir("clangtools-XXXXXX")
- , m_target(target)
+ , m_diagnosticConfig(diagnosticConfig)
, m_fileInfos(fileInfos)
{
- addStartDependency(m_projectBuilder);
-
- ClangToolsProjectSettings *projectSettings = ClangToolsProjectSettingsManager::getSettings(
- target->project());
- if (projectSettings->useGlobalSettings())
- m_projectBuilder->setEnabled(ClangToolsSettings::instance()->savedBuildBeforeAnalysis());
- else
- m_projectBuilder->setEnabled(projectSettings->buildBeforeAnalysis());
-}
-
-void ClangToolRunControl::init()
-{
+ setId("ClangTidyClazyRunner");
setSupportsReRunning(false);
- m_projectInfoBeforeBuild = CppTools::CppModelManager::instance()->projectInfo(
- m_target->project());
- BuildConfiguration *buildConfiguration = m_target->activeBuildConfiguration();
+ if (!preventBuild && ClangToolsSettings::instance()->savedBuildBeforeAnalysis()) {
+ m_projectBuilder = new ProjectBuilder(runControl);
+ addStartDependency(m_projectBuilder);
+ }
+
+ Target *target = runControl->target();
+ m_projectInfoBeforeBuild = CppTools::CppModelManager::instance()->projectInfo(target->project());
+
+ BuildConfiguration *buildConfiguration = target->activeBuildConfiguration();
QTC_ASSERT(buildConfiguration, return);
m_environment = buildConfiguration->environment();
- ToolChain *toolChain = ToolChainKitAspect::toolChain(m_target->kit(),
- ProjectExplorer::Constants::CXX_LANGUAGE_ID);
+ ToolChain *toolChain = ToolChainKitAspect::toolChain(target->kit(),
+ ProjectExplorer::Constants::CXX_LANGUAGE_ID);
QTC_ASSERT(toolChain, return);
m_targetTriple = toolChain->originalTargetTriple();
m_toolChainType = toolChain->typeId();
}
-void ClangToolRunControl::start()
+QList<RunnerCreator> ClangToolRunWorker::runnerCreators()
+{
+ QList<RunnerCreator> creators;
+
+ if (m_diagnosticConfig.clangTidyMode() != CppTools::ClangDiagnosticConfig::TidyMode::Disabled)
+ creators << [this]() { return createRunner<ClangTidyRunner>(); };
+
+ if (!m_diagnosticConfig.clazyChecks().isEmpty()) {
+ if (!qEnvironmentVariable("QTC_USE_CLAZY_STANDALONE_PATH").isEmpty())
+ creators << [this]() { return createRunner<ClazyStandaloneRunner>(); };
+ else
+ creators << [this]() { return createRunner<ClazyPluginRunner>(); };
+ }
+
+ return creators;
+}
+
+void ClangToolRunWorker::start()
{
TaskHub::clearTasks(Debugger::Constants::ANALYZERTASK_ID);
+ ProjectExplorerPlugin::saveModifiedFiles();
if (ClangToolsSettings::instance()->savedBuildBeforeAnalysis()) {
- QTC_ASSERT(m_projectBuilder, return;);
- if (!m_projectBuilder->success()) {
+ if (m_projectBuilder && !m_projectBuilder->success()) {
reportFailure();
return;
}
}
const QString &toolName = tool()->name();
- if (m_clangExecutable.isEmpty()) {
- const QString errorMessage = tr("%1: Can't find clang executable, stop.").arg(toolName);
- appendMessage(errorMessage, Utils::ErrorMessageFormat);
- TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID);
- TaskHub::requestPopup();
- reportFailure();
- return;
- }
-
- m_projectInfo = CppTools::CppModelManager::instance()->projectInfo(m_target->project());
- m_projectFiles = Utils::toSet(m_target->project()->files(Project::AllFiles));
+ Project *project = runControl()->project();
+ m_projectInfo = CppTools::CppModelManager::instance()->projectInfo(project);
+ m_projectFiles = Utils::toSet(project->files(Project::AllFiles));
// Some projects provides CompilerCallData once a build is finished,
if (m_projectInfo.configurationOrFilesChanged(m_projectInfoBeforeBuild)) {
@@ -318,10 +316,15 @@ void ClangToolRunControl::start()
// Collect files
const AnalyzeUnits unitsToProcess = unitsToAnalyze();
qCDebug(LOG) << "Files to process:" << unitsToProcess;
- m_unitsToProcess = unitsToProcess;
- m_initialFilesToProcessSize = m_unitsToProcess.count();
- m_filesAnalyzed = 0;
- m_filesNotAnalyzed = 0;
+
+ m_queue.clear();
+ for (const AnalyzeUnit &unit : unitsToProcess) {
+ for (const RunnerCreator &creator : runnerCreators())
+ m_queue << QueueItem{unit, creator};
+ }
+ m_initialQueueSize = m_queue.count();
+ m_filesAnalyzed.clear();
+ m_filesNotAnalyzed.clear();
// Set up progress information
using namespace Core;
@@ -331,8 +334,8 @@ void ClangToolRunControl::start()
toolName.toStdString().c_str());
futureProgress->setKeepOnFinish(FutureProgress::HideOnFinish);
connect(futureProgress, &FutureProgress::canceled,
- this, &ClangToolRunControl::onProgressCanceled);
- m_progress.setProgressRange(0, m_initialFilesToProcessSize);
+ this, &ClangToolRunWorker::onProgressCanceled);
+ m_progress.setProgressRange(0, m_initialQueueSize);
m_progress.reportStarted();
// Start process(es)
@@ -342,75 +345,91 @@ void ClangToolRunControl::start()
QTC_ASSERT(parallelRuns >= 1, reportFailure(); return);
m_success = true;
- if (m_unitsToProcess.isEmpty()) {
+ if (m_queue.isEmpty()) {
finalize();
return;
}
reportStarted();
- while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty())
+ while (m_runners.size() < parallelRuns && !m_queue.isEmpty())
analyzeNextFile();
}
-void ClangToolRunControl::stop()
+void ClangToolRunWorker::stop()
{
- QSetIterator<ClangToolRunner *> i(m_runners);
- while (i.hasNext()) {
- ClangToolRunner *runner = i.next();
+ for (ClangToolRunner *runner : m_runners) {
QObject::disconnect(runner, nullptr, this, nullptr);
delete runner;
}
m_projectFiles.clear();
m_runners.clear();
- m_unitsToProcess.clear();
+ m_queue.clear();
m_progress.reportFinished();
reportStopped();
}
-void ClangToolRunControl::analyzeNextFile()
+void ClangToolRunWorker::analyzeNextFile()
{
if (m_progress.isFinished())
return; // The previous call already reported that we are finished.
- if (m_unitsToProcess.isEmpty()) {
+ if (m_queue.isEmpty()) {
if (m_runners.isEmpty())
finalize();
return;
}
- const AnalyzeUnit unit = m_unitsToProcess.takeFirst();
+ const QueueItem queueItem = m_queue.takeFirst();
+ const AnalyzeUnit unit = queueItem.unit;
qCDebug(LOG) << "analyzeNextFile:" << unit.file;
- ClangToolRunner *runner = createRunner();
+ ClangToolRunner *runner = queueItem.runnerCreator();
m_runners.insert(runner);
+
+ const QString executable = runner->executable();
+ if (!isFileExecutable(executable)) {
+ const QString errorMessage = tr("%1: Invalid executable \"%2\", stop.")
+ .arg(runner->name(), executable);
+ TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID);
+ TaskHub::requestPopup();
+ reportFailure(errorMessage);
+ stop();
+ return;
+ }
+
QTC_ASSERT(runner->run(unit.file, unit.arguments), return);
- appendMessage(tr("Analyzing \"%1\".").arg(
- Utils::FilePath::fromString(unit.file).toUserOutput()),
+ appendMessage(tr("Analyzing \"%1\" [%2].")
+ .arg(FilePath::fromString(unit.file).toUserOutput(), runner->name()),
Utils::StdOutFormat);
}
-void ClangToolRunControl::onRunnerFinishedWithSuccess(const QString &filePath)
+void ClangToolRunWorker::onRunnerFinishedWithSuccess(const QString &filePath)
{
- const QString logFilePath = qobject_cast<ClangToolRunner *>(sender())->logFilePath();
- qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath;
+ auto runner = qobject_cast<ClangToolRunner *>(sender());
+ const QString outputFilePath = runner->outputFilePath();
+ qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << outputFilePath;
QString errorMessage;
- const QList<Diagnostic> diagnostics = tool()->read(filePath,
- m_projectFiles,
- logFilePath,
- &errorMessage);
- QFile::remove(logFilePath); // Clean-up.
+ const Diagnostics diagnostics = tool()->read(runner->outputFileFormat(),
+ outputFilePath,
+ filePath,
+ m_projectFiles,
+ &errorMessage);
+ QFile::remove(outputFilePath); // Clean-up.
if (!errorMessage.isEmpty()) {
+ m_filesAnalyzed.remove(filePath);
+ m_filesNotAnalyzed.insert(filePath);
qCDebug(LOG) << "onRunnerFinishedWithSuccess: Error reading log file:" << errorMessage;
- const QString filePath = qobject_cast<ClangToolRunner *>(sender())->filePath();
+ const QString filePath = qobject_cast<ClangToolRunner *>(sender())->fileToAnalyze();
appendMessage(tr("Failed to analyze \"%1\": %2").arg(filePath, errorMessage),
Utils::StdErrFormat);
} else {
- ++m_filesAnalyzed;
+ if (!m_filesNotAnalyzed.contains(filePath))
+ m_filesAnalyzed.insert(filePath);
if (!diagnostics.isEmpty())
tool()->onNewDiagnosticsAvailable(diagnostics);
}
@@ -418,30 +437,31 @@ void ClangToolRunControl::onRunnerFinishedWithSuccess(const QString &filePath)
handleFinished();
}
-void ClangToolRunControl::onRunnerFinishedWithFailure(const QString &errorMessage,
+void ClangToolRunWorker::onRunnerFinishedWithFailure(const QString &errorMessage,
const QString &errorDetails)
{
qCDebug(LOG).noquote() << "onRunnerFinishedWithFailure:"
<< errorMessage << '\n' << errorDetails;
auto *toolRunner = qobject_cast<ClangToolRunner *>(sender());
- const QString filePath = toolRunner->filePath();
- const QString logFilePath = toolRunner->logFilePath();
+ const QString fileToAnalyze = toolRunner->fileToAnalyze();
+ const QString outputFilePath = toolRunner->outputFilePath();
// Even in the error case the log file was created, so clean it up here, too.
- QFile::remove(logFilePath);
+ QFile::remove(outputFilePath);
- const QString message = tr("Failed to analyze \"%1\": %2").arg(filePath, errorMessage);
-
- ++m_filesNotAnalyzed;
+ m_filesAnalyzed.remove(fileToAnalyze);
+ m_filesNotAnalyzed.insert(fileToAnalyze);
m_success = false;
+
+ const QString message = tr("Failed to analyze \"%1\": %2").arg(fileToAnalyze, errorMessage);
appendMessage(message, Utils::StdErrFormat);
appendMessage(errorDetails, Utils::StdErrFormat);
TaskHub::addTask(Task::Error, message, Debugger::Constants::ANALYZERTASK_ID);
handleFinished();
}
-void ClangToolRunControl::handleFinished()
+void ClangToolRunWorker::handleFinished()
{
m_runners.remove(qobject_cast<ClangToolRunner *>(sender()));
updateProgressValue();
@@ -449,31 +469,33 @@ void ClangToolRunControl::handleFinished()
analyzeNextFile();
}
-void ClangToolRunControl::onProgressCanceled()
+void ClangToolRunWorker::onProgressCanceled()
{
m_progress.reportCanceled();
runControl()->initiateStop();
}
-void ClangToolRunControl::updateProgressValue()
+void ClangToolRunWorker::updateProgressValue()
{
- m_progress.setProgressValue(m_initialFilesToProcessSize - m_unitsToProcess.size());
+ m_progress.setProgressValue(m_initialQueueSize - m_queue.size());
}
-void ClangToolRunControl::finalize()
+void ClangToolRunWorker::finalize()
{
const QString toolName = tool()->name();
appendMessage(tr("%1 finished: "
"Processed %2 files successfully, %3 failed.")
- .arg(toolName).arg(m_filesAnalyzed).arg(m_filesNotAnalyzed),
+ .arg(toolName)
+ .arg(m_filesAnalyzed.size())
+ .arg(m_filesNotAnalyzed.size()),
Utils::NormalMessageFormat);
- if (m_filesNotAnalyzed != 0) {
+ if (m_filesNotAnalyzed.size() != 0) {
QString msg = tr("%1: Not all files could be analyzed.").arg(toolName);
TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
- if (m_target && !m_target->activeBuildConfiguration()->buildDirectory().exists()
- && !ClangToolsProjectSettingsManager::getSettings(m_target->project())
- ->buildBeforeAnalysis()) {
+ Target *target = runControl()->target();
+ if (target && !target->activeBuildConfiguration()->buildDirectory().exists()
+ && !ClangToolsSettings::instance()->savedBuildBeforeAnalysis()) {
msg = tr("%1: You might need to build the project to generate or update source "
"files. To build automatically, enable \"Build the project before starting "
"analysis\".")
@@ -488,5 +510,17 @@ void ClangToolRunControl::finalize()
runControl()->initiateStop();
}
+template<class T>
+ClangToolRunner *ClangToolRunWorker::createRunner()
+{
+ auto runner = new T(m_diagnosticConfig, this);
+ runner->init(m_temporaryDir.path(), m_environment);
+ connect(runner, &ClangToolRunner::finishedWithSuccess,
+ this, &ClangToolRunWorker::onRunnerFinishedWithSuccess);
+ connect(runner, &ClangToolRunner::finishedWithFailure,
+ this, &ClangToolRunWorker::onRunnerFinishedWithFailure);
+ return runner;
+}
+
} // namespace Internal
} // namespace ClangTools