forked from qt-creator/qt-creator
ClangTools: Allow to disable a specific type of diagnostic
... from the results list. This is much more convenient for the user than having to locate the diagnostic in the settings first. This patch deals with the global settings. We plan to offer the same for project-level settings in a follow-up patch. Task-number: QTCREATORBUG-24852 Change-Id: I7a97189c393048b98b9c2cdb6f21861a34670e8f Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -27,13 +27,16 @@
|
||||
|
||||
#include "clangtoolsdiagnosticmodel.h"
|
||||
#include "clangtoolsprojectsettings.h"
|
||||
#include "clangtoolssettings.h"
|
||||
#include "clangtoolsutils.h"
|
||||
#include "diagnosticconfigswidget.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/manhattanstyle.h>
|
||||
|
||||
#include <debugger/analyzer/diagnosticlocation.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/theme/theme.h>
|
||||
@@ -45,7 +48,11 @@
|
||||
#include <QHeaderView>
|
||||
#include <QPainter>
|
||||
#include <QSet>
|
||||
#include <QUuid>
|
||||
|
||||
#include <set>
|
||||
|
||||
using namespace CppTools;
|
||||
using namespace Debugger;
|
||||
|
||||
namespace ClangTools {
|
||||
@@ -166,6 +173,10 @@ DiagnosticView::DiagnosticView(QWidget *parent)
|
||||
connect(m_suppressAction, &QAction::triggered,
|
||||
this, &DiagnosticView::suppressCurrentDiagnostic);
|
||||
|
||||
m_disableGloballyAction = new QAction(this);
|
||||
connect(m_disableGloballyAction, &QAction::triggered,
|
||||
this, &DiagnosticView::disableCurrentDiagnosticGlobally);
|
||||
|
||||
installEventFilter(this);
|
||||
|
||||
setStyle(m_style);
|
||||
@@ -228,6 +239,55 @@ void DiagnosticView::suppressCurrentDiagnostic()
|
||||
filterModel->addSuppressedDiagnostics(diags);
|
||||
}
|
||||
|
||||
void DiagnosticView::disableCurrentDiagnosticGlobally()
|
||||
{
|
||||
ClangToolsSettings * const settings = ClangToolsSettings::instance();
|
||||
ClangDiagnosticConfigs configs = settings->diagnosticConfigs();
|
||||
ClangDiagnosticConfig config = Utils::findOrDefault(configs,
|
||||
[settings](const ClangDiagnosticConfig &c) {
|
||||
return c.id() == settings->runSettings().diagnosticConfigId();
|
||||
});
|
||||
const bool defaultWasActive = !config.id().isValid();
|
||||
if (defaultWasActive) {
|
||||
QTC_ASSERT(configs.isEmpty(), return);
|
||||
config = builtinConfig();
|
||||
config.setIsReadOnly(false);
|
||||
config.setId(Utils::Id::fromString(QUuid::createUuid().toString()));
|
||||
config.setDisplayName(tr("Custom Configuration"));
|
||||
configs << config;
|
||||
}
|
||||
|
||||
std::set<QString> handledNames;
|
||||
const QModelIndexList indexes = selectionModel()->selectedRows();
|
||||
for (const QModelIndex &index : indexes) {
|
||||
const Diagnostic diag = model()->data(index, ClangToolsDiagnosticModel::DiagnosticRole)
|
||||
.value<Diagnostic>();
|
||||
if (!diag.isValid())
|
||||
continue;
|
||||
if (!handledNames.insert(diag.name).second)
|
||||
continue;
|
||||
|
||||
if (diag.name.startsWith("clazy-")) {
|
||||
config.setClazyMode(ClangDiagnosticConfig::ClazyMode::UseCustomChecks);
|
||||
config.setClazyChecks(removeClazyCheck(config.clazyChecks(), diag.name));
|
||||
} else if (config.clangTidyMode() != ClangDiagnosticConfig::TidyMode::UseConfigFile) {
|
||||
config.setClangTidyMode(ClangDiagnosticConfig::TidyMode::UseCustomChecks);
|
||||
config.setClangTidyChecks(removeClangTidyCheck(config.clangTidyChecks(), diag.name));
|
||||
}
|
||||
}
|
||||
|
||||
if (!defaultWasActive) {
|
||||
for (ClangDiagnosticConfig &c : configs) {
|
||||
if (c.id() == config.id()) {
|
||||
c = config;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
settings->setDiagnosticConfigs(configs);
|
||||
settings->writeSettings();
|
||||
}
|
||||
|
||||
void DiagnosticView::goNext()
|
||||
{
|
||||
const QModelIndex currentIndex = selectionModel()->currentIndex();
|
||||
@@ -278,6 +338,39 @@ QModelIndex DiagnosticView::getTopLevelIndex(const QModelIndex &index, Direction
|
||||
return model()->index(row, 0);
|
||||
}
|
||||
|
||||
bool DiagnosticView::disableGloballyEnabled() const
|
||||
{
|
||||
const QList<QModelIndex> indexes = selectionModel()->selectedIndexes();
|
||||
if (indexes.isEmpty())
|
||||
return false;
|
||||
if (!Utils::anyOf(indexes, &QModelIndex::isValid))
|
||||
return false;
|
||||
|
||||
ClangToolsSettings * const settings = ClangToolsSettings::instance();
|
||||
const ClangDiagnosticConfigs configs = settings->diagnosticConfigs();
|
||||
const ClangDiagnosticConfig activeConfig = Utils::findOrDefault(configs,
|
||||
[settings](const ClangDiagnosticConfig &c) {
|
||||
return c.id() == settings->runSettings().diagnosticConfigId();
|
||||
});
|
||||
|
||||
// If the user has not created any custom configuration yet, then we'll do that for
|
||||
// them as an act of kindness. But if custom configurations exist and the default
|
||||
// (read-only) one is active, then we don't offer the action, as it's not clear what
|
||||
// exactly we should do there.
|
||||
if (configs.isEmpty())
|
||||
return true;
|
||||
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)
|
||||
return true;
|
||||
return Utils::anyOf(indexes, [this](const QModelIndex &index) {
|
||||
return model()->data(index).toString().startsWith("clazy-");
|
||||
});
|
||||
}
|
||||
|
||||
QList<QAction *> DiagnosticView::customActions() const
|
||||
{
|
||||
const QModelIndex currentIndex = selectionModel()->currentIndex();
|
||||
@@ -292,6 +385,9 @@ QList<QAction *> DiagnosticView::customActions() const
|
||||
m_suppressAction->setEnabled(isDiagnosticItem || hasMultiSelection);
|
||||
m_suppressAction->setText(hasMultiSelection ? tr("Suppress Selected Diagnostics")
|
||||
: tr("Suppress This Diagnostic"));
|
||||
m_disableGloballyAction->setEnabled(disableGloballyEnabled());
|
||||
m_disableGloballyAction->setText(hasMultiSelection ? tr("Disable Selected Diagnostics Globally")
|
||||
: tr("Disable This Diagnostic Globally"));
|
||||
|
||||
return {
|
||||
m_help,
|
||||
@@ -302,6 +398,7 @@ QList<QAction *> DiagnosticView::customActions() const
|
||||
m_filterOutCurrentKind,
|
||||
m_separator2,
|
||||
m_suppressAction,
|
||||
m_disableGloballyAction
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -61,11 +61,14 @@ private:
|
||||
|
||||
void openEditorForCurrentIndex();
|
||||
void suppressCurrentDiagnostic();
|
||||
void disableCurrentDiagnosticGlobally();
|
||||
enum Direction { Next = 1, Previous = -1 };
|
||||
QModelIndex getIndex(const QModelIndex &index, Direction direction) const;
|
||||
QModelIndex getTopLevelIndex(const QModelIndex &index, Direction direction) const;
|
||||
|
||||
private:
|
||||
bool disableGloballyEnabled() const;
|
||||
|
||||
QAction *m_help = nullptr;
|
||||
|
||||
QAction *m_showFilter = nullptr;
|
||||
@@ -74,6 +77,7 @@ private:
|
||||
QAction *m_filterOutCurrentKind = nullptr;
|
||||
|
||||
QAction *m_suppressAction = nullptr;
|
||||
QAction *m_disableGloballyAction = nullptr;
|
||||
|
||||
QAction *m_separator = nullptr;
|
||||
QAction *m_separator2 = nullptr;
|
||||
|
@@ -256,6 +256,11 @@ QString clazyStandaloneExecutable()
|
||||
}
|
||||
|
||||
static void addBuiltinConfigs(ClangDiagnosticConfigsModel &model)
|
||||
{
|
||||
model.appendOrUpdate(builtinConfig());
|
||||
}
|
||||
|
||||
ClangDiagnosticConfig builtinConfig()
|
||||
{
|
||||
ClangDiagnosticConfig config;
|
||||
config.setId(Constants::DIAG_CONFIG_TIDY_AND_CLAZY);
|
||||
@@ -265,8 +270,7 @@ static void addBuiltinConfigs(ClangDiagnosticConfigsModel &model)
|
||||
config.setClangOptions({"-w"}); // Do not emit any clang-only warnings
|
||||
config.setClangTidyMode(ClangDiagnosticConfig::TidyMode::UseDefaultChecks);
|
||||
config.setClazyMode(ClangDiagnosticConfig::ClazyMode::UseDefaultChecks);
|
||||
|
||||
model.appendOrUpdate(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
ClangDiagnosticConfigsModel diagnosticConfigsModel(const ClangDiagnosticConfigs &customConfigs)
|
||||
|
@@ -57,6 +57,8 @@ QString createDiagnosticToolTipString(
|
||||
Utils::optional<FixitStatus> status = Utils::nullopt,
|
||||
bool showSteps = true);
|
||||
|
||||
CppTools::ClangDiagnosticConfig builtinConfig();
|
||||
|
||||
QString createFullLocationString(const Debugger::DiagnosticLocation &location);
|
||||
|
||||
QString hintAboutBuildBeforeAnalysis();
|
||||
|
@@ -25,6 +25,9 @@
|
||||
|
||||
#include "diagnosticconfigswidget.h"
|
||||
|
||||
#include "clangtoolsutils.h"
|
||||
#include "executableinfo.h"
|
||||
|
||||
#include "ui_clazychecks.h"
|
||||
#include "ui_tidychecks.h"
|
||||
|
||||
@@ -266,8 +269,40 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex indexForName(const QString &name) const
|
||||
{
|
||||
return indexForName(QModelIndex(), name);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_enabled = true;
|
||||
|
||||
private:
|
||||
QModelIndex indexForName(const QModelIndex ¤t, const QString &name) const
|
||||
{
|
||||
QString nodeName;
|
||||
QString remainingName = name;
|
||||
if (current.isValid()) {
|
||||
nodeName = data(current).toString();
|
||||
if (nodeName == name)
|
||||
return current;
|
||||
if (nodeName.endsWith('*'))
|
||||
nodeName.chop(1);
|
||||
if (!name.startsWith(nodeName)) {
|
||||
if (!nodeName.contains("Level"))
|
||||
return {};
|
||||
} else {
|
||||
remainingName = name.mid(nodeName.length());
|
||||
}
|
||||
}
|
||||
const int childCount = rowCount(current);
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
const QModelIndex theIndex = indexForName(index(i, 0, current), remainingName);
|
||||
if (theIndex.isValid())
|
||||
return theIndex;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
static void openUrl(QAbstractItemModel *model, const QModelIndex &index)
|
||||
@@ -958,6 +993,30 @@ void DiagnosticConfigsWidget::syncClazyChecksGroupBox()
|
||||
m_clazyChecks->checksGroupBox->setTitle(title);
|
||||
}
|
||||
|
||||
QString removeClangTidyCheck(const QString &checks, const QString &check)
|
||||
{
|
||||
const ClangTidyInfo tidyInfo(clangTidyExecutable());
|
||||
TidyChecksTreeModel model(tidyInfo.supportedChecks);
|
||||
model.selectChecks(checks);
|
||||
const QModelIndex index = model.indexForName(check);
|
||||
if (!index.isValid())
|
||||
return checks;
|
||||
model.setData(index, false, Qt::CheckStateRole);
|
||||
return model.selectedChecks();
|
||||
}
|
||||
|
||||
QString removeClazyCheck(const QString &checks, const QString &check)
|
||||
{
|
||||
const ClazyStandaloneInfo clazyInfo(clazyStandaloneExecutable());
|
||||
ClazyChecksTreeModel model(clazyInfo.supportedChecks);
|
||||
model.enableChecks(checks.split(',', Qt::SkipEmptyParts));
|
||||
const QModelIndex index = model.indexForName(check.mid(QString("clazy-").length()));
|
||||
if (!index.isValid())
|
||||
return checks;
|
||||
model.setData(index, false, Qt::CheckStateRole);
|
||||
return model.enabledChecks().join(',');
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangTools
|
||||
|
||||
|
@@ -34,6 +34,10 @@
|
||||
namespace ClangTools {
|
||||
namespace Internal {
|
||||
|
||||
// Not UI-related, but requires the tree model (or else a huge refactoring or code duplication).
|
||||
QString removeClangTidyCheck(const QString &checks, const QString &check);
|
||||
QString removeClazyCheck(const QString &checks, const QString &check);
|
||||
|
||||
namespace Ui {
|
||||
class ClazyChecks;
|
||||
class TidyChecks;
|
||||
|
Reference in New Issue
Block a user