ClangTools: Add UI for specifying executables

Add a new group box "Executables" for this. Hide the UI for
clazy-standalone unless QTC_USE_CLAZY_STANDALONE_PATH is set as there is
no released version with the needed -export-fixes option.

Rename the previous group box from "General" to "Run Options".

Change-Id: Ia9daf66c40d3a7eea98b31d9c086886d29466490
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-28 08:56:22 +02:00
parent 8890a7412c
commit fc37ea4276
12 changed files with 279 additions and 7 deletions

View File

@@ -26,6 +26,7 @@
#include "clangtidyclazyrunner.h" #include "clangtidyclazyrunner.h"
#include "clangtoolssettings.h" #include "clangtoolssettings.h"
#include "clangtoolsutils.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
@@ -121,7 +122,7 @@ ClangTidyRunner::ClangTidyRunner(const ClangDiagnosticConfig &config, QObject *p
{ {
setName(tr("Clang-Tidy")); setName(tr("Clang-Tidy"));
setOutputFileFormat(OutputFileFormat::Yaml); setOutputFileFormat(OutputFileFormat::Yaml);
setExecutable(Core::ICore::clangTidyExecutable(CLANG_BINDIR)); setExecutable(clangTidyExecutable());
setArgsCreator([this, config](const QStringList &baseOptions) { setArgsCreator([this, config](const QStringList &baseOptions) {
return QStringList() return QStringList()
<< tidyChecksArguments(config) << tidyChecksArguments(config)
@@ -136,7 +137,7 @@ ClazyStandaloneRunner::ClazyStandaloneRunner(const ClangDiagnosticConfig &config
{ {
setName(tr("Clazy")); setName(tr("Clazy"));
setOutputFileFormat(OutputFileFormat::Yaml); setOutputFileFormat(OutputFileFormat::Yaml);
setExecutable(qEnvironmentVariable("QTC_USE_CLAZY_STANDALONE_PATH")); setExecutable(clazyStandaloneExecutable());
setArgsCreator([this, config](const QStringList &baseOptions) { setArgsCreator([this, config](const QStringList &baseOptions) {
return QStringList() return QStringList()
<< clazyChecksArguments(config) << clazyChecksArguments(config)

View File

@@ -310,7 +310,7 @@ void ClangToolRunWorker::start()
m_queue.clear(); m_queue.clear();
for (const AnalyzeUnit &unit : unitsToProcess) { for (const AnalyzeUnit &unit : unitsToProcess) {
for (auto creator : runnerCreators()) for (const RunnerCreator &creator : runnerCreators())
m_queue << QueueItem{unit, creator}; m_queue << QueueItem{unit, creator};
} }
m_initialQueueSize = m_queue.count(); m_initialQueueSize = m_queue.count();
@@ -378,6 +378,18 @@ void ClangToolRunWorker::analyzeNextFile()
ClangToolRunner *runner = queueItem.runnerCreator(); ClangToolRunner *runner = queueItem.runnerCreator();
m_runners.insert(runner); 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); QTC_ASSERT(runner->run(unit.file, unit.arguments), return);
appendMessage(tr("Analyzing \"%1\" [%2].") appendMessage(tr("Analyzing \"%1\" [%2].")

View File

@@ -62,6 +62,7 @@ public:
QString name() const { return m_name; } QString name() const { return m_name; }
OutputFileFormat outputFileFormat() const { return m_outputFileFormat; } OutputFileFormat outputFileFormat() const { return m_outputFileFormat; }
QString executable() const { return m_executable; }
QString filePath() const { return m_filePath; } QString filePath() const { return m_filePath; }
QString logFilePath() const { return m_logFile; } QString logFilePath() const { return m_logFile; }

View File

@@ -32,5 +32,8 @@ const char SETTINGS_PAGE_ID[] = "Analyzer.ClangTools.Settings";
const char SETTINGS_ID[] = "ClangTools"; const char SETTINGS_ID[] = "ClangTools";
const char CLANGTIDYCLAZY_RUN_MODE[] = "ClangTidyClazy.RunMode"; const char CLANGTIDYCLAZY_RUN_MODE[] = "ClangTidyClazy.RunMode";
const char CLANG_TIDY_EXECUTABLE_NAME[] = "clang-tidy";
const char CLAZY_STANDALONE_EXECUTABLE_NAME[] = "clazy-standalone";
} // Constants } // Constants
} // ClangTools } // ClangTools

View File

@@ -38,6 +38,8 @@
static const char simultaneousProcessesKey[] = "simultaneousProcesses"; static const char simultaneousProcessesKey[] = "simultaneousProcesses";
static const char buildBeforeAnalysisKey[] = "buildBeforeAnalysis"; static const char buildBeforeAnalysisKey[] = "buildBeforeAnalysis";
static const char diagnosticConfigIdKey[] = "diagnosticConfigId"; static const char diagnosticConfigIdKey[] = "diagnosticConfigId";
static const char clangTidyExecutableKey[] = "clangTidyExecutable";
static const char clazyStandaloneExecutableKey[] = "clazyStandaloneExecutable";
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
@@ -106,6 +108,36 @@ void ClangToolsSettings::updateSavedBuildBeforeAnalysiIfRequired()
emit buildBeforeAnalysisChanged(m_savedBuildBeforeAnalysis); emit buildBeforeAnalysisChanged(m_savedBuildBeforeAnalysis);
} }
QString ClangToolsSettings::savedClazyStandaloneExecutable() const
{
return m_savedClazyStandaloneExecutable;
}
QString ClangToolsSettings::savedClangTidyExecutable() const
{
return m_savedClangTidyExecutable;
}
QString ClangToolsSettings::clazyStandaloneExecutable() const
{
return m_clazyStandaloneExecutable;
}
void ClangToolsSettings::setClazyStandaloneExecutable(const QString &path)
{
m_clazyStandaloneExecutable = path;
}
QString ClangToolsSettings::clangTidyExecutable() const
{
return m_clangTidyExecutable;
}
void ClangToolsSettings::setClangTidyExecutable(const QString &path)
{
m_clangTidyExecutable = path;
}
void ClangToolsSettings::readSettings() void ClangToolsSettings::readSettings()
{ {
QSettings *settings = Core::ICore::settings(); QSettings *settings = Core::ICore::settings();
@@ -118,6 +150,11 @@ void ClangToolsSettings::readSettings()
m_buildBeforeAnalysis = settings->value(QString(buildBeforeAnalysisKey), true).toBool(); m_buildBeforeAnalysis = settings->value(QString(buildBeforeAnalysisKey), true).toBool();
m_savedClangTidyExecutable = m_clangTidyExecutable
= settings->value(QLatin1String(clangTidyExecutableKey)).toString();
m_savedClazyStandaloneExecutable = m_clazyStandaloneExecutable
= settings->value(QLatin1String(clazyStandaloneExecutableKey)).toString();
m_diagnosticConfigId = Core::Id::fromSetting(settings->value(QString(diagnosticConfigIdKey))); m_diagnosticConfigId = Core::Id::fromSetting(settings->value(QString(diagnosticConfigIdKey)));
if (!m_diagnosticConfigId.isValid()) if (!m_diagnosticConfigId.isValid())
m_diagnosticConfigId = "Builtin.TidyAndClazy"; m_diagnosticConfigId = "Builtin.TidyAndClazy";
@@ -135,10 +172,14 @@ void ClangToolsSettings::writeSettings()
settings->beginGroup(QString(Constants::SETTINGS_ID)); settings->beginGroup(QString(Constants::SETTINGS_ID));
settings->setValue(QString(simultaneousProcessesKey), m_simultaneousProcesses); settings->setValue(QString(simultaneousProcessesKey), m_simultaneousProcesses);
settings->setValue(QString(buildBeforeAnalysisKey), m_buildBeforeAnalysis); settings->setValue(QString(buildBeforeAnalysisKey), m_buildBeforeAnalysis);
settings->setValue(QString(clangTidyExecutableKey), m_clangTidyExecutable);
settings->setValue(QString(clazyStandaloneExecutableKey), m_clazyStandaloneExecutable);
settings->setValue(QString(diagnosticConfigIdKey), m_diagnosticConfigId.toSetting()); settings->setValue(QString(diagnosticConfigIdKey), m_diagnosticConfigId.toSetting());
m_savedSimultaneousProcesses = m_simultaneousProcesses; m_savedSimultaneousProcesses = m_simultaneousProcesses;
m_savedDiagnosticConfigId = m_diagnosticConfigId; m_savedDiagnosticConfigId = m_diagnosticConfigId;
m_savedClangTidyExecutable = m_clangTidyExecutable;
m_savedClazyStandaloneExecutable = m_clazyStandaloneExecutable;
updateSavedBuildBeforeAnalysiIfRequired(); updateSavedBuildBeforeAnalysiIfRequired();
settings->endGroup(); settings->endGroup();

View File

@@ -33,6 +33,7 @@
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
// TODO: Remove need for "saved* members
class ClangToolsSettings : public QObject class ClangToolsSettings : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -44,6 +45,8 @@ public:
int savedSimultaneousProcesses() const; int savedSimultaneousProcesses() const;
bool savedBuildBeforeAnalysis() const; bool savedBuildBeforeAnalysis() const;
Core::Id savedDiagnosticConfigId() const; Core::Id savedDiagnosticConfigId() const;
QString savedClangTidyExecutable() const;
QString savedClazyStandaloneExecutable() const;
int simultaneousProcesses() const; int simultaneousProcesses() const;
void setSimultaneousProcesses(int processes); void setSimultaneousProcesses(int processes);
@@ -54,6 +57,12 @@ public:
Core::Id diagnosticConfigId() const; Core::Id diagnosticConfigId() const;
void setDiagnosticConfigId(Core::Id id); void setDiagnosticConfigId(Core::Id id);
QString clangTidyExecutable() const;
void setClangTidyExecutable(const QString &path);
QString clazyStandaloneExecutable() const;
void setClazyStandaloneExecutable(const QString &path);
signals: signals:
void buildBeforeAnalysisChanged(bool checked) const; void buildBeforeAnalysisChanged(bool checked) const;
@@ -67,6 +76,10 @@ private:
int m_savedSimultaneousProcesses = -1; int m_savedSimultaneousProcesses = -1;
bool m_buildBeforeAnalysis = false; bool m_buildBeforeAnalysis = false;
bool m_savedBuildBeforeAnalysis= false; bool m_savedBuildBeforeAnalysis= false;
QString m_clangTidyExecutable;
QString m_savedClangTidyExecutable;
QString m_clazyStandaloneExecutable;
QString m_savedClazyStandaloneExecutable;
Core::Id m_diagnosticConfigId; Core::Id m_diagnosticConfigId;
Core::Id m_savedDiagnosticConfigId; Core::Id m_savedDiagnosticConfigId;
}; };

View File

@@ -26,6 +26,7 @@
#include "clangtoolsutils.h" #include "clangtoolsutils.h"
#include "clangtool.h" #include "clangtool.h"
#include "clangtoolsconstants.h"
#include "clangtoolsdiagnostic.h" #include "clangtoolsdiagnostic.h"
#include "clangtoolssettings.h" #include "clangtoolssettings.h"
@@ -70,5 +71,88 @@ void showHintAboutBuildBeforeAnalysis()
"ClangToolsDisablingBuildBeforeAnalysisHint"); "ClangToolsDisablingBuildBeforeAnalysisHint");
} }
bool isFileExecutable(const QString &filePath)
{
if (filePath.isEmpty())
return false;
const QFileInfo fileInfo(filePath);
return fileInfo.isFile() && fileInfo.isExecutable();
}
QString shippedClangTidyExecutable()
{
const QString shippedExecutable = Core::ICore::clangTidyExecutable(CLANG_BINDIR);
if (isFileExecutable(shippedExecutable))
return shippedExecutable;
return {};
}
QString shippedClazyStandaloneExecutable()
{
const QString shippedExecutable = Core::ICore::clazyStandaloneExecutable(CLANG_BINDIR);
if (isFileExecutable(shippedExecutable))
return shippedExecutable;
return {};
}
static QString fullPath(const QString &executable)
{
const QString hostExeSuffix = QLatin1String(QTC_HOST_EXE_SUFFIX);
const Qt::CaseSensitivity caseSensitivity = Utils::HostOsInfo::fileNameCaseSensitivity();
QString candidate = executable;
const bool hasSuffix = candidate.endsWith(hostExeSuffix, caseSensitivity);
const QFileInfo fileInfo = QFileInfo(candidate);
if (fileInfo.isAbsolute()) {
if (!hasSuffix)
candidate.append(hostExeSuffix);
} else {
const Utils::Environment environment = Utils::Environment::systemEnvironment();
const QString expandedPath = environment.searchInPath(candidate).toString();
if (!expandedPath.isEmpty())
candidate = expandedPath;
}
return candidate;
}
static QString findValidExecutable(const QStringList &candidates)
{
for (QString candidate : candidates) {
const QString expandedPath = fullPath(candidate);
if (isFileExecutable(expandedPath))
return expandedPath;
}
return {};
}
QString clangTidyExecutable()
{
const QString fromSettings = ClangToolsSettings::instance()->clangTidyExecutable();
if (!fromSettings.isEmpty())
return fullPath(fromSettings);
return findValidExecutable({
shippedClangTidyExecutable(),
Constants::CLANG_TIDY_EXECUTABLE_NAME,
});
}
QString clazyStandaloneExecutable()
{
const QString fromSettings = ClangToolsSettings::instance()->clazyStandaloneExecutable();
if (!fromSettings.isEmpty())
return fullPath(fromSettings);
return findValidExecutable({
shippedClazyStandaloneExecutable(),
qEnvironmentVariable("QTC_USE_CLAZY_STANDALONE_PATH"),
Constants::CLAZY_STANDALONE_EXECUTABLE_NAME,
});
}
} // namespace Internal } // namespace Internal
} // namespace ClangTools } // namespace ClangTools

View File

@@ -44,5 +44,13 @@ QString createFullLocationString(const Debugger::DiagnosticLocation &location);
QString hintAboutBuildBeforeAnalysis(); QString hintAboutBuildBeforeAnalysis();
void showHintAboutBuildBeforeAnalysis(); void showHintAboutBuildBeforeAnalysis();
bool isFileExecutable(const QString &filePath);
QString shippedClazyStandaloneExecutable();
QString clazyStandaloneExecutable();
QString shippedClangTidyExecutable();
QString clangTidyExecutable();
} // namespace Internal } // namespace Internal
} // namespace ClangTools } // namespace ClangTools

View File

@@ -28,8 +28,11 @@
#include "ui_basicsettingswidget.h" #include "ui_basicsettingswidget.h"
#include "ui_settingswidget.h" #include "ui_settingswidget.h"
#include "clangtoolsconstants.h"
#include "clangtoolsutils.h" #include "clangtoolsutils.h"
#include <coreplugin/icore.h>
#include <cpptools/clangdiagnosticconfigswidget.h> #include <cpptools/clangdiagnosticconfigswidget.h>
#include <cpptools/cppcodemodelsettings.h> #include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cpptoolsreuse.h> #include <cpptools/cpptoolsreuse.h>
@@ -37,18 +40,83 @@
#include <QDir> #include <QDir>
#include <QThread> #include <QThread>
#include <memory>
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
SettingsWidget::SettingsWidget( static void setupPathChooser(Utils::PathChooser *const chooser,
ClangToolsSettings *settings, const QString &promptDiaglogTitle,
QWidget *parent) const QString &placeHolderText,
const QString &pathFromSettings,
const QString &historyCompleterId,
std::function<void(const QString &path)> savePath)
{
chooser->setPromptDialogTitle(promptDiaglogTitle);
chooser->lineEdit()->setPlaceholderText(placeHolderText);
chooser->setPath(pathFromSettings);
chooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
chooser->setHistoryCompleter(historyCompleterId);
QObject::connect(chooser, &Utils::PathChooser::rawPathChanged, savePath),
chooser->setValidationFunction([chooser](Utils::FancyLineEdit *edit, QString *errorMessage) {
const QString currentFilePath = chooser->fileName().toString();
Utils::PathChooser pc;
Utils::PathChooser *helperPathChooser;
if (currentFilePath.isEmpty()) {
pc.setExpectedKind(chooser->expectedKind());
pc.setPath(edit->placeholderText());
helperPathChooser = &pc;
} else {
helperPathChooser = chooser;
}
return chooser->defaultValidationFunction()(helperPathChooser->lineEdit(), errorMessage);
});
}
SettingsWidget::SettingsWidget(ClangToolsSettings *settings, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, m_ui(new Ui::SettingsWidget) , m_ui(new Ui::SettingsWidget)
, m_settings(settings) , m_settings(settings)
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
//
// Group box "Executables"
//
QString placeHolderText = shippedClangTidyExecutable();
QString path = settings->clangTidyExecutable();
if (path.isEmpty() && placeHolderText.isEmpty())
path = Constants::CLANG_TIDY_EXECUTABLE_NAME;
setupPathChooser(m_ui->clangTidyPathChooser,
tr("Clang-Tidy Executable"),
placeHolderText,
path,
"ClangTools.ClangTidyExecutable.History",
[settings](const QString &path) { settings->setClangTidyExecutable(path); });
if (qEnvironmentVariable("QTC_USE_CLAZY_STANDALONE_PATH").isEmpty()) {
m_ui->clazyStandalonePathChooser->setVisible(false);
m_ui->clazyStandaloneLabel->setVisible(false);
} else {
placeHolderText = shippedClazyStandaloneExecutable();
path = settings->clazyStandaloneExecutable();
if (path.isEmpty() && placeHolderText.isEmpty())
path = Constants::CLAZY_STANDALONE_EXECUTABLE_NAME;
setupPathChooser(m_ui->clazyStandalonePathChooser,
tr("Clazy Executable"),
placeHolderText,
path,
"ClangTools.ClazyStandaloneExecutable.History",
[settings](const QString &path) {
settings->setClazyStandaloneExecutable(path);
});
}
//
// Group box "Run Options"
//
m_ui->simultaneousProccessesSpinBox->setValue(settings->savedSimultaneousProcesses()); m_ui->simultaneousProccessesSpinBox->setValue(settings->savedSimultaneousProcesses());
m_ui->simultaneousProccessesSpinBox->setMinimum(1); m_ui->simultaneousProccessesSpinBox->setMinimum(1);
m_ui->simultaneousProccessesSpinBox->setMaximum(QThread::idealThreadCount()); m_ui->simultaneousProccessesSpinBox->setMaximum(QThread::idealThreadCount());

View File

@@ -14,10 +14,39 @@
<string/> <string/>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Executables</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Clang-Tidy:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Utils::PathChooser" name="clangTidyPathChooser" native="true"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="clazyStandaloneLabel">
<property name="text">
<string>Clazy-Standalone:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Utils::PathChooser" name="clazyStandalonePathChooser" native="true"/>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">
<property name="title"> <property name="title">
<string>General</string> <string>Run Options</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
@@ -81,6 +110,12 @@
<extends>QWidget</extends> <extends>QWidget</extends>
<header>clangtools/basicsettingswidget.h</header> <header>clangtools/basicsettingswidget.h</header>
</customwidget> </customwidget>
<customwidget>
<class>Utils::PathChooser</class>
<extends>QWidget</extends>
<header location="global">utils/pathchooser.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections/> <connections/>

View File

@@ -495,6 +495,11 @@ QString ICore::clangTidyExecutable(const QString &clangBinDirectory)
return clangBinary("clang-tidy", clangBinDirectory); return clangBinary("clang-tidy", clangBinDirectory);
} }
QString ICore::clazyStandaloneExecutable(const QString &clangBinDirectory)
{
return clangBinary("clazy-standalone", clangBinDirectory);
}
static QString compilerString() static QString compilerString()
{ {
#if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too #if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too

View File

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