From 1b4de8d769a14bfebec508b1af115d87a918c618 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 29 Nov 2019 09:52:02 +0100 Subject: [PATCH] ClangTools: Add help context menu entry ...that opens the documentation page for the current diagnostic. Change-Id: I398fdc82bb118a80536acbb12420a9bac84e66c9 Reviewed-by: Cristian Adam --- .../clangdiagnostictooltipwidget.cpp | 10 ++------ src/plugins/clangtools/clangtool.cpp | 12 ++++++++++ src/plugins/clangtools/clangtool.h | 2 ++ .../clangtools/clangtoolsdiagnosticmodel.cpp | 4 ++++ .../clangtools/clangtoolsdiagnosticmodel.h | 3 ++- .../clangtools/clangtoolsdiagnosticview.cpp | 16 ++++++++++++- .../clangtools/clangtoolsdiagnosticview.h | 10 +++++++- src/plugins/clangtools/clangtoolsutils.cpp | 23 +++++++++++++++++++ src/plugins/clangtools/clangtoolsutils.h | 2 ++ .../clangtools/diagnosticconfigswidget.cpp | 5 +--- src/plugins/cpptools/cpptoolsconstants.h | 7 ++++++ 11 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp index fe77b0156cb..34aa4816be0 100644 --- a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp +++ b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp @@ -49,13 +49,6 @@ using Internal::ClangFixItOperation; namespace { -// CLANG-UPGRADE-CHECK: Checks/update URLs. -// -// Once it gets dedicated documentation pages for released versions, -// use them instead of pointing to master, as checks might vanish. -const char CLAZY_DOCUMENTATION_URL_TEMPLATE[] - = "https://github.com/KDE/clazy/blob/master/docs/checks/README-%1.md"; - const char LINK_ACTION_GOTO_LOCATION[] = "#gotoLocation"; const char LINK_ACTION_APPLY_FIX[] = "#applyFix"; @@ -230,7 +223,8 @@ private: // Clazy if (ClangCodeModel::Utils::DiagnosticTextInfo::isClazyOption(option)) { option = optionAsUtf8String.mid(8); // Remove "-Wclazy-" prefix. - return QString::fromUtf8(CLAZY_DOCUMENTATION_URL_TEMPLATE).arg(option); + return QString::fromUtf8(CppTools::Constants::CLAZY_DOCUMENTATION_URL_TEMPLATE) + .arg(option); } // Clang itself diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 9374090a714..fc8c32e0694 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -70,6 +70,7 @@ #include #include +#include #include #include #include @@ -420,6 +421,8 @@ ClangTool::ClangTool() m_diagnosticView->setSortingEnabled(true); m_diagnosticView->sortByColumn(Debugger::DetailedErrorView::DiagnosticColumn, Qt::AscendingOrder); + connect(m_diagnosticView, &DiagnosticView::showHelp, + this, &ClangTool::help); connect(m_diagnosticView, &DiagnosticView::showFilter, this, &ClangTool::filter); connect(m_diagnosticView, &DiagnosticView::clearFilter, @@ -930,6 +933,15 @@ void ClangTool::updateForInitialState() } } +void ClangTool::help() +{ + if (DiagnosticItem *item = diagnosticItem(m_diagnosticView->currentIndex())) { + const QString url = documentationUrl(item->diagnostic().name); + if (!url.isEmpty()) + QDesktopServices::openUrl(url); + } +} + void ClangTool::setFilterOptions(const OptionalFilterOptions &filterOptions) { m_diagnosticFilterModel->setFilterOptions(filterOptions); diff --git a/src/plugins/clangtools/clangtool.h b/src/plugins/clangtools/clangtool.h index 6a7940e63fb..3ee72da83c7 100644 --- a/src/plugins/clangtools/clangtool.h +++ b/src/plugins/clangtools/clangtool.h @@ -126,6 +126,8 @@ private: void updateForCurrentState(); void updateForInitialState(); + void help(); + void filter(); void clearFilter(); void filterForCurrentKind(); diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp index 07030687d0b..c7e96b382d8 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp @@ -433,6 +433,8 @@ QVariant DiagnosticItem::data(int column, int role) const } break; } + case ClangToolsDiagnosticModel::DocumentationUrlRole: + return documentationUrl(m_diagnostic.name); case Qt::DisplayRole: return QString("%1: %2").arg(lineColumnString(m_diagnostic.location), m_diagnostic.description); @@ -514,6 +516,8 @@ QVariant ExplainingStepItem::data(int column, int role) const return m_step.message; case ClangToolsDiagnosticModel::DiagnosticRole: return QVariant::fromValue(static_cast(parent())->diagnostic()); + case ClangToolsDiagnosticModel::DocumentationUrlRole: + return parent()->data(column, role); case Qt::DisplayRole: { const QString mainFilePath = static_cast(parent())->diagnostic().location.filePath; const QString locationString diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h index ecd3e21e91f..b27e01b383c 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h +++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h @@ -122,7 +122,8 @@ public: enum ItemRole { DiagnosticRole = Debugger::DetailedErrorView::FullTextRole + 1, TextRole, - CheckBoxEnabledRole + CheckBoxEnabledRole, + DocumentationUrlRole, }; QSet allChecks() const; diff --git a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp index 3a42ef7fe01..cf88a37c627 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp @@ -151,6 +151,14 @@ DiagnosticView::DiagnosticView(QWidget *parent) m_separator = new QAction(this); m_separator->setSeparator(true); + m_separator2 = new QAction(this); + m_separator2->setSeparator(true); + + m_help = new QAction(tr("Web Page"), this); + m_help->setIcon(Utils::Icons::INFO.icon()); + connect(m_help, &QAction::triggered, + this, &DiagnosticView::showHelp); + m_suppressAction = new QAction(tr("Suppress This Diagnostic"), this); connect(m_suppressAction, &QAction::triggered, this, &DiagnosticView::suppressCurrentDiagnostic); @@ -259,17 +267,23 @@ QModelIndex DiagnosticView::getTopLevelIndex(const QModelIndex &index, Direction QList DiagnosticView::customActions() const { const QModelIndex currentIndex = selectionModel()->currentIndex(); + const bool isDiagnosticItem = currentIndex.parent().isValid(); + const QString docUrl + = model()->data(currentIndex, ClangToolsDiagnosticModel::DocumentationUrlRole).toString(); + m_help->setEnabled(isDiagnosticItem && !docUrl.isEmpty()); m_filterForCurrentKind->setEnabled(isDiagnosticItem); m_filterOutCurrentKind->setEnabled(isDiagnosticItem); m_suppressAction->setEnabled(isDiagnosticItem); return { + m_help, + m_separator, m_showFilter, m_clearFilter, m_filterForCurrentKind, m_filterOutCurrentKind, - m_separator, + m_separator2, m_suppressAction, }; } diff --git a/src/plugins/clangtools/clangtoolsdiagnosticview.h b/src/plugins/clangtools/clangtoolsdiagnosticview.h index 6e591bb376f..83a440c6071 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticview.h +++ b/src/plugins/clangtools/clangtoolsdiagnosticview.h @@ -44,6 +44,8 @@ public: void scheduleAllFixits(bool schedule); signals: + void showHelp(); + void showFilter(); void clearFilter(); void filterForCurrentKind(); @@ -64,12 +66,18 @@ private: QModelIndex getTopLevelIndex(const QModelIndex &index, Direction direction) const; private: + QAction *m_help = nullptr; + QAction *m_showFilter = nullptr; QAction *m_clearFilter = nullptr; QAction *m_filterForCurrentKind = nullptr; QAction *m_filterOutCurrentKind = nullptr; - QAction *m_separator = nullptr; + QAction *m_suppressAction = nullptr; + + QAction *m_separator = nullptr; + QAction *m_separator2 = nullptr; + DiagnosticViewStyle *m_style = nullptr; DiagnosticViewDelegate *m_delegate = nullptr; bool m_ignoreSetSelectedFixItsCount = false; diff --git a/src/plugins/clangtools/clangtoolsutils.cpp b/src/plugins/clangtools/clangtoolsutils.cpp index 333a573161b..7fbcc358893 100644 --- a/src/plugins/clangtools/clangtoolsutils.cpp +++ b/src/plugins/clangtools/clangtoolsutils.cpp @@ -31,6 +31,7 @@ #include "clangtoolssettings.h" #include +#include #include #include @@ -193,5 +194,27 @@ ClangDiagnosticConfigsModel diagnosticConfigsModel() return Internal::diagnosticConfigsModel(ClangToolsSettings::instance()->diagnosticConfigs()); } +QString documentationUrl(const QString &checkName) +{ + QString name = checkName; + const QString clangPrefix = "clang-diagnostic-"; + if (name.startsWith(clangPrefix)) + return {}; // No documentation for this. + + QString url; + const QString clazyPrefix = "clazy-"; + const QString clangStaticAnalyzerPrefix = "clang-analyzer-core."; + if (name.startsWith(clazyPrefix)) { + name = checkName.mid(clazyPrefix.length()); + url = QString(CppTools::Constants::CLAZY_DOCUMENTATION_URL_TEMPLATE).arg(name); + } else if (name.startsWith(clangStaticAnalyzerPrefix)) { + url = CppTools::Constants::CLANG_STATIC_ANALYZER_DOCUMENTATION_URL; + } else { + url = QString(CppTools::Constants::TIDY_DOCUMENTATION_URL_TEMPLATE).arg(name); + } + + return url; +} + } // namespace Internal } // namespace ClangTools diff --git a/src/plugins/clangtools/clangtoolsutils.h b/src/plugins/clangtools/clangtoolsutils.h index a9b71da3b41..751304ebc80 100644 --- a/src/plugins/clangtools/clangtoolsutils.h +++ b/src/plugins/clangtools/clangtoolsutils.h @@ -57,6 +57,8 @@ QString clangTidyFallbackExecutable(); QString fullPath(const QString &executable); +QString documentationUrl(const QString &checkName); + CppTools::ClangDiagnosticConfigsModel diagnosticConfigsModel(); CppTools::ClangDiagnosticConfigsModel diagnosticConfigsModel( const CppTools::ClangDiagnosticConfigs &customConfigs); diff --git a/src/plugins/clangtools/diagnosticconfigswidget.cpp b/src/plugins/clangtools/diagnosticconfigswidget.cpp index 986d7f9ac41..d58c4f38b81 100644 --- a/src/plugins/clangtools/diagnosticconfigswidget.cpp +++ b/src/plugins/clangtools/diagnosticconfigswidget.cpp @@ -46,9 +46,6 @@ using namespace CppTools; namespace ClangTools { namespace Internal { -static constexpr const char CLANG_STATIC_ANALYZER_URL[] - = "https://clang-analyzer.llvm.org/available_checks.html"; - namespace ClangTidyPrefixTree { class Node @@ -346,7 +343,7 @@ private: if (role == LinkRole || role == Qt::ToolTipRole) { // 'clang-analyzer-' group if (node->isDir) - return QString::fromUtf8(CLANG_STATIC_ANALYZER_URL); + return CppTools::Constants::CLANG_STATIC_ANALYZER_DOCUMENTATION_URL; return QString::fromUtf8(CppTools::Constants::TIDY_DOCUMENTATION_URL_TEMPLATE) .arg(node->fullPath.toString()); } diff --git a/src/plugins/cpptools/cpptoolsconstants.h b/src/plugins/cpptools/cpptoolsconstants.h index e4329ff84b4..1924df134ad 100644 --- a/src/plugins/cpptools/cpptoolsconstants.h +++ b/src/plugins/cpptools/cpptoolsconstants.h @@ -102,6 +102,13 @@ const char SYMBOLS_FIND_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("CppTools", "C constexpr const char TIDY_DOCUMENTATION_URL_TEMPLATE[] = "https://releases.llvm.org/8.0.1/tools/clang/tools/extra/docs/clang-tidy/checks/%1.html"; +constexpr const char CLANG_STATIC_ANALYZER_DOCUMENTATION_URL[] + = "https://clang-analyzer.llvm.org/available_checks.html"; + +// CLANG-UPGRADE-CHECK: Checks/update URLs. +// +// Once it gets dedicated documentation pages for released versions, +// use them instead of pointing to master, as checks might vanish. constexpr const char CLAZY_DOCUMENTATION_URL_TEMPLATE[] = "https://github.com/KDE/clazy/blob/master/docs/checks/README-%1.md";