diff options
-rw-r--r-- | scripts/generateClangTidyChecks.py | 179 | ||||
-rw-r--r-- | src/plugins/clangtools/clangtoolsunittests.cpp | 4 | ||||
-rw-r--r-- | src/plugins/cpptools/clangdiagnosticconfig.cpp | 32 | ||||
-rw-r--r-- | src/plugins/cpptools/clangdiagnosticconfig.h | 11 | ||||
-rw-r--r-- | src/plugins/cpptools/clangdiagnosticconfigswidget.cpp | 233 | ||||
-rw-r--r-- | src/plugins/cpptools/clangdiagnosticconfigswidget.h | 8 | ||||
-rw-r--r-- | src/plugins/cpptools/clangdiagnosticconfigswidget.ui | 20 | ||||
-rw-r--r-- | src/plugins/cpptools/cppcodemodelsettings.cpp | 17 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptools.pro | 3 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptools.qbs | 1 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptools_clangtidychecks.h | 664 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptoolsconstants.h | 1 | ||||
-rw-r--r-- | src/plugins/cpptools/tidychecks.ui | 121 |
13 files changed, 1085 insertions, 209 deletions
diff --git a/scripts/generateClangTidyChecks.py b/scripts/generateClangTidyChecks.py new file mode 100644 index 0000000000..627489521e --- /dev/null +++ b/scripts/generateClangTidyChecks.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +############################################################################ +# +# Copyright (C) 2018 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 collections +import os +import re +import subprocess +import sys + +import common + +def next_common(string, common): + remaining_string = string[len(common):] + parts = re.split("[.\-]+", remaining_string) + return string[:(len(common) + len(parts[0]) + 1)] + +def extract_similar(group, group_common): + subgroups = {} + for key, val in group.items(): + common = next_common(key, group_common) + if common == group_common or common == key: + continue + if key not in group: + continue + + subgroup = {} + for subkey, subval in group.items(): + if not subkey.startswith(common): + continue + subgroup[subkey] = subval + del group[subkey] + if len(subgroup) == 1: + group[key] = val + else: + extract_similar(subgroup, common) + subgroups[common] = subgroup + group.update(subgroups) + if '' in group: + del group[''] + return group + +def print_formatted(group, group_name, indent): + index = 0 + for key in sorted(group): + index += 1 + comma = ',' + if index == len(group): + comma = '' + if len(group[key]) == 0: + print indent + '"' + key[len(group_name):] + '"' + comma + else: + print indent + '{' + print indent + ' "' + key[len(group_name):] + '",' + print indent + ' {' + print_formatted(group[key], key, indent + ' ') + print indent + ' }' + print indent + '}' + comma + +def print_to_header_file(group): + print '''/**************************************************************************** +** +** Copyright (C) 2018 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 { + +struct TidyNode +{ + const std::vector<TidyNode> children; + const char *name = nullptr; + TidyNode(const char *name, std::vector<TidyNode> &&children) + : children(std::move(children)) + , name(name) + {} + TidyNode(const char *name) : name(name) {} +}; + +// CLANG-UPGRADE-CHECK: Run 'scripts/generateClangTidyChecks.py' after Clang upgrade to +// update this header. +static const TidyNode CLANG_TIDY_CHECKS_ROOT +{ + "", + {''' + + print_formatted(group, '', ' ') + + print ''' } +}; + +} // namespace Constants +} // namespace CppTools''' + +def parse_arguments(): + parser = argparse.ArgumentParser(description="Clang-Tidy checks header file generator") + parser.add_argument('--tidy-path', help='path to clang-tidy binary', + default='clang-tidy.exe' if common.is_windows_platform() else 'clang-tidy', dest='tidypath') + return parser.parse_args() + +def main(): + arguments = parse_arguments() + process = subprocess.Popen([arguments.tidypath, '-checks=*', '-list-checks'], stdout=subprocess.PIPE) + lines = process.stdout.read().splitlines() + lines.pop(0) # 'Enabled checks:' + major_checks = ['android-', 'boost-', 'bugprone-', 'cert-', 'clang-analyzer-', + 'cppcoreguidelines-', 'fuchsia-', 'google-', 'hicpp-', 'llvm-', 'misc-', 'modernize-', + 'mpi-', 'objc-', 'performance-', 'readability-'] + current_major = 0 + major_groups = {} + for line in lines: + line = line.strip() + if current_major < (len(major_checks) - 1) and line.startswith(major_checks[current_major + 1]): + current_major += 1 + if major_checks[current_major] not in major_groups: + major_groups[major_checks[current_major]] = {} + major_groups[major_checks[current_major]][line] = {} + + for major_check, group in major_groups.items(): + major_groups[major_check] = extract_similar(group, major_check) + + current_path = os.path.dirname(os.path.abspath(__file__)) + header_path = os.path.abspath(os.path.join(current_path, '..', 'src', 'plugins', 'cpptools', 'cpptools_clangtidychecks.h')) + + default_stdout = sys.stdout + header_file = open(header_path, 'w') + sys.stdout = header_file + print_to_header_file(major_groups) + sys.stdout = default_stdout + header_file.close() +if __name__ == "__main__": + main() diff --git a/src/plugins/clangtools/clangtoolsunittests.cpp b/src/plugins/clangtools/clangtoolsunittests.cpp index 5268416cf9..98577a78a0 100644 --- a/src/plugins/clangtools/clangtoolsunittests.cpp +++ b/src/plugins/clangtools/clangtoolsunittests.cpp @@ -81,8 +81,8 @@ static CppTools::ClangDiagnosticConfig createTidyClazyConfig() config.setDisplayName("Test"); config.setIsReadOnly(true); config.setClangOptions(QStringList{QStringLiteral("-Wno-everything")}); - config.setClangTidyMode(CppTools::ClangDiagnosticConfig::TidyMode::ChecksString); - config.setClangTidyChecksString("-*,modernize-*, misc-*"); + config.setClangTidyMode(CppTools::ClangDiagnosticConfig::TidyMode::ChecksPrefixList); + config.setClangTidyChecks("modernize-*, misc-*"); config.setClazyChecks("level2"); return config; } diff --git a/src/plugins/cpptools/clangdiagnosticconfig.cpp b/src/plugins/cpptools/clangdiagnosticconfig.cpp index c760ed218a..a340e8347c 100644 --- a/src/plugins/cpptools/clangdiagnosticconfig.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfig.cpp @@ -73,8 +73,7 @@ bool ClangDiagnosticConfig::operator==(const ClangDiagnosticConfig &other) const && m_displayName == other.m_displayName && m_clangOptions == other.m_clangOptions && m_clangTidyMode == other.m_clangTidyMode - && m_clangTidyChecksPrefixes == other.m_clangTidyChecksPrefixes - && m_clangTidyChecksString == other.m_clangTidyChecksString + && m_clangTidyChecks == other.m_clangTidyChecks && m_clazyChecks == other.m_clazyChecks && m_isReadOnly == other.m_isReadOnly; } @@ -96,35 +95,12 @@ void ClangDiagnosticConfig::setClangTidyMode(TidyMode mode) QString ClangDiagnosticConfig::clangTidyChecks() const { - QString checks; - if (m_clangTidyMode == TidyMode::ChecksPrefixList) { - checks = QStringLiteral("-*") + clangTidyChecksPrefixes(); - } else if (m_clangTidyMode == TidyMode::ChecksString) { - checks = clangTidyChecksString(); - checks = checks.simplified(); - checks.replace(" ", ""); - } - return checks; + return m_clangTidyChecks; } -QString ClangDiagnosticConfig::clangTidyChecksPrefixes() const +void ClangDiagnosticConfig::setClangTidyChecks(const QString &checks) { - return m_clangTidyChecksPrefixes; -} - -void ClangDiagnosticConfig::setClangTidyChecksPrefixes(const QString &checks) -{ - m_clangTidyChecksPrefixes = checks; -} - -QString ClangDiagnosticConfig::clangTidyChecksString() const -{ - return m_clangTidyChecksString; -} - -void ClangDiagnosticConfig::setClangTidyChecksString(const QString &checks) -{ - m_clangTidyChecksString = checks; + m_clangTidyChecks = checks; } QString ClangDiagnosticConfig::clazyChecks() const diff --git a/src/plugins/cpptools/clangdiagnosticconfig.h b/src/plugins/cpptools/clangdiagnosticconfig.h index 6423aca181..faaf439ad3 100644 --- a/src/plugins/cpptools/clangdiagnosticconfig.h +++ b/src/plugins/cpptools/clangdiagnosticconfig.h @@ -41,7 +41,6 @@ public: { Disabled = 0, ChecksPrefixList, - ChecksString, File }; @@ -55,12 +54,7 @@ public: void setClangOptions(const QStringList &options); QString clangTidyChecks() const; - - QString clangTidyChecksPrefixes() const; - void setClangTidyChecksPrefixes(const QString &checks); - - QString clangTidyChecksString() const; - void setClangTidyChecksString(const QString &checks); + void setClangTidyChecks(const QString &checks); TidyMode clangTidyMode() const; void setClangTidyMode(TidyMode mode); @@ -79,8 +73,7 @@ private: QString m_displayName; QStringList m_clangOptions; TidyMode m_clangTidyMode = TidyMode::Disabled; - QString m_clangTidyChecksPrefixes; - QString m_clangTidyChecksString; + QString m_clangTidyChecks; QString m_clazyChecks; bool m_isReadOnly = false; }; diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp index 169362d397..22b2950e5a 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp @@ -26,28 +26,169 @@ #include "clangdiagnosticconfigswidget.h" #include "cppcodemodelsettings.h" +#include "cpptools_clangtidychecks.h" #include "cpptoolsreuse.h" #include "ui_clangdiagnosticconfigswidget.h" #include "ui_clangbasechecks.h" #include "ui_clazychecks.h" #include "ui_tidychecks.h" +#include <projectexplorer/selectablefilesmodel.h> + #include <utils/algorithm.h> #include <utils/qtcassert.h> #include <utils/utilsicons.h> #include <QDebug> +#include <QDialogButtonBox> #include <QInputDialog> #include <QPushButton> #include <QUuid> namespace CppTools { +static void buildTree(ProjectExplorer::Tree *parent, + ProjectExplorer::Tree *current, + const Constants::TidyNode &node) +{ + current->name = QString::fromUtf8(node.name); + current->isDir = node.children.size(); + if (parent) { + current->fullPath = parent->fullPath + current->name; + parent->childDirectories.push_back(current); + } else { + current->fullPath = Utils::FileName::fromString(current->name); + } + current->parent = parent; + for (const Constants::TidyNode &nodeChild : node.children) + buildTree(current, new ProjectExplorer::Tree, nodeChild); +} + +class TidyChecksTreeModel final : public ProjectExplorer::SelectableFilesModel +{ + Q_OBJECT + +public: + TidyChecksTreeModel() + : ProjectExplorer::SelectableFilesModel(nullptr) + { + buildTree(nullptr, m_root, Constants::CLANG_TIDY_CHECKS_ROOT); + } + + QString selectedChecks() const + { + QString checks; + collectChecks(m_root, checks); + return "-*" + checks; + } + + void selectChecks(const QString &checks) + { + m_root->checked = Qt::Unchecked; + propagateDown(index(0, 0, QModelIndex())); + + QStringList checksList = checks.simplified().remove(" ") + .split(",", QString::SkipEmptyParts); + + for (QString &check : checksList) { + Qt::CheckState state; + if (check.startsWith("-")) { + check = check.right(check.length() - 1); + state = Qt::Unchecked; + } else { + state = Qt::Checked; + } + const QModelIndex index = indexForCheck(check); + if (!index.isValid()) + continue; + auto node = static_cast<ProjectExplorer::Tree *>(index.internalPointer()); + node->checked = state; + propagateUp(index); + propagateDown(index); + } + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const final + { + if (!index.isValid() || role == Qt::DecorationRole) + return QVariant(); + if (role == Qt::DisplayRole) { + auto *node = static_cast<ProjectExplorer::Tree *>(index.internalPointer()); + return node->isDir ? (node->name + "*") : node->name; + } + return ProjectExplorer::SelectableFilesModel::data(index, 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()); + + QModelIndex result; + traverse(index(0, 0, QModelIndex()), [&](const QModelIndex &index){ + using ProjectExplorer::Tree; + if (result.isValid()) + return false; + + auto *node = static_cast<Tree *>(index.internalPointer()); + const QString nodeName = node->fullPath.toString(); + if ((check.endsWith("*") && nodeName.startsWith(check.left(check.length() - 1))) + || (!node->isDir && nodeName == check)) { + result = index; + return false; + } + + if (!check.startsWith(nodeName)) + return false; + + return true; + }); + return result; + } + + static void collectChecks(const ProjectExplorer::Tree *root, QString &checks) + { + if (root->checked == Qt::Unchecked) + return; + if (root->checked == Qt::Checked) { + checks += "," + root->fullPath.toString(); + if (root->isDir) + checks += "*"; + return; + } + for (const ProjectExplorer::Tree *t : root->childDirectories) + collectChecks(t, checks); + } +}; + ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &configToSelect, QWidget *parent) : QWidget(parent) , m_ui(new Ui::ClangDiagnosticConfigsWidget) , m_diagnosticConfigsModel(codeModelSettings()->clangCustomDiagnosticConfigs()) + , m_tidyTreeModel(new TidyChecksTreeModel()) { m_ui->setupUi(this); setupTabs(); @@ -134,22 +275,10 @@ void ClangDiagnosticConfigsWidget::onClangTidyModeChanged(int index) syncClangTidyWidgets(config); } -void ClangDiagnosticConfigsWidget::onClangTidyItemChanged(QListWidgetItem *item) +void ClangDiagnosticConfigsWidget::onClangTidyTreeChanged() { - const QString prefix = item->text(); ClangDiagnosticConfig config = selectedConfig(); - QString checks = config.clangTidyChecksPrefixes(); - item->checkState() == Qt::Checked - ? checks.append(',' + prefix) - : checks.remove(',' + prefix); - config.setClangTidyChecksPrefixes(checks); - updateConfig(config); -} - -void ClangDiagnosticConfigsWidget::onClangTidyLineEdited(const QString &text) -{ - ClangDiagnosticConfig config = selectedConfig(); - config.setClangTidyChecksString(text); + config.setClangTidyChecks(m_tidyTreeModel->selectedChecks()); updateConfig(config); } @@ -302,18 +431,13 @@ void ClangDiagnosticConfigsWidget::syncClangTidyWidgets(const ClangDiagnosticCon switch (tidyMode) { case ClangDiagnosticConfig::TidyMode::Disabled: case ClangDiagnosticConfig::TidyMode::File: - m_tidyChecks->checksString->setVisible(false); - m_tidyChecks->checksListWrapper->setCurrentIndex(1); - break; - case ClangDiagnosticConfig::TidyMode::ChecksString: - m_tidyChecks->checksString->setVisible(true); + m_tidyChecks->plainTextEditButton->setVisible(false); m_tidyChecks->checksListWrapper->setCurrentIndex(1); - m_tidyChecks->checksString->setText(config.clangTidyChecksString()); break; case ClangDiagnosticConfig::TidyMode::ChecksPrefixList: - m_tidyChecks->checksString->setVisible(false); + m_tidyChecks->plainTextEditButton->setVisible(true); m_tidyChecks->checksListWrapper->setCurrentIndex(0); - syncTidyChecksList(config); + syncTidyChecksToTree(config); break; } @@ -321,25 +445,9 @@ void ClangDiagnosticConfigsWidget::syncClangTidyWidgets(const ClangDiagnosticCon connectClangTidyItemChanged(); } -void ClangDiagnosticConfigsWidget::syncTidyChecksList(const ClangDiagnosticConfig &config) +void ClangDiagnosticConfigsWidget::syncTidyChecksToTree(const ClangDiagnosticConfig &config) { - const QString tidyChecks = config.clangTidyChecksPrefixes(); - for (int row = 0; row < m_tidyChecks->checksPrefixesList->count(); ++row) { - QListWidgetItem *item = m_tidyChecks->checksPrefixesList->item(row); - - Qt::ItemFlags flags = item->flags(); - flags |= Qt::ItemIsUserCheckable; - if (config.isReadOnly()) - flags &= ~Qt::ItemIsEnabled; - else - flags |= Qt::ItemIsEnabled; - item->setFlags(flags); - - if (tidyChecks.indexOf(item->text()) != -1) - item->setCheckState(Qt::Checked); - else - item->setCheckState(Qt::Unchecked); - } + m_tidyTreeModel->selectChecks(config.clangTidyChecks()); } void ClangDiagnosticConfigsWidget::syncClazyWidgets(const ClangDiagnosticConfig &config) @@ -411,10 +519,8 @@ void ClangDiagnosticConfigsWidget::connectClangTidyItemChanged() static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ClangDiagnosticConfigsWidget::onClangTidyModeChanged); - connect(m_tidyChecks->checksPrefixesList, &QListWidget::itemChanged, - this, &ClangDiagnosticConfigsWidget::onClangTidyItemChanged); - connect(m_tidyChecks->checksString, &QLineEdit::textEdited, - this, &ClangDiagnosticConfigsWidget::onClangTidyLineEdited); + connect(m_tidyTreeModel.get(), &TidyChecksTreeModel::dataChanged, + this, &ClangDiagnosticConfigsWidget::onClangTidyTreeChanged); } void ClangDiagnosticConfigsWidget::disconnectClangTidyItemChanged() @@ -423,10 +529,8 @@ void ClangDiagnosticConfigsWidget::disconnectClangTidyItemChanged() static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ClangDiagnosticConfigsWidget::onClangTidyModeChanged); - disconnect(m_tidyChecks->checksPrefixesList, &QListWidget::itemChanged, - this, &ClangDiagnosticConfigsWidget::onClangTidyItemChanged); - disconnect(m_tidyChecks->checksString, &QLineEdit::textEdited, - this, &ClangDiagnosticConfigsWidget::onClangTidyLineEdited); + disconnect(m_tidyTreeModel.get(), &TidyChecksTreeModel::dataChanged, + this, &ClangDiagnosticConfigsWidget::onClangTidyTreeChanged); } void ClangDiagnosticConfigsWidget::connectClazyRadioButtonClicked(QRadioButton *button) @@ -493,6 +597,37 @@ void ClangDiagnosticConfigsWidget::setupTabs() 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); + connect(m_tidyChecks->plainTextEditButton, &QPushButton::clicked, this, [this]() { + QDialog dialog; + dialog.setWindowTitle(tr("Checks")); + dialog.setLayout(new QVBoxLayout); + auto *textEdit = new QTextEdit(&dialog); + dialog.layout()->addWidget(textEdit); + auto *buttonsBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog.layout()->addWidget(buttonsBox); + QObject::connect(buttonsBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + QObject::connect(buttonsBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + const QString initialChecks = m_tidyTreeModel->selectedChecks(); + textEdit->setPlainText(initialChecks); + + QObject::connect(&dialog, &QDialog::accepted, [=, &initialChecks]() { + const QString updatedChecks = textEdit->toPlainText(); + if (updatedChecks == initialChecks) + return; + + disconnectClangTidyItemChanged(); + + // Also throws away invalid options. + m_tidyTreeModel->selectChecks(updatedChecks); + onClangTidyTreeChanged(); + + connectClangTidyItemChanged(); + }); + dialog.exec(); + }); + connectClangTidyItemChanged(); m_ui->tabWidget->addTab(m_clangBaseChecksWidget, tr("Clang")); @@ -502,3 +637,5 @@ void ClangDiagnosticConfigsWidget::setupTabs() } } // CppTools namespace + +#include "clangdiagnosticconfigswidget.moc" diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.h b/src/plugins/cpptools/clangdiagnosticconfigswidget.h index 6ad9c3031e..5307593220 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.h +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.h @@ -50,6 +50,8 @@ class ClazyChecks; class TidyChecks; } +class TidyChecksTreeModel; + class CPPTOOLS_EXPORT ClangDiagnosticConfigsWidget : public QWidget { Q_OBJECT @@ -70,8 +72,7 @@ private: void onCopyButtonClicked(); void onRemoveButtonClicked(); void onClangTidyModeChanged(int index); - void onClangTidyItemChanged(QListWidgetItem *item); - void onClangTidyLineEdited(const QString &text); + void onClangTidyTreeChanged(); void onClazyRadioButtonChanged(bool checked); void onDiagnosticOptionsEdited(); @@ -81,7 +82,7 @@ private: void syncOtherWidgetsToComboBox(); void syncClangTidyWidgets(const ClangDiagnosticConfig &config); void syncClazyWidgets(const ClangDiagnosticConfig &config); - void syncTidyChecksList(const ClangDiagnosticConfig &config); + void syncTidyChecksToTree(const ClangDiagnosticConfig &config); void updateConfig(const CppTools::ClangDiagnosticConfig &config); @@ -115,6 +116,7 @@ private: std::unique_ptr<CppTools::Ui::TidyChecks> m_tidyChecks; QWidget *m_tidyChecksWidget = nullptr; + std::unique_ptr<TidyChecksTreeModel> m_tidyTreeModel; int m_selectedConfigIndex = 0; }; diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.ui b/src/plugins/cpptools/clangdiagnosticconfigswidget.ui index cb9ef98a3c..e80ccef4fe 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.ui +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.ui @@ -17,7 +17,20 @@ <item> <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> - <widget class="QListWidget" name="configChooserList"/> + <widget class="QListWidget" name="configChooserList"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>156</height> + </size> + </property> + </widget> </item> <item> <layout class="QVBoxLayout" name="verticalLayout_3"> @@ -40,10 +53,13 @@ <property name="orientation"> <enum>Qt::Vertical</enum> </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> - <height>40</height> + <height>100</height> </size> </property> </spacer> diff --git a/src/plugins/cpptools/cppcodemodelsettings.cpp b/src/plugins/cpptools/cppcodemodelsettings.cpp index 6b54c266e0..5aaaa2c105 100644 --- a/src/plugins/cpptools/cppcodemodelsettings.cpp +++ b/src/plugins/cpptools/cppcodemodelsettings.cpp @@ -55,12 +55,9 @@ static QString clangDiagnosticConfigsArrayDisplayNameKey() static QString clangDiagnosticConfigsArrayWarningsKey() { return QLatin1String("diagnosticOptions"); } -static QString clangDiagnosticConfigsArrayClangTidyChecksPrefixesKey() +static QString clangDiagnosticConfigsArrayClangTidyChecksKey() { return QLatin1String("clangTidyChecks"); } -static QString clangDiagnosticConfigsArrayClangTidyChecksStringKey() -{ return QLatin1String("clangTidyChecksString"); } - static QString clangDiagnosticConfigsArrayClangTidyModeKey() { return QLatin1String("clangTidyMode"); } @@ -96,10 +93,8 @@ static ClangDiagnosticConfigs customDiagnosticConfigsFromSettings(QSettings *s) config.setClangOptions(s->value(clangDiagnosticConfigsArrayWarningsKey()).toStringList()); config.setClangTidyMode(static_cast<ClangDiagnosticConfig::TidyMode>( s->value(clangDiagnosticConfigsArrayClangTidyModeKey()).toInt())); - config.setClangTidyChecksPrefixes( - s->value(clangDiagnosticConfigsArrayClangTidyChecksPrefixesKey()).toString()); - config.setClangTidyChecksString( - s->value(clangDiagnosticConfigsArrayClangTidyChecksStringKey()).toString()); + config.setClangTidyChecks( + s->value(clangDiagnosticConfigsArrayClangTidyChecksKey()).toString()); config.setClazyChecks(s->value(clangDiagnosticConfigsArrayClazyChecksKey()).toString()); configs.append(config); } @@ -157,10 +152,8 @@ void CppCodeModelSettings::toSettings(QSettings *s) s->setValue(clangDiagnosticConfigsArrayWarningsKey(), config.clangOptions()); s->setValue(clangDiagnosticConfigsArrayClangTidyModeKey(), static_cast<int>(config.clangTidyMode())); - s->setValue(clangDiagnosticConfigsArrayClangTidyChecksPrefixesKey(), - config.clangTidyChecksPrefixes()); - s->setValue(clangDiagnosticConfigsArrayClangTidyChecksStringKey(), - config.clangTidyChecksString()); + s->setValue(clangDiagnosticConfigsArrayClangTidyChecksKey(), + config.clangTidyChecks()); s->setValue(clangDiagnosticConfigsArrayClazyChecksKey(), config.clazyChecks()); } s->endArray(); diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 7666d8521e..b9093ee79b 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -100,7 +100,8 @@ HEADERS += \ cppsymbolinfo.h \ cursorineditor.h \ wrappablelineedit.h \ - usages.h + usages.h \ + cpptools_clangtidychecks.h SOURCES += \ abstracteditorsupport.cpp \ diff --git a/src/plugins/cpptools/cpptools.qbs b/src/plugins/cpptools/cpptools.qbs index 80fdfd78b7..c218f1ceac 100644 --- a/src/plugins/cpptools/cpptools.qbs +++ b/src/plugins/cpptools/cpptools.qbs @@ -155,6 +155,7 @@ Project { "cppsourceprocessor.cpp", "cppsourceprocessor.h", "cpptools.qrc", + "cpptools_clangtidychecks.h", "cpptools_global.h", "cpptools_utils.h", "cpptoolsbridge.cpp", diff --git a/src/plugins/cpptools/cpptools_clangtidychecks.h b/src/plugins/cpptools/cpptools_clangtidychecks.h new file mode 100644 index 0000000000..9fc1fc516d --- /dev/null +++ b/src/plugins/cpptools/cpptools_clangtidychecks.h @@ -0,0 +1,664 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 { + +struct TidyNode +{ + const std::vector<TidyNode> children; + const char *name = nullptr; + TidyNode(const char *name, std::vector<TidyNode> &&children) + : children(std::move(children)) + , name(name) + {} + TidyNode(const char *name) : name(name) {} +}; + +// CLANG-UPGRADE-CHECK: Run 'scripts/generateClangTidyChecks.py' after Clang upgrade to +// update this header. +static const TidyNode CLANG_TIDY_CHECKS_ROOT +{ + "", + { + { + "android-", + { + { + "cloexec-", + { + "accept", + "accept4", + "creat", + "dup", + { + "epoll-", + { + "create", + "create1" + } + }, + "fopen", + { + "inotify-", + { + "init", + "init1" + } + }, + "memfd-create", + "open", + "socket" + } + } + } + }, + { + "boost-", + { + "use-to-string" + } + }, + { + "bugprone-", + { + "argument-comment", + "assert-side-effect", + "bool-pointer-implicit-conversion", + "copy-constructor-init", + "dangling-handle", + "fold-init-type", + "forward-declaration-namespace", + "inaccurate-erase", + "integer-division", + "misplaced-operator-in-strlen-in-alloc", + "move-forwarding-reference", + "multiple-statement-macro", + "string-constructor", + "suspicious-memset-usage", + "undefined-memory-manipulation", + "use-after-move", + "virtual-near-miss" + } + }, + { + "cert-", + { + "dcl03-c", + "dcl21-cpp", + "dcl50-cpp", + "dcl54-cpp", + "dcl58-cpp", + "dcl59-cpp", + "env33-c", + "err09-cpp", + "err34-c", + "err52-cpp", + "err58-cpp", + "err60-cpp", + "err61-cpp", + "fio38-c", + "flp30-c", + "msc30-c", + "msc50-cpp", + "oop11-cpp" + } + }, + { + "clang-analyzer-", + { + "apiModeling.google.GTest", + { + "core.", + { + "CallAndMessage", + "DivideZero", + "DynamicTypePropagation", + "NonNullParamChecker", + "NonnilStringConstants", + "NullDereference", + "StackAddressEscape", + "UndefinedBinaryOperatorResult", + "VLASize", + { + "builtin.", + { + "BuiltinFunctions", + "NoReturnFunctions" + } + }, + { + "uninitialized.", + { + "ArraySubscript", + "Assign", + "Branch", + "CapturedBlockVariable", + "UndefReturn" + } + } + } + }, + { + "cplusplus.", + { + "NewDelete", + "NewDeleteLeaks", + "SelfAssignment" + } + }, + "deadcode.DeadStores", + "llvm.Conventions", + { + "nullability.", + { + "NullPassedToNonnull", + "NullReturnedFromNonnull", + "NullableDereferenced", + "NullablePassedToNonnull", + "NullableReturnedFromNonnull" + } + }, + { + "optin.", + { + "cplusplus.VirtualCall", + "mpi.MPI-Checker", + { + "osx.", + { + { + "cocoa.", + { + { + "localizability.", + { + "EmptyLocalizationContextChecker", + "NonLocalizedStringChecker" + } + } + } + } + } + }, + "performance.Padding", + "portability.UnixAPI" + } + }, + { + "osx.", + { + "API", + "NumberObjectConversion", + "ObjCProperty", + "SecKeychainAPI", + { + "cocoa.", + { + "AtSync", + "ClassRelease", + "Dealloc", + "IncompatibleMethodTypes", + "Loops", + "MissingSuperCall", + "NSAutoreleasePool", + "NSError", + "NilArg", + "NonNilReturnValue", + "ObjCGenerics", + "RetainCount", + "SelfInit", + "SuperDealloc", + "UnusedIvars", + "VariadicMethodTypes" + } + }, + { + "coreFoundation.", + { + "CFError", + "CFNumber", + "CFRetainRelease", + { + "containers.", + { + "OutOfBounds", + "PointerSizedValues" + } + } + } + } + } + }, + { + "security.", + { + "FloatLoopCounter", + { + "insecureAPI.", + { + "UncheckedReturn", + "getpw", + "gets", + "mkstemp", + "mktemp", + "rand", + "strcpy", + "vfork" + } + } + } + }, + { + "unix.", + { + "API", + "Malloc", + "MallocSizeof", + "MismatchedDeallocator", + "StdCLibraryFunctions", + "Vfork", + { + "cstring.", + { + "BadSizeArg", + "NullArg" + } + } + } + }, + { + "valist.", + { + "CopyToSelf", + "Uninitialized", + "Unterminated" + } + } + } + }, + { + "cppcoreguidelines-", + { + "c-copy-assignment-signature", + "interfaces-global-init", + "no-malloc", + "owning-memory", + { + "pro-", + { + { + "bounds-", + { + "array-to-pointer-decay", + "constant-array-index", + "pointer-arithmetic" + } + }, + { + "type-", + { + "const-cast", + "cstyle-cast", + "member-init", + "reinterpret-cast", + "static-cast-downcast", + "union-access", + "vararg" + } + } + } + }, + "slicing", + "special-member-functions" + } + }, + { + "fuchsia-", + { + "default-arguments", + "overloaded-operator", + "virtual-inheritance" + } + }, + { + "google-", + { + { + "build-", + { + "explicit-make-pair", + "namespaces", + "using-namespace" + } + }, + "default-arguments", + "explicit-constructor", + "global-names-in-headers", + { + "objc-", + { + "avoid-throwing-exception", + "global-variable-declaration" + } + }, + { + "readability-", + { + "braces-around-statements", + "casting", + "function-size", + "namespace-comments", + "redundant-smartptr-get", + "todo" + } + }, + { + "runtime-", + { + "int", + "member-string-references", + "operator", + "references" + } + } + } + }, + { + "hicpp-", + { + "braces-around-statements", + "deprecated-headers", + "exception-baseclass", + "explicit-conversions", + "function-size", + "invalid-access-moved", + "member-init", + "move-const-arg", + "named-parameter", + "new-delete-operators", + { + "no-", + { + "array-decay", + "assembler", + "malloc" + } + }, + "noexcept-move", + "signed-bitwise", + "special-member-functions", + "static-assert", + "undelegated-constructor", + { + "use-", + { + "auto", + "emplace", + { + "equals-", + { + "default", + "delete" + } + }, + "noexcept", + "nullptr", + "override" + } + }, + "vararg" + } + }, + { + "llvm-", + { + "header-guard", + "include-order", + "namespace-comment", + "twine-local" + } + }, + { + "misc-", + { + "definitions-in-headers", + "forwarding-reference-overload", + "incorrect-roundings", + "lambda-function-name", + { + "macro-", + { + "parentheses", + "repeated-side-effects" + } + }, + { + "misplaced-", + { + "const", + "widening-cast" + } + }, + "new-delete-overloads", + "non-copyable-objects", + "redundant-expression", + { + "sizeof-", + { + "container", + "expression" + } + }, + "static-assert", + { + "string-", + { + "compare", + "integer-assignment", + "literal-with-embedded-nul" + } + }, + { + "suspicious-", + { + "enum-usage", + "missing-comma", + "semicolon", + "string-compare" + } + }, + "swapped-arguments", + "throw-by-value-catch-by-reference", + "unconventional-assign-operator", + "undelegated-constructor", + "uniqueptr-reset-release", + { + "unused-", + { + "alias-decls", + "parameters", + "raii", + "using-decls" + } + } + } + }, + { + "modernize-", + { + "avoid-bind", + "deprecated-headers", + "loop-convert", + { + "make-", + { + "shared", + "unique" + } + }, + "pass-by-value", + "raw-string-literal", + "redundant-void-arg", + { + "replace-", + { + "auto-ptr", + "random-shuffle" + } + }, + "return-braced-init-list", + "shrink-to-fit", + "unary-static-assert", + { + "use-", + { + "auto", + "bool-literals", + "default-member-init", + "emplace", + { + "equals-", + { + "default", + "delete" + } + }, + "noexcept", + "nullptr", + "override", + "transparent-functors", + "using" + } + } + } + }, + { + "mpi-", + { + "buffer-deref", + "type-mismatch" + } + }, + { + "objc-", + { + { + "avoid-", + { + "nserror-init", + "spinlock" + } + }, + "forbidden-subclassing", + "property-declaration" + } + }, + { + "performance-", + { + "faster-string-find", + "for-range-copy", + "implicit-conversion-in-loop", + { + "inefficient-", + { + "algorithm", + "string-concatenation", + "vector-operation" + } + }, + { + "move-", + { + "const-arg", + "constructor-init" + } + }, + "noexcept-move-constructor", + "type-promotion-in-math-fn", + { + "unnecessary-", + { + "copy-initialization", + "value-param" + } + } + } + }, + { + "readability-", + { + "avoid-const-params-in-decls", + "braces-around-statements", + "container-size-empty", + "delete-null-pointer", + "deleted-default", + "else-after-return", + "function-size", + "identifier-naming", + "implicit-bool-conversion", + "inconsistent-declaration-parameter-name", + "misleading-indentation", + "misplaced-array-index", + "named-parameter", + "non-const-parameter", + { + "redundant-", + { + "control-flow", + "declaration", + "function-ptr-dereference", + "member-init", + "smartptr-get", + { + "string-", + { + "cstr", + "init" + } + } + } + }, + "simplify-boolean-expr", + { + "static-", + { + "accessed-through-instance", + "definition-in-anonymous-namespace" + } + }, + "uniqueptr-delete-release" + } + } + } +}; + +} // namespace Constants +} // namespace CppTools diff --git a/src/plugins/cpptools/cpptoolsconstants.h b/src/plugins/cpptools/cpptoolsconstants.h index ce49e21b92..51ece3d025 100644 --- a/src/plugins/cpptools/cpptoolsconstants.h +++ b/src/plugins/cpptools/cpptoolsconstants.h @@ -93,6 +93,5 @@ const char LOCATOR_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("CppTools", "C++ Cl const char SYMBOLS_FIND_FILTER_ID[] = "Symbols"; const char SYMBOLS_FIND_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("CppTools", "C++ Symbols"); - } // namespace Constants } // namespace CppTools diff --git a/src/plugins/cpptools/tidychecks.ui b/src/plugins/cpptools/tidychecks.ui index 0d144f956e..faa8e19b24 100644 --- a/src/plugins/cpptools/tidychecks.ui +++ b/src/plugins/cpptools/tidychecks.ui @@ -37,12 +37,7 @@ </item> <item> <property name="text"> - <string>Select Clang-Tidy prefixes</string> - </property> - </item> - <item> - <property name="text"> - <string>Provide Clang-Tidy checks string</string> + <string>Select Checks</string> </property> </item> <item> @@ -53,6 +48,13 @@ </widget> </item> <item> + <widget class="QPushButton" name="plainTextEditButton"> + <property name="text"> + <string>Edit Checks as String...</string> + </property> + </widget> + </item> + <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -68,9 +70,6 @@ </layout> </item> <item> - <widget class="QLineEdit" name="checksString"/> - </item> - <item> <widget class="QStackedWidget" name="checksListWrapper"> <widget class="QWidget" name="checksPage"> <layout class="QVBoxLayout" name="verticalLayout"> @@ -87,87 +86,16 @@ <number>0</number> </property> <item> - <widget class="QListWidget" name="checksPrefixesList"> - <item> - <property name="text"> - <string>android-*</string> - </property> - </item> - <item> - <property name="text"> - <string>boost-*</string> - </property> - </item> - <item> - <property name="text"> - <string>bugprone-*</string> - </property> - </item> - <item> - <property name="text"> - <string>cert-*</string> - </property> - </item> - <item> - <property name="text"> - <string>cppcoreguidelines-*</string> - </property> - </item> - <item> - <property name="text"> - <string>clang-analyzer-*</string> - </property> - </item> - <item> - <property name="text"> - <string>clang-diagnostic-*</string> - </property> - </item> - <item> - <property name="text"> - <string>google-*</string> - </property> - </item> - <item> - <property name="text"> - <string>hicpp-*</string> - </property> - </item> - <item> - <property name="text"> - <string>llvm-*</string> - </property> - </item> - <item> - <property name="text"> - <string>misc-*</string> - </property> - </item> - <item> - <property name="text"> - <string>modernize-*</string> - </property> - </item> - <item> - <property name="text"> - <string>mpi-*</string> - </property> - </item> - <item> - <property name="text"> - <string>objc-*</string> - </property> - </item> - <item> - <property name="text"> - <string>performance-*</string> - </property> - </item> - <item> - <property name="text"> - <string>readability-*</string> - </property> - </item> + <widget class="QTreeView" name="checksPrefixesTree"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>300</height> + </size> + </property> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> </widget> </item> </layout> @@ -186,19 +114,6 @@ <property name="bottomMargin"> <number>0</number> </property> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>237</height> - </size> - </property> - </spacer> - </item> </layout> </widget> </widget> |