ClangTools: Prefer .clang-tidy file by default

... and move this setting outside the diagnostic config.

Fixes: QTCREATORBUG-28852
Change-Id: Ie3b19ba7bec2bc96451f3216fa06a6941cad4c94
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2023-04-11 12:49:21 +02:00
parent de0e0fab18
commit 4028777743
16 changed files with 83 additions and 79 deletions

View File

@@ -98,15 +98,12 @@ ClangDiagnosticConfig diagnosticConfig()
return warningsConfigForProject(project);
}
bool isDiagnosticConfigChangable(Project *project, const ClangDiagnostic &diagnostic)
static bool isDiagnosticConfigChangable(Project *project)
{
if (!project)
return false;
const ClangDiagnosticConfig config = diagnosticConfig();
if (config.clangTidyMode() == ClangDiagnosticConfig::TidyMode::UseConfigFile
&& diagnosticType(diagnostic) == DiagnosticType::Tidy) {
if (diagnosticConfig().useBuildSystemWarnings())
return false;
}
return true;
}
@@ -308,7 +305,7 @@ ClangdTextMark::ClangdTextMark(const FilePath &filePath,
// Remove diagnostic warning action
Project *project = projectForCurrentEditor();
if (project && isDiagnosticConfigChangable(project, diag)) {
if (project && isDiagnosticConfigChangable(project)) {
action = new QAction();
action->setIcon(Icons::BROKEN.icon());
action->setToolTip(Tr::tr("Disable Diagnostic in Current Project"));

View File

@@ -858,13 +858,13 @@ static CheckResult canAnalyze()
{
const ClangDiagnosticConfig config = diagnosticConfig(runSettings().diagnosticConfigId());
if (config.isEnabled(ClangToolType::Tidy)
if (toolEnabled(ClangToolType::Tidy, config, runSettings())
&& !toolExecutable(ClangToolType::Tidy).isExecutableFile()) {
return {CheckResult::InvalidTidyExecutable,
Tr::tr("Set a valid Clang-Tidy executable.")};
}
if (config.isEnabled(ClangToolType::Clazy)
if (toolEnabled(ClangToolType::Clazy, config, runSettings())
&& !toolExecutable(ClangToolType::Clazy).isExecutableFile()) {
return {CheckResult::InvalidClazyExecutable,
Tr::tr("Set a valid Clazy-Standalone executable.")};

View File

@@ -185,7 +185,11 @@ void ClangToolRunWorker::start()
using namespace Tasking;
QList<TaskItem> tasks{ParallelLimit(qMax(1, m_runSettings.parallelJobs()))};
for (const AnalyzeUnit &unit : std::as_const(unitsToProcess)) {
const AnalyzeInputData input{tool, m_diagnosticConfig, m_temporaryDir.path(),
if (!m_diagnosticConfig.isEnabled(tool)
&& !m_runSettings.hasConfigFileForSourceFile(unit.file)) {
continue;
}
const AnalyzeInputData input{tool, m_runSettings, m_diagnosticConfig, m_temporaryDir.path(),
m_environment, unit};
const auto setupHandler = [this, unit, tool] {
const QString filePath = unit.file.toUserOutput();

View File

@@ -52,21 +52,22 @@ static bool isClMode(const QStringList &options)
return options.contains("--driver-mode=cl");
}
static QStringList checksArguments(ClangToolType tool,
const ClangDiagnosticConfig &diagnosticConfig)
static QStringList checksArguments(const AnalyzeInputData &input)
{
if (tool == ClangToolType::Tidy) {
const ClangDiagnosticConfig::TidyMode tidyMode = diagnosticConfig.clangTidyMode();
// The argument "-config={}" stops stating/evaluating the .clang-tidy file.
if (tidyMode == ClangDiagnosticConfig::TidyMode::UseDefaultChecks)
return {"-config={}", "-checks=-clang-diagnostic-*"};
if (tidyMode == ClangDiagnosticConfig::TidyMode::UseCustomChecks)
return {"-config=" + diagnosticConfig.clangTidyChecksAsJson()};
if (input.tool == ClangToolType::Tidy) {
if (input.runSettings.hasConfigFileForSourceFile(input.unit.file))
return {"--warnings-as-errors=-*", "-checks=-clang-diagnostic-*"};
switch (input.config.clangTidyMode()) {
case ClangDiagnosticConfig::TidyMode::UseDefaultChecks:
// The argument "-config={}" stops stating/evaluating the .clang-tidy file.
return {"-config={}", "-checks=-clang-diagnostic-*"};
case ClangDiagnosticConfig::TidyMode::UseCustomChecks:
return {"-config=" + input.config.clangTidyChecksAsJson()};
}
const QString clazyChecks = diagnosticConfig.checks(ClangToolType::Clazy);
}
const QString clazyChecks = input.config.checks(ClangToolType::Clazy);
if (!clazyChecks.isEmpty())
return {"-checks=" + diagnosticConfig.checks(ClangToolType::Clazy)};
return {"-checks=" + input.config.checks(ClangToolType::Clazy)};
return {};
}
@@ -148,7 +149,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input,
const ClangToolStorage &data = *storage;
const QStringList args = checksArguments(input.tool, input.config)
const QStringList args = checksArguments(input)
+ mainToolArguments(data)
+ QStringList{"--"}
+ clangArguments(input.config, input.unit.arguments);

View File

@@ -4,6 +4,7 @@
#pragma once
#include "clangfileinfo.h"
#include "clangtoolssettings.h"
#include <cppeditor/clangdiagnosticconfig.h>
@@ -28,6 +29,7 @@ using AnalyzeUnits = QList<AnalyzeUnit>;
struct AnalyzeInputData
{
CppEditor::ClangToolType tool = CppEditor::ClangToolType::Tidy;
RunSettings runSettings;
CppEditor::ClangDiagnosticConfig config;
Utils::FilePath outputDirPath;
Utils::Environment environment;

View File

@@ -313,9 +313,8 @@ bool DiagnosticView::disableChecksEnabled() const
if (!activeConfig.id().isValid())
return false;
// If all selected diagnostics come from clang-tidy and the active config is controlled
// by a .clang-tidy file, then we do not offer the action.
if (activeConfig.clangTidyMode() != ClangDiagnosticConfig::TidyMode::UseConfigFile)
// If all selected diagnostics come from clang-tidy and we prefer a .clang-tidy file, then we do not offer the action.
if (!settings->runSettings().preferConfigFile())
return true;
return Utils::anyOf(indexes, [this](const QModelIndex &index) {
return model()->data(index).toString().startsWith("clazy-");

View File

@@ -27,6 +27,7 @@ const char clangTidyExecutableKey[] = "ClangTidyExecutable";
const char clazyStandaloneExecutableKey[] = "ClazyStandaloneExecutable";
const char parallelJobsKey[] = "ParallelJobs";
const char preferConfigFileKey[] = "PreferConfigFile";
const char buildBeforeAnalysisKey[] = "BuildBeforeAnalysis";
const char analyzeOpenFilesKey[] = "AnalyzeOpenFiles";
const char oldDiagnosticConfigIdKey[] = "diagnosticConfigId";
@@ -46,6 +47,7 @@ void RunSettings::fromMap(const QVariantMap &map, const QString &prefix)
{
m_diagnosticConfigId = Id::fromSetting(map.value(prefix + diagnosticConfigIdKey));
m_parallelJobs = map.value(prefix + parallelJobsKey).toInt();
m_preferConfigFile = map.value(prefix + preferConfigFileKey).toBool();
m_buildBeforeAnalysis = map.value(prefix + buildBeforeAnalysisKey).toBool();
m_analyzeOpenFiles = map.value(prefix + analyzeOpenFilesKey).toBool();
}
@@ -54,6 +56,7 @@ void RunSettings::toMap(QVariantMap &map, const QString &prefix) const
{
map.insert(prefix + diagnosticConfigIdKey, m_diagnosticConfigId.toSetting());
map.insert(prefix + parallelJobsKey, m_parallelJobs);
map.insert(prefix + preferConfigFileKey, m_preferConfigFile);
map.insert(prefix + buildBeforeAnalysisKey, m_buildBeforeAnalysis);
map.insert(prefix + analyzeOpenFilesKey, m_analyzeOpenFiles);
}
@@ -69,10 +72,23 @@ bool RunSettings::operator==(const RunSettings &other) const
{
return m_diagnosticConfigId == other.m_diagnosticConfigId
&& m_parallelJobs == other.m_parallelJobs
&& m_preferConfigFile == other.m_preferConfigFile
&& m_buildBeforeAnalysis == other.m_buildBeforeAnalysis
&& m_analyzeOpenFiles == other.m_analyzeOpenFiles;
}
bool RunSettings::hasConfigFileForSourceFile(const Utils::FilePath &sourceFile) const
{
if (!preferConfigFile())
return false;
for (FilePath parentDir = sourceFile.parentDir(); !parentDir.isEmpty();
parentDir = parentDir.parentDir()) {
if (parentDir.resolvePath(QLatin1String(".clang-tidy")).isReadableFile())
return true;
}
return false;
}
ClangToolsSettings::ClangToolsSettings()
{
readSettings();
@@ -139,6 +155,7 @@ void ClangToolsSettings::readSettings()
QVariantMap defaults;
defaults.insert(diagnosticConfigIdKey, defaultDiagnosticId().toSetting());
defaults.insert(parallelJobsKey, m_runSettings.parallelJobs());
defaults.insert(preferConfigFileKey, m_runSettings.preferConfigFile());
defaults.insert(buildBeforeAnalysisKey, m_runSettings.buildBeforeAnalysis());
defaults.insert(analyzeOpenFilesKey, m_runSettings.analyzeOpenFiles());
map = defaults;

View File

@@ -31,6 +31,9 @@ public:
Utils::Id diagnosticConfigId() const;
void setDiagnosticConfigId(const Utils::Id &id) { m_diagnosticConfigId = id; }
bool preferConfigFile() const { return m_preferConfigFile; }
void setPreferConfigFile(bool yesno) { m_preferConfigFile = yesno; }
bool buildBeforeAnalysis() const { return m_buildBeforeAnalysis; }
void setBuildBeforeAnalysis(bool yesno) { m_buildBeforeAnalysis = yesno; }
@@ -42,9 +45,12 @@ public:
bool operator==(const RunSettings &other) const;
bool hasConfigFileForSourceFile(const Utils::FilePath &sourceFile) const;
private:
Utils::Id m_diagnosticConfigId;
int m_parallelJobs = -1;
bool m_preferConfigFile = true;
bool m_buildBeforeAnalysis = true;
bool m_analyzeOpenFiles = true;
};

View File

@@ -343,5 +343,13 @@ QString clazyDocUrl(const QString &check)
return QString::fromLatin1(urlTemplate).arg(versionString, check);
}
bool toolEnabled(CppEditor::ClangToolType type, const ClangDiagnosticConfig &config,
const RunSettings &runSettings)
{
if (type == ClangToolType::Tidy && runSettings.preferConfigFile())
return true;
return config.isEnabled(type);
}
} // namespace Internal
} // namespace ClangTools

View File

@@ -17,6 +17,7 @@ namespace Utils { class FilePath; }
namespace ClangTools {
namespace Internal {
class RunSettings;
QString clangTidyDocUrl(const QString &check);
QString clazyDocUrl(const QString &check);
@@ -47,6 +48,8 @@ Utils::FilePath toolShippedExecutable(CppEditor::ClangToolType tool);
Utils::FilePath toolExecutable(CppEditor::ClangToolType tool);
Utils::FilePath toolFallbackExecutable(CppEditor::ClangToolType tool);
QString clangToolName(CppEditor::ClangToolType tool);
bool toolEnabled(CppEditor::ClangToolType type, const CppEditor::ClangDiagnosticConfig &config,
const RunSettings &runSettings);
bool isVFSOverlaySupported(const Utils::FilePath &executable);

View File

@@ -56,7 +56,6 @@ QString removeClazyCheck(const QString &checks, const QString &check);
class TidyChecksWidget : public QWidget
{
public:
QComboBox *tidyMode;
QPushButton *plainTextEditButton;
FancyLineEdit *filterLineEdit;
QTreeView *checksPrefixesTree;
@@ -65,10 +64,6 @@ public:
TidyChecksWidget()
{
tidyMode = new QComboBox;
tidyMode->addItem(Tr::tr("Select Checks"));
tidyMode->addItem(Tr::tr("Use .clang-tidy config file"));
plainTextEditButton = new QPushButton(Tr::tr("Edit Checks as String..."));
filterLineEdit = new FancyLineEdit;
@@ -104,7 +99,7 @@ public:
}.attachTo(invalidExecutablePage, WithoutMargins);
Column {
Row { tidyMode, plainTextEditButton, filterLineEdit },
Row { plainTextEditButton, filterLineEdit },
stackedWidget,
}.attachTo(this);
}
@@ -1107,17 +1102,6 @@ void DiagnosticConfigsWidget::syncClangTidyWidgets(const ClangDiagnosticConfig &
disconnectClangTidyItemChanged();
const ClangDiagnosticConfig::TidyMode tidyMode = config.clangTidyMode();
switch (tidyMode) {
case ClangDiagnosticConfig::TidyMode::UseConfigFile:
m_tidyChecks->tidyMode->setCurrentIndex(1);
m_tidyChecks->plainTextEditButton->setVisible(false);
m_tidyChecks->filterLineEdit->setVisible(false);
m_tidyChecks->stackedWidget->setCurrentIndex(TidyPages::EmptyPage);
break;
case ClangDiagnosticConfig::TidyMode::UseCustomChecks:
case ClangDiagnosticConfig::TidyMode::UseDefaultChecks:
m_tidyChecks->tidyMode->setCurrentIndex(0);
if (m_tidyInfo.supportedChecks.isEmpty()) {
m_tidyChecks->plainTextEditButton->setVisible(false);
m_tidyChecks->filterLineEdit->setVisible(false);
@@ -1128,11 +1112,8 @@ void DiagnosticConfigsWidget::syncClangTidyWidgets(const ClangDiagnosticConfig &
m_tidyChecks->stackedWidget->setCurrentIndex(TidyPages::ChecksPage);
syncTidyChecksToTree(config);
}
break;
}
const bool enabled = !config.isReadOnly();
m_tidyChecks->tidyMode->setEnabled(enabled);
m_tidyChecks->plainTextEditButton->setText(enabled ? Tr::tr("Edit Checks as String...")
: Tr::tr("View Checks as String..."));
m_tidyTreeModel->setEnabled(enabled);
@@ -1189,16 +1170,12 @@ void DiagnosticConfigsWidget::syncExtraWidgets(const ClangDiagnosticConfig &conf
void DiagnosticConfigsWidget::connectClangTidyItemChanged()
{
connect(m_tidyChecks->tidyMode, &QComboBox::currentIndexChanged,
this, &DiagnosticConfigsWidget::onClangTidyModeChanged);
connect(m_tidyTreeModel.get(), &TidyChecksTreeModel::dataChanged,
this, &DiagnosticConfigsWidget::onClangTidyTreeChanged);
}
void DiagnosticConfigsWidget::disconnectClangTidyItemChanged()
{
disconnect(m_tidyChecks->tidyMode, &QComboBox::currentIndexChanged,
this, &DiagnosticConfigsWidget::onClangTidyModeChanged);
disconnect(m_tidyTreeModel.get(), &TidyChecksTreeModel::dataChanged,
this, &DiagnosticConfigsWidget::onClangTidyTreeChanged);
}
@@ -1215,18 +1192,6 @@ void DiagnosticConfigsWidget::disconnectClazyItemChanged()
this, &DiagnosticConfigsWidget::onClazyTreeChanged);
}
void DiagnosticConfigsWidget::onClangTidyModeChanged(int index)
{
const ClangDiagnosticConfig::TidyMode tidyMode
= index == 0 ? ClangDiagnosticConfig::TidyMode::UseCustomChecks
: ClangDiagnosticConfig::TidyMode::UseConfigFile;
ClangDiagnosticConfig config = currentConfig();
config.setClangTidyMode(tidyMode);
updateConfig(config);
syncClangTidyWidgets(config);
}
void DiagnosticConfigsWidget::onClangTidyTreeChanged()
{
ClangDiagnosticConfig config = currentConfig();
@@ -1330,7 +1295,7 @@ void disableChecks(const QList<Diagnostic> &diagnostics)
}
config.setChecks(ClangToolType::Clazy,
removeClazyCheck(config.checks(ClangToolType::Clazy), diag.name));
} else if (config.clangTidyMode() != ClangDiagnosticConfig::TidyMode::UseConfigFile) {
} else if (!settings->runSettings().preferConfigFile()){
if (config.clangTidyMode() == ClangDiagnosticConfig::TidyMode::UseDefaultChecks) {
config.setClangTidyMode(ClangDiagnosticConfig::TidyMode::UseCustomChecks);
const ClangTidyInfo tidyInfo(toolExecutable(ClangToolType::Tidy));

View File

@@ -41,7 +41,6 @@ private:
void syncClazyWidgets(const CppEditor::ClangDiagnosticConfig &config);
void syncClazyChecksGroupBox();
void onClangTidyModeChanged(int index);
void onClangTidyTreeChanged();
void onClazyTreeChanged();

View File

@@ -190,15 +190,17 @@ void DocumentClangToolRunner::run()
const Environment env = projectBuildEnvironment(project);
using namespace Tasking;
QList<TaskItem> tasks{parallel};
const auto addClangTool = [this, &config, &env, &tasks](ClangToolType tool) {
if (!config.isEnabled(tool))
const auto addClangTool = [this, &runSettings, &config, &env, &tasks](ClangToolType tool) {
if (!toolEnabled(tool, config, runSettings))
return;
if (!config.isEnabled(tool) && !runSettings.hasConfigFileForSourceFile(m_fileInfo.file))
return;
const FilePath executable = toolExecutable(tool);
const auto [includeDir, clangVersion] = getClangIncludeDirAndVersion(executable);
if (!executable.isExecutableFile() || includeDir.isEmpty() || clangVersion.isEmpty())
return;
const AnalyzeUnit unit(m_fileInfo, includeDir, clangVersion);
const AnalyzeInputData input{tool, config, m_temporaryDir.path(), env, unit,
const AnalyzeInputData input{tool, runSettings, config, m_temporaryDir.path(), env, unit,
vfso().overlayFilePath().toString()};
const auto setupHandler = [this, executable] {
return !m_document->isModified() || isVFSOverlaySupported(executable);

View File

@@ -31,11 +31,9 @@ RunSettingsWidget::RunSettingsWidget(QWidget *parent)
resize(383, 125);
m_diagnosticWidget = new ClangDiagnosticConfigsSelectionWidget;
m_preferConfigFile = new QCheckBox(Tr::tr("Prefer .clang-tidy file, if present"));
m_buildBeforeAnalysis = new QCheckBox(Tr::tr("Build the project before analysis"));
m_analyzeOpenFiles = new QCheckBox(Tr::tr("Analyze open files"));
m_parallelJobsSpinBox = new QSpinBox;
m_parallelJobsSpinBox->setRange(1, 32);
@@ -47,6 +45,7 @@ RunSettingsWidget::RunSettingsWidget(QWidget *parent)
title(Tr::tr("Run Options")),
Column {
m_diagnosticWidget,
m_preferConfigFile,
m_buildBeforeAnalysis,
m_analyzeOpenFiles,
Row { Tr::tr("Parallel jobs:"), m_parallelJobsSpinBox, st },
@@ -99,6 +98,9 @@ void RunSettingsWidget::fromSettings(const RunSettings &s)
connect(m_diagnosticWidget, &ClangDiagnosticConfigsSelectionWidget::changed,
this, &RunSettingsWidget::changed);
m_preferConfigFile->setChecked(s.preferConfigFile());
connect(m_preferConfigFile, &QCheckBox::toggled, this, &RunSettingsWidget::changed);
disconnect(m_buildBeforeAnalysis, 0, 0, 0);
m_buildBeforeAnalysis->setToolTip(hintAboutBuildBeforeAnalysis());
m_buildBeforeAnalysis->setCheckState(s.buildBeforeAnalysis() ? Qt::Checked : Qt::Unchecked);
@@ -115,13 +117,13 @@ void RunSettingsWidget::fromSettings(const RunSettings &s)
connect(m_parallelJobsSpinBox, &QSpinBox::valueChanged, this, &RunSettingsWidget::changed);
m_analyzeOpenFiles->setChecked(s.analyzeOpenFiles());
connect(m_analyzeOpenFiles, &QCheckBox::toggled, this, &RunSettingsWidget::changed);
}
RunSettings RunSettingsWidget::toSettings() const
{
RunSettings s;
s.setDiagnosticConfigId(m_diagnosticWidget->currentConfigId());
s.setPreferConfigFile(m_preferConfigFile->isChecked());
s.setBuildBeforeAnalysis(m_buildBeforeAnalysis->checkState() == Qt::CheckState::Checked);
s.setParallelJobs(m_parallelJobsSpinBox->value());
s.setAnalyzeOpenFiles(m_analyzeOpenFiles->checkState() == Qt::CheckState::Checked);

View File

@@ -37,6 +37,7 @@ signals:
private:
CppEditor::ClangDiagnosticConfigsSelectionWidget *m_diagnosticWidget;
QCheckBox *m_preferConfigFile;
QCheckBox *m_buildBeforeAnalysis;
QCheckBox *m_analyzeOpenFiles;
QSpinBox *m_parallelJobsSpinBox;

View File

@@ -42,10 +42,8 @@ public:
// Clang-Tidy
enum class TidyMode
{
// Disabled, // Used by Qt Creator 4.10 and below.
UseCustomChecks = 1,
UseConfigFile,
UseDefaultChecks,
UseDefaultChecks = 3,
};
TidyMode clangTidyMode() const;
void setClangTidyMode(TidyMode mode);