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

View File

@@ -310,7 +310,7 @@ void ClangToolRunWorker::start()
m_queue.clear();
for (const AnalyzeUnit &unit : unitsToProcess) {
for (auto creator : runnerCreators())
for (const RunnerCreator &creator : runnerCreators())
m_queue << QueueItem{unit, creator};
}
m_initialQueueSize = m_queue.count();
@@ -378,6 +378,18 @@ void ClangToolRunWorker::analyzeNextFile()
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\" [%2].")

View File

@@ -62,6 +62,7 @@ public:
QString name() const { return m_name; }
OutputFileFormat outputFileFormat() const { return m_outputFileFormat; }
QString executable() const { return m_executable; }
QString filePath() const { return m_filePath; }
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 CLANGTIDYCLAZY_RUN_MODE[] = "ClangTidyClazy.RunMode";
const char CLANG_TIDY_EXECUTABLE_NAME[] = "clang-tidy";
const char CLAZY_STANDALONE_EXECUTABLE_NAME[] = "clazy-standalone";
} // Constants
} // ClangTools

View File

@@ -38,6 +38,8 @@
static const char simultaneousProcessesKey[] = "simultaneousProcesses";
static const char buildBeforeAnalysisKey[] = "buildBeforeAnalysis";
static const char diagnosticConfigIdKey[] = "diagnosticConfigId";
static const char clangTidyExecutableKey[] = "clangTidyExecutable";
static const char clazyStandaloneExecutableKey[] = "clazyStandaloneExecutable";
namespace ClangTools {
namespace Internal {
@@ -106,6 +108,36 @@ void ClangToolsSettings::updateSavedBuildBeforeAnalysiIfRequired()
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()
{
QSettings *settings = Core::ICore::settings();
@@ -118,6 +150,11 @@ void ClangToolsSettings::readSettings()
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)));
if (!m_diagnosticConfigId.isValid())
m_diagnosticConfigId = "Builtin.TidyAndClazy";
@@ -135,10 +172,14 @@ void ClangToolsSettings::writeSettings()
settings->beginGroup(QString(Constants::SETTINGS_ID));
settings->setValue(QString(simultaneousProcessesKey), m_simultaneousProcesses);
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());
m_savedSimultaneousProcesses = m_simultaneousProcesses;
m_savedDiagnosticConfigId = m_diagnosticConfigId;
m_savedClangTidyExecutable = m_clangTidyExecutable;
m_savedClazyStandaloneExecutable = m_clazyStandaloneExecutable;
updateSavedBuildBeforeAnalysiIfRequired();
settings->endGroup();

View File

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

View File

@@ -26,6 +26,7 @@
#include "clangtoolsutils.h"
#include "clangtool.h"
#include "clangtoolsconstants.h"
#include "clangtoolsdiagnostic.h"
#include "clangtoolssettings.h"
@@ -70,5 +71,88 @@ void showHintAboutBuildBeforeAnalysis()
"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 ClangTools

View File

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

View File

@@ -28,8 +28,11 @@
#include "ui_basicsettingswidget.h"
#include "ui_settingswidget.h"
#include "clangtoolsconstants.h"
#include "clangtoolsutils.h"
#include <coreplugin/icore.h>
#include <cpptools/clangdiagnosticconfigswidget.h>
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cpptoolsreuse.h>
@@ -37,18 +40,83 @@
#include <QDir>
#include <QThread>
#include <memory>
namespace ClangTools {
namespace Internal {
SettingsWidget::SettingsWidget(
ClangToolsSettings *settings,
QWidget *parent)
static void setupPathChooser(Utils::PathChooser *const chooser,
const QString &promptDiaglogTitle,
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)
, m_ui(new Ui::SettingsWidget)
, m_settings(settings)
{
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->setMinimum(1);
m_ui->simultaneousProccessesSpinBox->setMaximum(QThread::idealThreadCount());

View File

@@ -14,10 +14,39 @@
<string/>
</property>
<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>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>General</string>
<string>Run Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
@@ -81,6 +110,12 @@
<extends>QWidget</extends>
<header>clangtools/basicsettingswidget.h</header>
</customwidget>
<customwidget>
<class>Utils::PathChooser</class>
<extends>QWidget</extends>
<header location="global">utils/pathchooser.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@@ -495,6 +495,11 @@ QString ICore::clangTidyExecutable(const QString &clangBinDirectory)
return clangBinary("clang-tidy", clangBinDirectory);
}
QString ICore::clazyStandaloneExecutable(const QString &clangBinDirectory)
{
return clangBinary("clazy-standalone", clangBinDirectory);
}
static QString compilerString()
{
#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 clangExecutable(const QString &clangBinDirectory);
static QString clangTidyExecutable(const QString &clangBinDirectory);
static QString clazyStandaloneExecutable(const QString &clangBinDirectory);
static QString clangIncludeDirectory(const QString &clangVersion,
const QString &clangResourceDirectory);