forked from qt-creator/qt-creator
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:
@@ -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,
|
||||
|
@@ -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());
|
||||
});
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -97,7 +97,6 @@ private:
|
||||
protected:
|
||||
ProjectBuilder *m_projectBuilder;
|
||||
Utils::Environment m_environment;
|
||||
QString m_clangExecutable;
|
||||
Utils::TemporaryDirectory m_temporaryDir;
|
||||
|
||||
private:
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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"
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user