forked from qt-creator/qt-creator
Clang: Make clazy UI more fine-grained
...so that specific checks can be enabled/disabled. This replaces the level radio buttons in Tools > Options > C++ > Code Model > "Manage..." > Tab: Clazy. Task-number: QTCREATORBUG-21120 Change-Id: If468d79d3c309b287b4105d83ac31f0b1489c71c Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
131
scripts/generateClazyChecks.py
Executable file
131
scripts/generateClazyChecks.py
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (C) 2019 The Qt Company Ltd.
|
||||
# Contact: https://www.qt.io/licensing/
|
||||
#
|
||||
# This file is part of Qt Creator.
|
||||
#
|
||||
# Commercial License Usage
|
||||
# Licensees holding valid commercial Qt licenses may use this file in
|
||||
# accordance with the commercial license agreement provided with the
|
||||
# Software or, alternatively, in accordance with the terms contained in
|
||||
# a written agreement between you and The Qt Company. For licensing terms
|
||||
# and conditions see https://www.qt.io/terms-conditions. For further
|
||||
# information use the contact form at https://www.qt.io/contact-us.
|
||||
#
|
||||
# GNU General Public License Usage
|
||||
# Alternatively, this file may be used under the terms of the GNU
|
||||
# General Public License version 3 as published by the Free Software
|
||||
# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
# included in the packaging of this file. Please review the following
|
||||
# information to ensure the GNU General Public License requirements will
|
||||
# be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
|
||||
def full_header_file_content(checks_initializer_as_string):
|
||||
return '''/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace CppTools {
|
||||
namespace Constants {
|
||||
|
||||
class ClazyCheckInfo
|
||||
{
|
||||
public:
|
||||
bool isValid() const { return !name.isEmpty() && level >= -1; }
|
||||
|
||||
QString name;
|
||||
int level = -1; // "Manual level"
|
||||
QStringList topics;
|
||||
};
|
||||
using ClazyCheckInfos = std::vector<ClazyCheckInfo>;
|
||||
|
||||
// CLANG-UPGRADE-CHECK: Run 'scripts/generateClazyChecks.py' after Clang upgrade to
|
||||
// update this header.
|
||||
static const ClazyCheckInfos CLAZY_CHECKS = {
|
||||
''' + checks_initializer_as_string + '''
|
||||
};
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace CppTools
|
||||
'''
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description='Clazy checks header file generator')
|
||||
parser.add_argument('--clazy-checks-json-path', help='path to clazy\'s checks.json',
|
||||
default=None, dest='checks_json_path')
|
||||
return parser.parse_args()
|
||||
|
||||
def quoted(text):
|
||||
return '"%s"' % (text)
|
||||
|
||||
def categories_as_initializer_string(check):
|
||||
if 'categories' not in check:
|
||||
return '{}'
|
||||
out = ''
|
||||
for category in check['categories']:
|
||||
out += quoted(category) + ','
|
||||
if out.endswith(','):
|
||||
out = out[:-1]
|
||||
return '{' + out + '}'
|
||||
|
||||
def check_as_initializer_string(check):
|
||||
return '{%s, %d, %s}' %(quoted(check['name']),
|
||||
check['level'],
|
||||
categories_as_initializer_string(check))
|
||||
|
||||
def checks_as_initializer_string(checks):
|
||||
out = ''
|
||||
for check in checks:
|
||||
out += ' ' + check_as_initializer_string(check) + ',\n'
|
||||
if out.endswith(',\n'):
|
||||
out = out[:-2]
|
||||
return out
|
||||
|
||||
def main():
|
||||
arguments = parse_arguments()
|
||||
|
||||
content = file(arguments.checks_json_path).read()
|
||||
checks = json.loads(content)['checks']
|
||||
|
||||
current_path = os.path.dirname(os.path.abspath(__file__))
|
||||
header_path = os.path.abspath(os.path.join(current_path, '..', 'src',
|
||||
'plugins', 'cpptools', 'cpptools_clazychecks.h'))
|
||||
|
||||
with open(header_path, 'w') as f:
|
||||
f.write(full_header_file_content(checks_as_initializer_string(checks)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@@ -120,12 +120,14 @@ void ClangDiagnosticConfigsSelectionWidget::connectToClangDiagnosticConfigsDialo
|
||||
connect(buttonsBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||
connect(buttonsBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
|
||||
connect(&dialog, &QDialog::accepted, [widget]() {
|
||||
const bool previousEnableLowerClazyLevels = codeModelSettings()->enableLowerClazyLevels();
|
||||
connect(&dialog, &QDialog::accepted, [widget, previousEnableLowerClazyLevels]() {
|
||||
QSharedPointer<CppCodeModelSettings> settings = codeModelSettings();
|
||||
const ClangDiagnosticConfigs oldDiagnosticConfigs
|
||||
= settings->clangCustomDiagnosticConfigs();
|
||||
const ClangDiagnosticConfigs currentDiagnosticConfigs = widget->customConfigs();
|
||||
if (oldDiagnosticConfigs != currentDiagnosticConfigs) {
|
||||
if (oldDiagnosticConfigs != currentDiagnosticConfigs
|
||||
|| previousEnableLowerClazyLevels != codeModelSettings()->enableLowerClazyLevels()) {
|
||||
const ClangDiagnosticConfigsModel configsModel(currentDiagnosticConfigs);
|
||||
if (!configsModel.hasConfigWithId(settings->clangDiagnosticConfigId()))
|
||||
settings->resetClangDiagnosticConfigId();
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "cppcodemodelsettings.h"
|
||||
#include "cpptools_clangtidychecks.h"
|
||||
#include "cpptools_clazychecks.h"
|
||||
#include "cpptoolsconstants.h"
|
||||
#include "cpptoolsreuse.h"
|
||||
#include "ui_clangdiagnosticconfigswidget.h"
|
||||
@@ -45,10 +46,14 @@
|
||||
#include <QDialogButtonBox>
|
||||
#include <QInputDialog>
|
||||
#include <QPushButton>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStringListModel>
|
||||
#include <QUuid>
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
using namespace Constants;
|
||||
|
||||
static constexpr const char CLANG_STATIC_ANALYZER_URL[]
|
||||
= "https://clang-analyzer.llvm.org/available_checks.html";
|
||||
|
||||
@@ -75,13 +80,99 @@ static bool needsLink(ProjectExplorer::Tree *node) {
|
||||
return !node->isDir && !node->fullPath.toString().startsWith("clang-analyzer-");
|
||||
}
|
||||
|
||||
class TidyChecksTreeModel final : public ProjectExplorer::SelectableFilesModel
|
||||
static void selectAll(QAbstractItemView *view)
|
||||
{
|
||||
view->setSelectionMode(QAbstractItemView::MultiSelection);
|
||||
view->selectAll();
|
||||
view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
}
|
||||
|
||||
class BaseChecksTreeModel : public ProjectExplorer::SelectableFilesModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles { LinkRole = Qt::UserRole + 1 };
|
||||
enum Columns { NameColumn, LinkColumn };
|
||||
|
||||
BaseChecksTreeModel()
|
||||
: ProjectExplorer::SelectableFilesModel(nullptr)
|
||||
{}
|
||||
|
||||
int columnCount(const QModelIndex &) const override { return 2; }
|
||||
|
||||
QVariant data(const QModelIndex &fullIndex, int role = Qt::DisplayRole) const override
|
||||
{
|
||||
if (fullIndex.column() == LinkColumn) {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return tr("Web Page");
|
||||
case Qt::FontRole: {
|
||||
QFont font = QApplication::font();
|
||||
font.setUnderline(true);
|
||||
return font;
|
||||
}
|
||||
case Qt::ForegroundRole:
|
||||
return QApplication::palette().link().color();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
|
||||
{
|
||||
if (role == Qt::CheckStateRole && !m_enabled)
|
||||
return false;
|
||||
ProjectExplorer::SelectableFilesModel::setData(index, value, role);
|
||||
return true;
|
||||
}
|
||||
|
||||
void setEnabled(bool enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
// TODO: Remove/replace this method after base class refactoring is done.
|
||||
void traverse(const QModelIndex &index,
|
||||
const std::function<bool(const QModelIndex &)> &visit) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
if (!visit(index))
|
||||
return;
|
||||
|
||||
if (!hasChildren(index))
|
||||
return;
|
||||
|
||||
const int rows = rowCount(index);
|
||||
const int cols = columnCount(index);
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
for (int j = 0; j < cols; ++j)
|
||||
traverse(this->index(i, j, index), visit);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool m_enabled = true;
|
||||
};
|
||||
|
||||
static void openUrl(QAbstractItemModel *model, const QModelIndex &index)
|
||||
{
|
||||
const QString link = model->data(index, BaseChecksTreeModel::LinkRole).toString();
|
||||
if (link.isEmpty())
|
||||
return;
|
||||
|
||||
QDesktopServices::openUrl(QUrl(link));
|
||||
};
|
||||
|
||||
class TidyChecksTreeModel final : public BaseChecksTreeModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TidyChecksTreeModel()
|
||||
: ProjectExplorer::SelectableFilesModel(nullptr)
|
||||
{
|
||||
buildTree(nullptr, m_root, Constants::CLANG_TIDY_CHECKS_ROOT);
|
||||
}
|
||||
@@ -119,11 +210,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int columnCount(const QModelIndex &/*parent*/) const override
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
private:
|
||||
QVariant data(const QModelIndex &fullIndex, int role = Qt::DisplayRole) const final
|
||||
{
|
||||
if (!fullIndex.isValid() || role == Qt::DecorationRole)
|
||||
@@ -134,25 +221,16 @@ public:
|
||||
if (fullIndex.column() == 1) {
|
||||
if (!needsLink(node))
|
||||
return QVariant();
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return tr("Web Page");
|
||||
case Qt::FontRole: {
|
||||
QFont font = QApplication::font();
|
||||
font.setUnderline(true);
|
||||
return font;
|
||||
}
|
||||
case Qt::ForegroundRole:
|
||||
return QApplication::palette().link().color();
|
||||
case Qt::UserRole: {
|
||||
|
||||
if (role == LinkRole) {
|
||||
// 'clang-analyzer-' group
|
||||
if (node->isDir)
|
||||
return QString::fromUtf8(CLANG_STATIC_ANALYZER_URL);
|
||||
return QString::fromUtf8(Constants::TIDY_DOCUMENTATION_URL_TEMPLATE)
|
||||
.arg(node->fullPath.toString());
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
return BaseChecksTreeModel::data(fullIndex, role);
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
@@ -161,41 +239,6 @@ public:
|
||||
return ProjectExplorer::SelectableFilesModel::data(index, role);
|
||||
}
|
||||
|
||||
void setEnabled(bool enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
|
||||
{
|
||||
if (role == Qt::CheckStateRole && !m_enabled)
|
||||
return false;
|
||||
return ProjectExplorer::SelectableFilesModel::setData(index, value, role);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// TODO: Remove/replace this method after base class refactoring is done.
|
||||
void traverse(const QModelIndex &index,
|
||||
const std::function<bool(const QModelIndex &)> &visit) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
if (!visit(index))
|
||||
return;
|
||||
|
||||
if (!hasChildren(index))
|
||||
return;
|
||||
|
||||
const int rows = rowCount(index);
|
||||
const int cols = columnCount(index);
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
for (int j = 0; j < cols; ++j)
|
||||
traverse(this->index(i, j, index), visit);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex indexForCheck(const QString &check) const {
|
||||
if (check == "*")
|
||||
return index(0, 0, QModelIndex());
|
||||
@@ -232,8 +275,321 @@ private:
|
||||
for (const ProjectExplorer::Tree *t : root->childDirectories)
|
||||
collectChecks(t, checks);
|
||||
}
|
||||
};
|
||||
|
||||
bool m_enabled = true;
|
||||
class ClazyChecksTree : public ProjectExplorer::Tree
|
||||
{
|
||||
public:
|
||||
enum Kind { TopLevelNode, LevelNode, CheckNode };
|
||||
ClazyChecksTree(const QString &name, Kind kind)
|
||||
{
|
||||
this->name = name;
|
||||
this->kind = kind;
|
||||
this->isDir = kind == TopLevelNode || kind == LevelNode;
|
||||
}
|
||||
|
||||
static ClazyChecksTree *fromIndex(const QModelIndex &index)
|
||||
{
|
||||
return static_cast<ClazyChecksTree *>(index.internalPointer());
|
||||
}
|
||||
|
||||
public:
|
||||
ClazyCheckInfo checkInfo;
|
||||
Kind kind = TopLevelNode;
|
||||
};
|
||||
|
||||
class ClazyChecksTreeModel final : public BaseChecksTreeModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClazyChecksTreeModel() { buildTree(); }
|
||||
|
||||
QStringList enabledChecks() const
|
||||
{
|
||||
QStringList checks;
|
||||
collectChecks(m_root, checks);
|
||||
return checks;
|
||||
}
|
||||
|
||||
void enableChecks(const QStringList &checks)
|
||||
{
|
||||
// Unselect all
|
||||
m_root->checked = Qt::Unchecked;
|
||||
propagateDown(index(0, 0, QModelIndex()));
|
||||
|
||||
// <= Qt Creator 4.8 settings provide specific levels: {"level0"}
|
||||
if (checks.size() == 1 && checks.first().startsWith("level")) {
|
||||
bool ok = false;
|
||||
const int level = checks.first().mid(5).toInt(&ok);
|
||||
QTC_ASSERT(ok, return);
|
||||
enableChecksByLevel(level);
|
||||
return;
|
||||
}
|
||||
|
||||
// >= Qt Creator 4.9 settings provide specific checks: {c1, c2, ...}
|
||||
for (const QString &check : checks) {
|
||||
const QModelIndex index = indexForCheck(check);
|
||||
if (!index.isValid())
|
||||
continue;
|
||||
ClazyChecksTree::fromIndex(index)->checked = Qt::Checked;
|
||||
propagateUp(index);
|
||||
propagateDown(index);
|
||||
}
|
||||
}
|
||||
|
||||
bool hasEnabledButNotVisibleChecks(
|
||||
const std::function<bool(const QModelIndex &index)> &isHidden) const
|
||||
{
|
||||
bool enabled = false;
|
||||
traverse(index(0, 0, QModelIndex()), [&](const QModelIndex &index){
|
||||
if (enabled)
|
||||
return false;
|
||||
const auto *node = ClazyChecksTree::fromIndex(index);
|
||||
if (node->kind == ClazyChecksTree::CheckNode && index.column() == NameColumn) {
|
||||
const bool isChecked = data(index, Qt::CheckStateRole).toInt() == Qt::Checked;
|
||||
const bool isVisible = isHidden(index);
|
||||
if (isChecked && isVisible) {
|
||||
enabled = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
bool enableLowerLevels() const { return m_enableLowerLevels; }
|
||||
void setEnableLowerLevels(bool enable) { m_enableLowerLevels = enable; }
|
||||
|
||||
QSet<QString> topics() const { return m_topics; }
|
||||
|
||||
private:
|
||||
void buildTree()
|
||||
{
|
||||
// Top level node
|
||||
m_root = new ClazyChecksTree("*", ClazyChecksTree::TopLevelNode);
|
||||
|
||||
for (const ClazyCheckInfo &check : CLAZY_CHECKS) {
|
||||
// Level node
|
||||
ClazyChecksTree *&levelNode = m_levelNodes[check.level];
|
||||
if (!levelNode) {
|
||||
levelNode = new ClazyChecksTree(levelDescription(check.level), ClazyChecksTree::LevelNode);
|
||||
levelNode->parent = m_root;
|
||||
levelNode->checkInfo.level = check.level; // Pass on the level for sorting
|
||||
m_root->childDirectories << levelNode;
|
||||
}
|
||||
|
||||
// Check node
|
||||
auto checkNode = new ClazyChecksTree(check.name, ClazyChecksTree::CheckNode);
|
||||
checkNode->parent = levelNode;
|
||||
checkNode->checkInfo = check;
|
||||
|
||||
levelNode->childDirectories.append(checkNode);
|
||||
|
||||
m_topics.unite(check.topics.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
QVariant data(const QModelIndex &fullIndex, int role = Qt::DisplayRole) const override final
|
||||
{
|
||||
if (!fullIndex.isValid() || role == Qt::DecorationRole)
|
||||
return QVariant();
|
||||
const QModelIndex index = this->index(fullIndex.row(), 0, fullIndex.parent());
|
||||
const auto *node = ClazyChecksTree::fromIndex(index);
|
||||
|
||||
if (fullIndex.column() == LinkColumn) {
|
||||
if (role == LinkRole) {
|
||||
if (node->checkInfo.name.isEmpty())
|
||||
return QVariant();
|
||||
return QString::fromUtf8(Constants::CLAZY_DOCUMENTATION_URL_TEMPLATE).arg(node->name);
|
||||
}
|
||||
if (role == Qt::DisplayRole && node->kind != ClazyChecksTree::CheckNode)
|
||||
return QVariant();
|
||||
|
||||
return BaseChecksTreeModel::data(fullIndex, role);
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
return node->name;
|
||||
|
||||
return ProjectExplorer::SelectableFilesModel::data(index, role);
|
||||
}
|
||||
|
||||
static QString levelDescription(int level)
|
||||
{
|
||||
switch (level) {
|
||||
case -1:
|
||||
return tr("Manual Level: Very few false positives");
|
||||
case 0:
|
||||
return tr("Level 0: No false positives");
|
||||
case 1:
|
||||
return tr("Level 1: Very few false positives");
|
||||
case 2:
|
||||
return tr("Level 2: More false positives");
|
||||
case 3:
|
||||
return tr("Level 3: Experimental checks");
|
||||
default:
|
||||
QTC_CHECK(false && "No clazy level description");
|
||||
return tr("Level %1").arg(QString::number(level));
|
||||
}
|
||||
}
|
||||
|
||||
void enableChecksByLevel(int level)
|
||||
{
|
||||
if (level < 0)
|
||||
return;
|
||||
|
||||
ClazyChecksTree *node = m_levelNodes.value(level);
|
||||
QTC_ASSERT(node, return);
|
||||
const QModelIndex index = indexForTree(node);
|
||||
QTC_ASSERT(index.isValid(), return);
|
||||
|
||||
node->checked = Qt::Checked;
|
||||
propagateUp(index);
|
||||
propagateDown(index);
|
||||
|
||||
enableChecksByLevel(--level);
|
||||
}
|
||||
|
||||
QModelIndex indexForCheck(const QString &check) const {
|
||||
if (check == "*")
|
||||
return index(0, 0, QModelIndex());
|
||||
|
||||
QModelIndex result;
|
||||
traverse(index(0, 0, QModelIndex()), [&](const QModelIndex &index){
|
||||
if (result.isValid())
|
||||
return false;
|
||||
const auto *node = ClazyChecksTree::fromIndex(index);
|
||||
if (node->kind == ClazyChecksTree::CheckNode && node->checkInfo.name == check) {
|
||||
result = index;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
QModelIndex indexForTree(const ClazyChecksTree *tree) const {
|
||||
if (!tree)
|
||||
return QModelIndex();
|
||||
|
||||
QModelIndex result;
|
||||
traverse(index(0, 0, QModelIndex()), [&](const QModelIndex &index){
|
||||
if (result.isValid())
|
||||
return false;
|
||||
if (index.internalPointer() == tree) {
|
||||
result = index;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
static void collectChecks(const ProjectExplorer::Tree *root, QStringList &checks)
|
||||
{
|
||||
if (root->checked == Qt::Unchecked)
|
||||
return;
|
||||
if (root->checked == Qt::Checked && !root->isDir) {
|
||||
checks.append(root->name);
|
||||
return;
|
||||
}
|
||||
for (const ProjectExplorer::Tree *t : root->childDirectories)
|
||||
collectChecks(t, checks);
|
||||
}
|
||||
|
||||
static QStringList toStringList(const QVariantList &variantList)
|
||||
{
|
||||
QStringList list;
|
||||
for (auto &item : variantList)
|
||||
list.append(item.toString());
|
||||
return list;
|
||||
}
|
||||
|
||||
private:
|
||||
QHash<int, ClazyChecksTree *> m_levelNodes;
|
||||
QSet<QString> m_topics;
|
||||
bool m_enableLowerLevels = true;
|
||||
};
|
||||
|
||||
class ClazyChecksSortFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
ClazyChecksSortFilterModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{}
|
||||
|
||||
void setTopics(const QStringList &value)
|
||||
{
|
||||
m_topics = value;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
|
||||
{
|
||||
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
if (!index.isValid())
|
||||
return false;
|
||||
|
||||
const auto *node = ClazyChecksTree::fromIndex(index);
|
||||
if (node->kind == ClazyChecksTree::CheckNode) {
|
||||
const QStringList topics = node->checkInfo.topics;
|
||||
return Utils::anyOf(m_topics, [this, topics](const QString &topic) {
|
||||
return topics.contains(topic);
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Note that sort order of levels is important for "enableLowerLevels" mode, see setData().
|
||||
bool lessThan(const QModelIndex &l, const QModelIndex &r) const override
|
||||
{
|
||||
const int leftLevel = adaptLevel(ClazyChecksTree::fromIndex(l)->checkInfo.level);
|
||||
const int rightLevel = adaptLevel(ClazyChecksTree::fromIndex(r)->checkInfo.level);
|
||||
|
||||
if (leftLevel == rightLevel)
|
||||
return sourceModel()->data(l).toString() < sourceModel()->data(r).toString();
|
||||
return leftLevel < rightLevel;
|
||||
}
|
||||
|
||||
static bool adaptLevel(int level)
|
||||
{
|
||||
if (level == -1) // "Manual Level"
|
||||
return 1000;
|
||||
return level;
|
||||
}
|
||||
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
|
||||
{
|
||||
if (!index.isValid())
|
||||
return false;
|
||||
|
||||
if (role == Qt::CheckStateRole
|
||||
&& static_cast<ClazyChecksTreeModel *>(sourceModel())->enableLowerLevels()
|
||||
&& QSortFilterProxyModel::setData(index, value, role)) {
|
||||
const auto *node = ClazyChecksTree::fromIndex(mapToSource(index));
|
||||
if (node->kind == ClazyChecksTree::LevelNode && node->checkInfo.level >= 0) {
|
||||
// Rely on the sort order to find the lower level index/node
|
||||
const auto previousIndex = this->index(index.row() - 1,
|
||||
index.column(),
|
||||
index.parent());
|
||||
if (previousIndex.isValid()
|
||||
&& ClazyChecksTree::fromIndex(mapToSource(previousIndex))->checkInfo.level
|
||||
>= 0) {
|
||||
setData(previousIndex, value, role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QSortFilterProxyModel::setData(index, value, role);
|
||||
}
|
||||
|
||||
private:
|
||||
QStringList m_topics;
|
||||
};
|
||||
|
||||
ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &configToSelect,
|
||||
@@ -241,6 +597,7 @@ ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &confi
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::ClangDiagnosticConfigsWidget)
|
||||
, m_diagnosticConfigsModel(codeModelSettings()->clangCustomDiagnosticConfigs())
|
||||
, m_clazyTreeModel(new ClazyChecksTreeModel())
|
||||
, m_tidyTreeModel(new TidyChecksTreeModel())
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
@@ -256,14 +613,12 @@ ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &confi
|
||||
this, &ClangDiagnosticConfigsWidget::onRemoveButtonClicked);
|
||||
connectDiagnosticOptionsChanged();
|
||||
|
||||
connect(m_tidyChecks->checksPrefixesTree, &QTreeView::clicked,
|
||||
[this](const QModelIndex &index) {
|
||||
const QString link = m_tidyTreeModel->data(index, Qt::UserRole).toString();
|
||||
if (link.isEmpty())
|
||||
return;
|
||||
|
||||
QDesktopServices::openUrl(QUrl(link));
|
||||
});
|
||||
connect(m_tidyChecks->checksPrefixesTree,
|
||||
&QTreeView::clicked,
|
||||
[model = m_tidyTreeModel.get()](const QModelIndex &index) { openUrl(model, index); });
|
||||
connect(m_clazyChecks->checksView,
|
||||
&QTreeView::clicked,
|
||||
[model = m_clazySortFilterProxyModel](const QModelIndex &index) { openUrl(model, index); });
|
||||
|
||||
syncWidgetsToModel(configToSelect);
|
||||
}
|
||||
@@ -344,25 +699,12 @@ void ClangDiagnosticConfigsWidget::onClangTidyTreeChanged()
|
||||
updateConfig(config);
|
||||
}
|
||||
|
||||
void ClangDiagnosticConfigsWidget::onClazyRadioButtonChanged(bool checked)
|
||||
void ClangDiagnosticConfigsWidget::onClazyTreeChanged()
|
||||
{
|
||||
if (!checked)
|
||||
return;
|
||||
|
||||
QString checks;
|
||||
if (m_clazyChecks->clazyRadioDisabled->isChecked())
|
||||
checks = QString();
|
||||
else if (m_clazyChecks->clazyRadioLevel0->isChecked())
|
||||
checks = "level0";
|
||||
else if (m_clazyChecks->clazyRadioLevel1->isChecked())
|
||||
checks = "level1";
|
||||
else if (m_clazyChecks->clazyRadioLevel2->isChecked())
|
||||
checks = "level2";
|
||||
else if (m_clazyChecks->clazyRadioLevel3->isChecked())
|
||||
checks = "level3";
|
||||
syncClazyChecksGroupBox();
|
||||
|
||||
ClangDiagnosticConfig config = selectedConfig();
|
||||
config.setClazyChecks(checks);
|
||||
config.setClazyChecks(m_clazyTreeModel->enabledChecks().join(","));
|
||||
updateConfig(config);
|
||||
}
|
||||
|
||||
@@ -518,22 +860,35 @@ void ClangDiagnosticConfigsWidget::syncTidyChecksToTree(const ClangDiagnosticCon
|
||||
|
||||
void ClangDiagnosticConfigsWidget::syncClazyWidgets(const ClangDiagnosticConfig &config)
|
||||
{
|
||||
disconnectClazyItemChanged();
|
||||
|
||||
const QString clazyChecks = config.clazyChecks();
|
||||
|
||||
QRadioButton *button = m_clazyChecks->clazyRadioDisabled;
|
||||
if (clazyChecks.isEmpty())
|
||||
button = m_clazyChecks->clazyRadioDisabled;
|
||||
else if (clazyChecks == "level0")
|
||||
button = m_clazyChecks->clazyRadioLevel0;
|
||||
else if (clazyChecks == "level1")
|
||||
button = m_clazyChecks->clazyRadioLevel1;
|
||||
else if (clazyChecks == "level2")
|
||||
button = m_clazyChecks->clazyRadioLevel2;
|
||||
else if (clazyChecks == "level3")
|
||||
button = m_clazyChecks->clazyRadioLevel3;
|
||||
m_clazyTreeModel->enableChecks(clazyChecks.split(',', QString::SkipEmptyParts));
|
||||
|
||||
button->setChecked(true);
|
||||
m_clazyChecksWidget->setEnabled(!config.isReadOnly());
|
||||
syncClazyChecksGroupBox();
|
||||
|
||||
const bool enabled = !config.isReadOnly();
|
||||
m_clazyChecks->topicsResetButton->setEnabled(enabled);
|
||||
m_clazyChecks->enableLowerLevelsCheckBox->setEnabled(enabled);
|
||||
selectAll(m_clazyChecks->topicsView);
|
||||
m_clazyChecks->topicsView->setEnabled(enabled);
|
||||
m_clazyTreeModel->setEnabled(enabled);
|
||||
|
||||
connectClazyItemChanged();
|
||||
}
|
||||
|
||||
void ClangDiagnosticConfigsWidget::syncClazyChecksGroupBox()
|
||||
{
|
||||
const auto isHidden = [this](const QModelIndex &index) {
|
||||
return !m_clazySortFilterProxyModel->filterAcceptsRow(index.row(), index.parent());
|
||||
};
|
||||
const bool hasEnabledButHidden = m_clazyTreeModel->hasEnabledButNotVisibleChecks(isHidden);
|
||||
const QString title = hasEnabledButHidden ? tr("Checks (%1 enabled, some are filtered out)")
|
||||
: tr("Checks (%1 enabled)");
|
||||
|
||||
const QStringList checks = m_clazyTreeModel->enabledChecks();
|
||||
m_clazyChecks->checksGroupBox->setTitle(title.arg(checks.count()));
|
||||
}
|
||||
|
||||
void ClangDiagnosticConfigsWidget::updateConfig(const ClangDiagnosticConfig &config)
|
||||
@@ -599,12 +954,16 @@ void ClangDiagnosticConfigsWidget::disconnectClangTidyItemChanged()
|
||||
this, &ClangDiagnosticConfigsWidget::onClangTidyTreeChanged);
|
||||
}
|
||||
|
||||
void ClangDiagnosticConfigsWidget::connectClazyRadioButtonClicked(QRadioButton *button)
|
||||
void ClangDiagnosticConfigsWidget::connectClazyItemChanged()
|
||||
{
|
||||
connect(button,
|
||||
&QRadioButton::clicked,
|
||||
this,
|
||||
&ClangDiagnosticConfigsWidget::onClazyRadioButtonChanged);
|
||||
connect(m_clazyTreeModel.get(), &ClazyChecksTreeModel::dataChanged,
|
||||
this, &ClangDiagnosticConfigsWidget::onClazyTreeChanged);
|
||||
}
|
||||
|
||||
void ClangDiagnosticConfigsWidget::disconnectClazyItemChanged()
|
||||
{
|
||||
disconnect(m_clazyTreeModel.get(), &ClazyChecksTreeModel::dataChanged,
|
||||
this, &ClangDiagnosticConfigsWidget::onClazyTreeChanged);
|
||||
}
|
||||
|
||||
void ClangDiagnosticConfigsWidget::connectConfigChooserCurrentIndex()
|
||||
@@ -644,6 +1003,15 @@ ClangDiagnosticConfigs ClangDiagnosticConfigsWidget::customConfigs() const
|
||||
});
|
||||
}
|
||||
|
||||
static void setupTreeView(QTreeView *view, QAbstractItemModel *model, int expandToDepth = 0)
|
||||
{
|
||||
view->setModel(model);
|
||||
view->expandToDepth(expandToDepth);
|
||||
view->header()->setStretchLastSection(false);
|
||||
view->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
view->setHeaderHidden(true);
|
||||
}
|
||||
|
||||
void ClangDiagnosticConfigsWidget::setupTabs()
|
||||
{
|
||||
m_clangBaseChecks.reset(new CppTools::Ui::ClangBaseChecks);
|
||||
@@ -653,20 +1021,45 @@ void ClangDiagnosticConfigsWidget::setupTabs()
|
||||
m_clazyChecks.reset(new CppTools::Ui::ClazyChecks);
|
||||
m_clazyChecksWidget = new QWidget();
|
||||
m_clazyChecks->setupUi(m_clazyChecksWidget);
|
||||
m_clazySortFilterProxyModel = new ClazyChecksSortFilterModel(this);
|
||||
m_clazySortFilterProxyModel->setSourceModel(m_clazyTreeModel.get());
|
||||
setupTreeView(m_clazyChecks->checksView, m_clazySortFilterProxyModel, 2);
|
||||
m_clazyChecks->checksView->setSortingEnabled(true);
|
||||
m_clazyChecks->checksView->sortByColumn(0, Qt::AscendingOrder);
|
||||
auto topicsModel = new QStringListModel(m_clazyTreeModel->topics().toList(), this);
|
||||
topicsModel->sort(0);
|
||||
m_clazyChecks->topicsView->setModel(topicsModel);
|
||||
connect(m_clazyChecks->topicsResetButton, &QPushButton::clicked, [this](){
|
||||
selectAll(m_clazyChecks->topicsView);
|
||||
});
|
||||
connect(m_clazyChecks->topicsView->selectionModel(),
|
||||
&QItemSelectionModel::selectionChanged,
|
||||
[this, topicsModel](const QItemSelection &, const QItemSelection &) {
|
||||
const auto indexes = m_clazyChecks->topicsView->selectionModel()->selectedIndexes();
|
||||
const QStringList topics
|
||||
= Utils::transform(indexes, [topicsModel](const QModelIndex &index) {
|
||||
return topicsModel->data(index).toString();
|
||||
});
|
||||
m_clazySortFilterProxyModel->setTopics(topics);
|
||||
this->syncClazyChecksGroupBox();
|
||||
});
|
||||
|
||||
connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioDisabled);
|
||||
connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioLevel0);
|
||||
connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioLevel1);
|
||||
connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioLevel2);
|
||||
connectClazyRadioButtonClicked(m_clazyChecks->clazyRadioLevel3);
|
||||
selectAll(m_clazyChecks->topicsView);
|
||||
connect(m_clazyChecks->enableLowerLevelsCheckBox, &QCheckBox::stateChanged, [this](int) {
|
||||
const bool enable = m_clazyChecks->enableLowerLevelsCheckBox->isChecked();
|
||||
m_clazyTreeModel->setEnableLowerLevels(enable);
|
||||
codeModelSettings()->setEnableLowerClazyLevels(
|
||||
m_clazyChecks->enableLowerLevelsCheckBox->isChecked());
|
||||
});
|
||||
const Qt::CheckState checkEnableLowerClazyLevels
|
||||
= codeModelSettings()->enableLowerClazyLevels() ? Qt::Checked : Qt::Unchecked;
|
||||
m_clazyChecks->enableLowerLevelsCheckBox->setCheckState(checkEnableLowerClazyLevels);
|
||||
|
||||
m_tidyChecks.reset(new CppTools::Ui::TidyChecks);
|
||||
m_tidyChecksWidget = new QWidget();
|
||||
m_tidyChecks->setupUi(m_tidyChecksWidget);
|
||||
m_tidyChecks->checksPrefixesTree->setModel(m_tidyTreeModel.get());
|
||||
m_tidyChecks->checksPrefixesTree->expandToDepth(0);
|
||||
m_tidyChecks->checksPrefixesTree->header()->setStretchLastSection(false);
|
||||
m_tidyChecks->checksPrefixesTree->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
setupTreeView(m_tidyChecks->checksPrefixesTree, m_tidyTreeModel.get());
|
||||
|
||||
connect(m_tidyChecks->plainTextEditButton, &QPushButton::clicked, this, [this]() {
|
||||
const bool readOnly = selectedConfig().isReadOnly();
|
||||
|
||||
@@ -702,6 +1095,7 @@ void ClangDiagnosticConfigsWidget::setupTabs()
|
||||
});
|
||||
|
||||
connectClangTidyItemChanged();
|
||||
connectClazyItemChanged();
|
||||
|
||||
m_ui->tabWidget->addTab(m_clangBaseChecksWidget, tr("Clang"));
|
||||
m_ui->tabWidget->addTab(m_tidyChecksWidget, tr("Clang-Tidy"));
|
||||
|
@@ -38,7 +38,6 @@
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QListWidgetItem;
|
||||
class QPushButton;
|
||||
class QRadioButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace CppTools {
|
||||
@@ -51,6 +50,8 @@ class TidyChecks;
|
||||
}
|
||||
|
||||
class TidyChecksTreeModel;
|
||||
class ClazyChecksTreeModel;
|
||||
class ClazyChecksSortFilterModel;
|
||||
|
||||
class CPPTOOLS_EXPORT ClangDiagnosticConfigsWidget : public QWidget
|
||||
{
|
||||
@@ -73,8 +74,8 @@ private:
|
||||
void onRemoveButtonClicked();
|
||||
void onClangTidyModeChanged(int index);
|
||||
void onClangTidyTreeChanged();
|
||||
void onClazyTreeChanged();
|
||||
void onClangTidyTreeItemClicked(const QModelIndex &index);
|
||||
void onClazyRadioButtonChanged(bool checked);
|
||||
|
||||
void onDiagnosticOptionsEdited();
|
||||
|
||||
@@ -83,6 +84,7 @@ private:
|
||||
void syncOtherWidgetsToComboBox();
|
||||
void syncClangTidyWidgets(const ClangDiagnosticConfig &config);
|
||||
void syncClazyWidgets(const ClangDiagnosticConfig &config);
|
||||
void syncClazyChecksGroupBox();
|
||||
void syncTidyChecksToTree(const ClangDiagnosticConfig &config);
|
||||
|
||||
void updateConfig(const CppTools::ClangDiagnosticConfig &config);
|
||||
@@ -97,7 +99,8 @@ private:
|
||||
void connectClangTidyItemChanged();
|
||||
void disconnectClangTidyItemChanged();
|
||||
|
||||
void connectClazyRadioButtonClicked(QRadioButton *button);
|
||||
void connectClazyItemChanged();
|
||||
void disconnectClazyItemChanged();
|
||||
|
||||
void connectConfigChooserCurrentIndex();
|
||||
void disconnectConfigChooserCurrentIndex();
|
||||
@@ -114,6 +117,8 @@ private:
|
||||
|
||||
std::unique_ptr<CppTools::Ui::ClazyChecks> m_clazyChecks;
|
||||
QWidget *m_clazyChecksWidget = nullptr;
|
||||
std::unique_ptr<ClazyChecksTreeModel> m_clazyTreeModel;
|
||||
ClazyChecksSortFilterModel *m_clazySortFilterProxyModel = nullptr;
|
||||
|
||||
std::unique_ptr<CppTools::Ui::TidyChecks> m_tidyChecks;
|
||||
QWidget *m_tidyChecksWidget = nullptr;
|
||||
|
@@ -105,7 +105,14 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget"/>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>700</width>
|
||||
<height>500</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>609</width>
|
||||
<height>220</height>
|
||||
<width>700</width>
|
||||
<height>500</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -23,7 +23,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Each level adds checks to the previous level. For more information, see <a href="https://github.com/KDE/clazy">clazy's homepage</a>.</string>
|
||||
<string>See <a href="https://github.com/KDE/clazy">clazy's homepage</a> for more information.</string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
@@ -31,64 +31,74 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="clazyRadioDisabled">
|
||||
<property name="text">
|
||||
<string>Disabled</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="clazyRadioLevel0">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Level 0: No false positives</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="clazyRadioLevel1">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Level 1: Very few false positives</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="clazyRadioLevel2">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Level 2: More false positives</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="clazyRadioLevel3">
|
||||
<property name="toolTip">
|
||||
<string>Not always correct, possibly very noisy, might require a knowledgeable developer to review, might have a very big rate of false-positives, might have bugs.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Level 3: Experimental checks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>34</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Topic Filter</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="topicsResetButton">
|
||||
<property name="text">
|
||||
<string>Reset to All</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="topicsView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="checksGroupBox">
|
||||
<property name="title">
|
||||
<string>Checks</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableLowerLevelsCheckBox">
|
||||
<property name="toolTip">
|
||||
<string>When enabling a level explicitly, also enable lower levels (Clazy semantic).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable lower levels automatically</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="checksView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@@ -64,6 +64,9 @@ static QString clangDiagnosticConfigsArrayClangTidyModeKey()
|
||||
static QString clangDiagnosticConfigsArrayClazyChecksKey()
|
||||
{ return QLatin1String("clazyChecks"); }
|
||||
|
||||
static QString enableLowerClazyLevelsKey()
|
||||
{ return QLatin1String("enableLowerClazyLevels"); }
|
||||
|
||||
static QString pchUsageKey()
|
||||
{ return QLatin1String(Constants::CPPTOOLS_MODEL_MANAGER_PCH_USAGE); }
|
||||
|
||||
@@ -124,6 +127,8 @@ void CppCodeModelSettings::fromSettings(QSettings *s)
|
||||
setClangDiagnosticConfigId(initialClangDiagnosticConfigId());
|
||||
}
|
||||
|
||||
setEnableLowerClazyLevels(s->value(enableLowerClazyLevelsKey(), true).toBool());
|
||||
|
||||
const QVariant pchUsageVariant = s->value(pchUsageKey(), initialPchUsage());
|
||||
setPCHUsage(static_cast<PCHUsage>(pchUsageVariant.toInt()));
|
||||
|
||||
@@ -165,6 +170,7 @@ void CppCodeModelSettings::toSettings(QSettings *s)
|
||||
s->endArray();
|
||||
|
||||
s->setValue(clangDiagnosticConfigKey(), clangDiagnosticConfigId().toSetting());
|
||||
s->setValue(enableLowerClazyLevelsKey(), enableLowerClazyLevels());
|
||||
s->setValue(pchUsageKey(), pchUsage());
|
||||
|
||||
s->setValue(interpretAmbiguousHeadersAsCHeadersKey(), interpretAmbigiousHeadersAsCHeaders());
|
||||
@@ -256,3 +262,13 @@ void CppCodeModelSettings::setIndexerFileSizeLimitInMb(int sizeInMB)
|
||||
{
|
||||
m_indexerFileSizeLimitInMB = sizeInMB;
|
||||
}
|
||||
|
||||
bool CppCodeModelSettings::enableLowerClazyLevels() const
|
||||
{
|
||||
return m_enableLowerClazyLevels;
|
||||
}
|
||||
|
||||
void CppCodeModelSettings::setEnableLowerClazyLevels(bool yesno)
|
||||
{
|
||||
m_enableLowerClazyLevels = yesno;
|
||||
}
|
||||
|
@@ -61,6 +61,9 @@ public:
|
||||
ClangDiagnosticConfigs clangCustomDiagnosticConfigs() const;
|
||||
void setClangCustomDiagnosticConfigs(const ClangDiagnosticConfigs &configs);
|
||||
|
||||
bool enableLowerClazyLevels() const;
|
||||
void setEnableLowerClazyLevels(bool yesno);
|
||||
|
||||
PCHUsage pchUsage() const;
|
||||
void setPCHUsage(PCHUsage pchUsage);
|
||||
|
||||
@@ -84,6 +87,7 @@ private:
|
||||
int m_indexerFileSizeLimitInMB = 5;
|
||||
ClangDiagnosticConfigs m_clangCustomDiagnosticConfigs;
|
||||
Core::Id m_clangDiagnosticConfigId;
|
||||
bool m_enableLowerClazyLevels = true; // For UI behavior only
|
||||
};
|
||||
|
||||
} // namespace CppTools
|
||||
|
@@ -103,7 +103,8 @@ HEADERS += \
|
||||
cppmodelmanagerinterface.h \
|
||||
cppbuiltinmodelmanagersupport.h \
|
||||
headerpathfilter.h \
|
||||
cppkitinfo.h
|
||||
cppkitinfo.h \
|
||||
cpptools_clazychecks.h
|
||||
|
||||
SOURCES += \
|
||||
abstracteditorsupport.cpp \
|
||||
|
@@ -158,6 +158,7 @@ Project {
|
||||
"cppsourceprocessor.h",
|
||||
"cpptools.qrc",
|
||||
"cpptools_clangtidychecks.h",
|
||||
"cpptools_clazychecks.h",
|
||||
"cpptools_global.h",
|
||||
"cpptools_utils.h",
|
||||
"cpptoolsbridge.cpp",
|
||||
|
130
src/plugins/cpptools/cpptools_clazychecks.h
Normal file
130
src/plugins/cpptools/cpptools_clazychecks.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace CppTools {
|
||||
namespace Constants {
|
||||
|
||||
class ClazyCheckInfo
|
||||
{
|
||||
public:
|
||||
bool isValid() const { return !name.isEmpty() && level >= -1; }
|
||||
|
||||
QString name;
|
||||
int level = -1; // "Manual level"
|
||||
QStringList topics;
|
||||
};
|
||||
using ClazyCheckInfos = std::vector<ClazyCheckInfo>;
|
||||
|
||||
// CLANG-UPGRADE-CHECK: Run 'scripts/generateClazyChecks.py' after Clang upgrade to
|
||||
// update this header.
|
||||
static const ClazyCheckInfos CLAZY_CHECKS = {
|
||||
{"qt-keywords", -1, {}},
|
||||
{"ifndef-define-typo", -1, {"bug"}},
|
||||
{"inefficient-qlist", -1, {"containers","performance"}},
|
||||
{"isempty-vs-count", -1, {"readability"}},
|
||||
{"qrequiredresult-candidates", -1, {"bug"}},
|
||||
{"qstring-varargs", -1, {"bug"}},
|
||||
{"qt4-qstring-from-array", -1, {"qt4","qstring"}},
|
||||
{"tr-non-literal", -1, {"bug"}},
|
||||
{"raw-environment-function", -1, {"bug"}},
|
||||
{"container-inside-loop", -1, {"containers","performance"}},
|
||||
{"qhash-with-char-pointer-key", -1, {"cpp","bug"}},
|
||||
{"connect-by-name", 0, {"bug","readability"}},
|
||||
{"connect-non-signal", 0, {"bug"}},
|
||||
{"wrong-qevent-cast", 0, {"bug"}},
|
||||
{"lambda-in-connect", 0, {"bug"}},
|
||||
{"lambda-unique-connection", 0, {"bug"}},
|
||||
{"qdatetime-utc", 0, {"performance"}},
|
||||
{"qgetenv", 0, {"performance"}},
|
||||
{"qstring-insensitive-allocation", 0, {"performance","qstring"}},
|
||||
{"fully-qualified-moc-types", 0, {"bug","qml"}},
|
||||
{"qvariant-template-instantiation", 0, {"performance"}},
|
||||
{"unused-non-trivial-variable", 0, {"readability"}},
|
||||
{"connect-not-normalized", 0, {"performance"}},
|
||||
{"mutable-container-key", 0, {"containers","bug"}},
|
||||
{"qenums", 0, {"deprecation"}},
|
||||
{"qmap-with-pointer-key", 0, {"containers","performance"}},
|
||||
{"qstring-ref", 0, {"performance","qstring"}},
|
||||
{"strict-iterators", 0, {"containers","performance","bug"}},
|
||||
{"writing-to-temporary", 0, {"bug"}},
|
||||
{"container-anti-pattern", 0, {"containers","performance"}},
|
||||
{"qcolor-from-literal", 0, {"performance"}},
|
||||
{"qfileinfo-exists", 0, {"performance"}},
|
||||
{"qstring-arg", 0, {"performance","qstring"}},
|
||||
{"empty-qstringliteral", 0, {"performance"}},
|
||||
{"qt-macros", 0, {"bug"}},
|
||||
{"temporary-iterator", 0, {"containers","bug"}},
|
||||
{"wrong-qglobalstatic", 0, {"performance"}},
|
||||
{"lowercase-qml-type-name", 0, {"qml","bug"}},
|
||||
{"auto-unexpected-qstringbuilder", 1, {"bug","qstring"}},
|
||||
{"connect-3arg-lambda", 1, {"bug"}},
|
||||
{"const-signal-or-slot", 1, {"readability","bug"}},
|
||||
{"detaching-temporary", 1, {"containers","performance"}},
|
||||
{"foreach", 1, {"containers","performance"}},
|
||||
{"incorrect-emit", 1, {"readability"}},
|
||||
{"inefficient-qlist-soft", 1, {"containers","performance"}},
|
||||
{"install-event-filter", 1, {"bug"}},
|
||||
{"non-pod-global-static", 1, {"performance"}},
|
||||
{"post-event", 1, {"bug"}},
|
||||
{"qdeleteall", 1, {"containers","performance"}},
|
||||
{"qlatin1string-non-ascii", 1, {"bug","qstring"}},
|
||||
{"qproperty-without-notify", 1, {"bug"}},
|
||||
{"qstring-left", 1, {"bug","performance","qstring"}},
|
||||
{"range-loop", 1, {"containers","performance"}},
|
||||
{"returning-data-from-temporary", 1, {"bug"}},
|
||||
{"rule-of-two-soft", 1, {"cpp","bug"}},
|
||||
{"child-event-qobject-cast", 1, {"bug"}},
|
||||
{"virtual-signal", 1, {"bug","readability"}},
|
||||
{"overridden-signal", 1, {"bug","readability"}},
|
||||
{"qhash-namespace", 1, {"bug"}},
|
||||
{"skipped-base-method", 1, {"bug","cpp"}},
|
||||
{"unneeded-cast", 3, {"cpp","readability"}},
|
||||
{"ctor-missing-parent-argument", 2, {"bug"}},
|
||||
{"base-class-event", 2, {"bug"}},
|
||||
{"copyable-polymorphic", 2, {"cpp","bug"}},
|
||||
{"function-args-by-ref", 2, {"cpp","performance"}},
|
||||
{"function-args-by-value", 2, {"cpp","performance"}},
|
||||
{"global-const-char-pointer", 2, {"cpp","performance"}},
|
||||
{"implicit-casts", 2, {"cpp","bug"}},
|
||||
{"missing-qobject-macro", 2, {"bug"}},
|
||||
{"missing-typeinfo", 2, {"containers","performance"}},
|
||||
{"old-style-connect", 2, {"performance"}},
|
||||
{"qstring-allocations", 2, {"performance","qstring"}},
|
||||
{"returning-void-expression", 2, {"readability","cpp"}},
|
||||
{"rule-of-three", 2, {"cpp","bug"}},
|
||||
{"virtual-call-ctor", 2, {"cpp","bug"}},
|
||||
{"static-pmf", 2, {"bug"}},
|
||||
{"assert-with-side-effects", 3, {"bug"}},
|
||||
{"detaching-member", 3, {"containers","performance"}},
|
||||
{"thread-with-slots", 3, {"bug"}},
|
||||
{"reserve-candidates", 3, {"containers"}}
|
||||
};
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace CppTools
|
@@ -101,5 +101,8 @@ const char SYMBOLS_FIND_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("CppTools", "C
|
||||
constexpr const char TIDY_DOCUMENTATION_URL_TEMPLATE[]
|
||||
= "https://releases.llvm.org/7.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/%1.html";
|
||||
|
||||
constexpr const char CLAZY_DOCUMENTATION_URL_TEMPLATE[]
|
||||
= "https://github.com/KDE/clazy/blob/master/docs/checks/README-%1.md";
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace CppTools
|
||||
|
Reference in New Issue
Block a user