forked from qt-creator/qt-creator
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:
@@ -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)
|
||||
|
@@ -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].")
|
||||
|
@@ -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; }
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
};
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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());
|
||||
|
@@ -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/>
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user