ClangTools: Invoke clang-tidy instead of clang

Change-Id: Ibcc53cf8cb8bbaf262757bec52f15936506dad50
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Nikolai Kosjar
2019-08-01 16:08:40 +02:00
parent 9f868c44ce
commit a8f00d147c
13 changed files with 104 additions and 75 deletions

View File

@@ -47,11 +47,12 @@ QList<RunnerCreator> ClangTidyClazyRunWorker::runnerCreators()
{
QList<RunnerCreator> creators;
if (!m_diagnosticConfig.clazyChecks().isEmpty())
creators << [this]() { return createRunner<ClazyRunner>(); };
if (m_diagnosticConfig.clangTidyMode() != CppTools::ClangDiagnosticConfig::TidyMode::Disabled)
creators << [this]() { return createRunner<ClangTidyRunner>(); };
if (!m_diagnosticConfig.clazyChecks().isEmpty())
creators << [this]() { return createRunner<ClazyPluginRunner>(); };
return creators;
}
@@ -59,7 +60,7 @@ template <class T>
ClangToolRunner *ClangTidyClazyRunWorker::createRunner()
{
auto runner = new T(m_diagnosticConfig, this);
runner->init(m_clangExecutable, m_temporaryDir.path(), m_environment);
runner->init(m_temporaryDir.path(), m_environment);
connect(runner, &ClangToolRunner::finishedWithSuccess,
this, &ClangTidyClazyRunWorker::onRunnerFinishedWithSuccess);
connect(runner, &ClangToolRunner::finishedWithFailure,

View File

@@ -27,6 +27,8 @@
#include "clangtoolssettings.h"
#include <coreplugin/icore.h>
#include <cpptools/compileroptionsbuilder.h>
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cpptoolsreuse.h>
@@ -45,40 +47,13 @@ using namespace CppTools;
namespace ClangTools {
namespace Internal {
static QStringList commonArguments(const QStringList &options,
const QString &logFile,
const ClangDiagnosticConfig diagnosticConfig)
static QStringList serializeDiagnosticsArguments(const QStringList &baseOptions,
const QString &outputFilePath)
{
QStringList arguments;
if (LOG().isDebugEnabled())
arguments << QLatin1String("-v");
const QStringList serializeArgs{"-serialize-diagnostics", logFile};
if (options.contains("--driver-mode=cl"))
arguments << clangArgsForCl(serializeArgs);
else
arguments << serializeArgs;
arguments << ClangDiagnosticConfigsModel::globalDiagnosticOptions()
<< diagnosticConfig.clangOptions();
return arguments;
}
static QStringList tidyPluginArguments(const ClangDiagnosticConfig diagnosticConfig)
{
QStringList arguments;
const ClangDiagnosticConfig::TidyMode tidyMode = diagnosticConfig.clangTidyMode();
if (tidyMode != ClangDiagnosticConfig::TidyMode::Disabled) {
arguments << XclangArgs({"-add-plugin", "clang-tidy"});
if (tidyMode != ClangDiagnosticConfig::TidyMode::File) {
const QString tidyChecks = diagnosticConfig.clangTidyChecks();
arguments << XclangArgs({"-plugin-arg-clang-tidy", "-checks=" + tidyChecks});
}
}
return arguments;
const QStringList serializeArgs{"-serialize-diagnostics", outputFilePath};
if (baseOptions.contains("--driver-mode=cl"))
return clangArgsForCl(serializeArgs);
return serializeArgs;
}
static QStringList clazyPluginArguments(const ClangDiagnosticConfig diagnosticConfig)
@@ -100,25 +75,64 @@ static QStringList clazyPluginArguments(const ClangDiagnosticConfig diagnosticCo
return arguments;
}
static QStringList tidyChecksArguments(const ClangDiagnosticConfig diagnosticConfig)
{
const ClangDiagnosticConfig::TidyMode tidyMode = diagnosticConfig.clangTidyMode();
if (tidyMode != ClangDiagnosticConfig::TidyMode::Disabled) {
if (tidyMode != ClangDiagnosticConfig::TidyMode::File)
return {"-checks=" + diagnosticConfig.clangTidyChecks()};
}
return {};
}
static QStringList mainToolArguments(const QString &mainFilePath, const QString &outputFilePath)
{
return {
"-export-fixes=" + outputFilePath,
QDir::toNativeSeparators(mainFilePath),
};
}
static QStringList clangArguments(const ClangDiagnosticConfig &diagnosticConfig,
const QStringList &baseOptions)
{
QStringList arguments;
arguments << ClangDiagnosticConfigsModel::globalDiagnosticOptions()
<< diagnosticConfig.clangOptions()
<< baseOptions;
if (LOG().isDebugEnabled())
arguments << QLatin1String("-v");
return arguments;
}
ClangTidyRunner::ClangTidyRunner(const ClangDiagnosticConfig &config, QObject *parent)
: ClangToolRunner(parent)
{
setName(tr("Clang-Tidy"));
setOutputFileFormat(OutputFileFormat::Yaml);
setExecutable(Core::ICore::clangTidyExecutable(CLANG_BINDIR));
setArgsCreator([this, config](const QStringList &baseOptions) {
return commonArguments(baseOptions, m_logFile, config)
<< tidyPluginArguments(config)
<< baseOptions
<< QDir::toNativeSeparators(filePath());
return QStringList()
<< tidyChecksArguments(config)
<< mainToolArguments(filePath(), m_logFile)
<< "--"
<< clangArguments(config, baseOptions);
});
}
ClazyRunner::ClazyRunner(const ClangDiagnosticConfig &config, QObject *parent)
ClazyPluginRunner::ClazyPluginRunner(const ClangDiagnosticConfig &config, QObject *parent)
: ClangToolRunner(parent)
{
setName(tr("Clazy"));
setOutputFileFormat(OutputFileFormat::Serialized);
setExecutable(Core::ICore::clangExecutable(CLANG_BINDIR));
setArgsCreator([this, config](const QStringList &baseOptions) {
return commonArguments(baseOptions, m_logFile, config)
<< clazyPluginArguments(config) << baseOptions
return serializeDiagnosticsArguments(baseOptions, m_logFile)
<< clazyPluginArguments(config)
<< clangArguments(config, baseOptions)
<< QDir::toNativeSeparators(filePath());
});
}

View File

@@ -40,12 +40,12 @@ public:
ClangTidyRunner(const CppTools::ClangDiagnosticConfig &config, QObject *parent = nullptr);
};
class ClazyRunner final : public ClangToolRunner
class ClazyPluginRunner final : public ClangToolRunner
{
Q_OBJECT
public:
ClazyRunner(const CppTools::ClangDiagnosticConfig &config, QObject *parent = nullptr);
ClazyPluginRunner(const CppTools::ClangDiagnosticConfig &config, QObject *parent = nullptr);
};
} // namespace Internal

View File

@@ -516,7 +516,8 @@ void ClangTidyClazyTool::handleStateUpdate()
Debugger::showPermanentStatusMessage(message);
}
Diagnostics ClangTidyClazyTool::read(const QString &logFilePath,
Diagnostics ClangTidyClazyTool::read(OutputFileFormat outputFileFormat,
const QString &logFilePath,
const QString &mainFilePath,
const QSet<Utils::FilePath> &projectFiles,
QString *errorMessage) const
@@ -525,6 +526,11 @@ Diagnostics ClangTidyClazyTool::read(const QString &logFilePath,
return projectFiles.contains(filePath);
};
if (outputFileFormat == OutputFileFormat::Yaml) {
return readExportedDiagnostics(Utils::FilePath::fromString(logFilePath),
acceptFromFilePath,
errorMessage);
}
return readSerializedDiagnostics(Utils::FilePath::fromString(logFilePath),
Utils::FilePath::fromString(mainFilePath),
acceptFromFilePath,

View File

@@ -53,7 +53,8 @@ public:
void startTool(bool askUserForFileSelection) final;
Diagnostics read(const QString &logFilePath,
Diagnostics read(OutputFileFormat outputFileFormat,
const QString &logFilePath,
const QString &mainFilePath,
const QSet<Utils::FilePath> &projectFiles,
QString *errorMessage) const final;

View File

@@ -27,6 +27,7 @@
#include "clangfileinfo.h"
#include "clangtoolsdiagnostic.h"
#include "clangtoolslogfilereader.h"
#include <projectexplorer/runconfiguration.h>
#include <cpptools/projectinfo.h>
@@ -50,7 +51,8 @@ public:
virtual void startTool(bool askUserForFileSelection) = 0;
virtual Diagnostics read(const QString &logFilePath,
virtual Diagnostics read(OutputFileFormat outputFileFormat,
const QString &logFilePath,
const QString &mainFilePath,
const QSet<Utils::FilePath> &projectFiles,
QString *errorMessage) const = 0;

View File

@@ -232,7 +232,6 @@ ClangToolRunWorker::ClangToolRunWorker(RunControl *runControl,
const FileInfos &fileInfos)
: RunWorker(runControl)
, m_projectBuilder(new ProjectBuilder(runControl, this))
, m_clangExecutable(Core::ICore::clangExecutable(CLANG_BINDIR))
, m_temporaryDir("clangtools-XXXXXX")
, m_fileInfos(fileInfos)
{
@@ -276,15 +275,6 @@ void ClangToolRunWorker::start()
}
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;
}
Project *project = runControl()->project();
m_projectInfo = CppTools::CppModelManager::instance()->projectInfo(project);
m_projectFiles = Utils::toSet(project->files(Project::AllFiles));
@@ -397,11 +387,13 @@ void ClangToolRunWorker::analyzeNextFile()
void ClangToolRunWorker::onRunnerFinishedWithSuccess(const QString &filePath)
{
const QString logFilePath = qobject_cast<ClangToolRunner *>(sender())->logFilePath();
auto runner = qobject_cast<ClangToolRunner *>(sender());
const QString logFilePath = runner->logFilePath();
qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath;
QString errorMessage;
const Diagnostics diagnostics = tool()->read(logFilePath,
const Diagnostics diagnostics = tool()->read(runner->outputFileFormat(),
logFilePath,
filePath,
m_projectFiles,
&errorMessage);

View File

@@ -97,7 +97,6 @@ private:
protected:
ProjectBuilder *m_projectBuilder;
Utils::Environment m_environment;
QString m_clangExecutable;
Utils::TemporaryDirectory m_temporaryDir;
private:

View File

@@ -58,13 +58,10 @@ QString finishedWithBadExitCode(const QString &name, int exitCode)
return ClangToolRunner::tr("%1 finished with exit code: %2.").arg(name).arg(exitCode);
}
void ClangToolRunner::init(const QString &clangExecutable,
const QString &clangLogFileDir,
void ClangToolRunner::init(const QString &clangLogFileDir,
const Utils::Environment &environment)
{
m_clangExecutable = QDir::toNativeSeparators(clangExecutable);
m_clangLogFileDir = clangLogFileDir;
QTC_CHECK(!m_clangExecutable.isEmpty());
QTC_CHECK(!m_clangLogFileDir.isEmpty());
m_process.setProcessChannelMode(QProcess::MergedChannels);
@@ -84,7 +81,7 @@ ClangToolRunner::~ClangToolRunner()
bool ClangToolRunner::run(const QString &filePath, const QStringList &compilerOptions)
{
QTC_ASSERT(!m_clangExecutable.isEmpty(), return false);
QTC_ASSERT(!m_executable.isEmpty(), return false);
QTC_CHECK(!compilerOptions.contains(QLatin1String("-o")));
QTC_CHECK(!compilerOptions.contains(filePath));
@@ -94,10 +91,10 @@ bool ClangToolRunner::run(const QString &filePath, const QStringList &compilerOp
m_logFile = createLogFile(filePath);
QTC_ASSERT(!m_logFile.isEmpty(), return false);
const QStringList arguments = m_argsCreator(compilerOptions);
m_commandLine = Utils::QtcProcess::joinArgs(QStringList(m_clangExecutable) + arguments);
m_commandLine = Utils::QtcProcess::joinArgs(QStringList(m_executable) + arguments);
qCDebug(LOG).noquote() << "Starting" << m_commandLine;
m_process.start(m_clangExecutable, arguments);
m_process.start(m_executable, arguments);
return true;
}

View File

@@ -25,6 +25,8 @@
#pragma once
#include "clangtoolslogfilereader.h"
#include <memory>
#include <QString>
@@ -47,11 +49,11 @@ public:
ClangToolRunner(QObject *parent = nullptr) : QObject(parent) {}
~ClangToolRunner() override;
void init(const QString &clangExecutable,
const QString &clangLogFileDir,
const Utils::Environment &environment);
void init(const QString &clangLogFileDir, const Utils::Environment &environment);
void setName(const QString &name) { m_name = name; }
void setExecutable(const QString &executable) { m_executable = executable; }
void setArgsCreator(const ArgsCreator &argsCreator) { m_argsCreator = argsCreator; }
void setOutputFileFormat(const OutputFileFormat &format) { m_outputFileFormat = format; }
// compilerOptions is expected to contain everything except:
// (1) filePath, that is the file to analyze
@@ -59,6 +61,7 @@ public:
bool run(const QString &filePath, const QStringList &compilerOptions = QStringList());
QString name() const { return m_name; }
OutputFileFormat outputFileFormat() const { return m_outputFileFormat; }
QString filePath() const { return m_filePath; }
QString logFilePath() const { return m_logFile; }
@@ -82,11 +85,12 @@ protected:
QByteArray m_processOutput;
private:
QString m_clangExecutable;
QString m_clangLogFileDir;
QString m_name;
QString m_executable;
ArgsCreator m_argsCreator;
OutputFileFormat m_outputFileFormat = OutputFileFormat::Yaml;
QString m_filePath;
QString m_commandLine;

View File

@@ -34,6 +34,8 @@ namespace Utils { class FilePath; }
namespace ClangTools {
namespace Internal {
enum class OutputFileFormat { Serialized, Yaml };
using AcceptDiagsFromFilePath = std::function<bool(const Utils::FilePath &)>;
// Reads diagnostics generated by "clang -serialize-diagnostics path/to/file"

View File

@@ -476,15 +476,25 @@ QString ICore::clangIncludeDirectory(const QString &clangVersion, const QString
return QDir::toNativeSeparators(dir.canonicalPath());
}
QString ICore::clangExecutable(const QString &clangBinDirectory)
static QString clangBinary(const QString &binaryBaseName, const QString &clangBinDirectory)
{
const QString hostExeSuffix(QTC_HOST_EXE_SUFFIX);
QFileInfo executable(libexecPath() + "/clang/bin/clang" + hostExeSuffix);
QFileInfo executable(ICore::libexecPath() + "/clang/bin/" + binaryBaseName + hostExeSuffix);
if (!executable.exists())
executable = QFileInfo(clangBinDirectory + "/clang" + hostExeSuffix);
executable = QFileInfo(clangBinDirectory + "/" + binaryBaseName + hostExeSuffix);
return QDir::toNativeSeparators(executable.canonicalFilePath());
}
QString ICore::clangExecutable(const QString &clangBinDirectory)
{
return clangBinary("clang", clangBinDirectory);
}
QString ICore::clangTidyExecutable(const QString &clangBinDirectory)
{
return clangBinary("clang-tidy", clangBinDirectory);
}
static QString compilerString()
{
#if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too

View File

@@ -99,6 +99,7 @@ public:
static QString installerResourcePath();
static QString libexecPath();
static QString clangExecutable(const QString &clangBinDirectory);
static QString clangTidyExecutable(const QString &clangBinDirectory);
static QString clangIncludeDirectory(const QString &clangVersion,
const QString &clangResourceDirectory);