From 93685b97efe97616802f7483ebe1e37c8e8a653f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20P=C3=B6nitz?= Date: Wed, 18 Feb 2015 16:05:46 +0100 Subject: Compile fix after recent Analyzer core changes Change-Id: I100e75c526ff8609849526c3317a6d0a1658176b Reviewed-by: Christian Stenger Reviewed-by: Nikolai Kosjar --- .../clangstaticanalyzer/clangstaticanalyzerplugin.cpp | 17 ++++++++++++++--- plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp | 9 ++++----- plugins/clangstaticanalyzer/clangstaticanalyzertool.h | 12 +++++++----- .../clangstaticanalyzerunittests.cpp | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp index 1c09b0039e..55adb34d6d 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp @@ -125,16 +125,27 @@ bool ClangStaticAnalyzerPlugin::initializeEnterpriseFeatures(const QStringList & Q_UNUSED(arguments); Q_UNUSED(errorString); - m_analyzerTool = new ClangStaticAnalyzerTool(this); + auto tool = m_analyzerTool = new ClangStaticAnalyzerTool(this); addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory(m_analyzerTool)); addAutoReleasedObject(new ClangStaticAnalyzerOptionsPage); + auto toolStarter = [tool](StartMode mode) { return tool->startTool(mode); }; + auto widgetCreator = [tool] { return tool->createWidgets(); }; + auto runControlCreator = [tool](const AnalyzerStartParameters &sp, + ProjectExplorer::RunConfiguration *runConfiguration) { + return tool->createRunControl(sp, runConfiguration); + }; + const QString toolTip = tr("Clang Static Analyzer uses the analyzer from the clang project " "to find bugs."); AnalyzerAction *action = new AnalyzerAction(this); - action->setId("ClangStaticAnalyzer"); - action->setTool(m_analyzerTool); + action->setRunMode(ProjectExplorer::ClangStaticAnalyzerMode); + action->setToolId(ClangStaticAnalyzerToolId); + action->setActionId("ClangStaticAnalyzer"); + action->setWidgetCreator(widgetCreator); + action->setRunControlCreator(runControlCreator); + action->setToolStarter(toolStarter); action->setText(tr("Clang Static Analyzer")); action->setToolTip(toolTip); action->setMenuGroup(Constants::G_ANALYZER_TOOLS); diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp index 4fbc2aa5b5..c0e10fed3e 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp @@ -49,7 +49,7 @@ namespace ClangStaticAnalyzer { namespace Internal { ClangStaticAnalyzerTool::ClangStaticAnalyzerTool(QObject *parent) - : IAnalyzerTool(parent) + : QObject(parent) , m_diagnosticModel(0) , m_diagnosticView(0) , m_goBack(0) @@ -57,8 +57,6 @@ ClangStaticAnalyzerTool::ClangStaticAnalyzerTool(QObject *parent) , m_running(false) { setObjectName(QLatin1String("ClangStaticAnalyzerTool")); - setRunMode(ProjectExplorer::ClangStaticAnalyzerMode); - setToolMode(AnyMode); } QWidget *ClangStaticAnalyzerTool::createWidgets() @@ -85,7 +83,8 @@ QWidget *ClangStaticAnalyzerTool::createWidgets() m_diagnosticView->setObjectName(QLatin1String("ClangStaticAnalyzerIssuesView")); m_diagnosticView->setWindowTitle(tr("Clang Static Analyzer Issues")); - QDockWidget *issuesDock = AnalyzerManager::createDockWidget(this, m_diagnosticView); + QDockWidget *issuesDock = AnalyzerManager::createDockWidget(ClangStaticAnalyzerToolId, + m_diagnosticView); issuesDock->show(); Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow(); mw->splitDockWidget(mw->toolBarDockWidget(), issuesDock, Qt::Vertical); @@ -208,7 +207,7 @@ void ClangStaticAnalyzerTool::startTool(StartMode mode) m_projectInfoBeforeBuild = CppTools::CppModelManager::instance()->projectInfo(project); QTC_ASSERT(m_projectInfoBeforeBuild.isValid(), return); m_running = true; - ProjectExplorerPlugin::instance()->runProject(project, runMode()); + ProjectExplorerPlugin::runProject(project, ProjectExplorer::ClangStaticAnalyzerMode); } CppTools::ProjectInfo ClangStaticAnalyzerTool::projectInfoBeforeBuild() const diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.h b/plugins/clangstaticanalyzer/clangstaticanalyzertool.h index 24c39e3b39..ba4f57020d 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.h +++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.h @@ -31,7 +31,9 @@ class ClangStaticAnalyzerDiagnosticModel; class ClangStaticAnalyzerDiagnosticView; class Diagnostic; -class ClangStaticAnalyzerTool : public Analyzer::IAnalyzerTool +const char ClangStaticAnalyzerToolId[] = "ClangStaticAnalyzer"; + +class ClangStaticAnalyzerTool : public QObject { Q_OBJECT @@ -44,15 +46,15 @@ public: bool isRunning() const { return m_running; } QList diagnostics() const; -signals: - void finished(); // For testing. - -private: QWidget *createWidgets(); Analyzer::AnalyzerRunControl *createRunControl(const Analyzer::AnalyzerStartParameters &sp, ProjectExplorer::RunConfiguration *runConfiguration); void startTool(Analyzer::StartMode mode); +signals: + void finished(); // For testing. + +private: void onEngineIsStarting(); void onNewDiagnosticsAvailable(const QList &diagnostics); void onEngineFinished(); diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp index 82c5ac1b29..318ff95637 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp @@ -81,7 +81,7 @@ void ClangStaticAnalyzerUnitTests::testProject() CppTools::Tests::ProjectOpenerAndCloser projectManager; const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true); QVERIFY(projectInfo.isValid()); - AnalyzerManager::selectTool(m_analyzerTool, Analyzer::StartLocal); + AnalyzerManager::selectTool(ClangStaticAnalyzerToolId, Analyzer::StartLocal); AnalyzerManager::startTool(); if (m_analyzerTool->isRunning()) { QSignalSpy waiter(m_analyzerTool, SIGNAL(finished())); -- cgit v1.2.3 From 4495ab283c8713d4f6fcfd36e8296f4c3867f1cb Mon Sep 17 00:00:00 2001 From: Daniel Teske Date: Thu, 19 Feb 2015 14:48:39 +0100 Subject: Fix compile after Analyzer changes Change-Id: I3870488ff2052465508c23d429dcb2d25a249857 Reviewed-by: Andre Poenitz --- plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp index 318ff95637..d73cf78e42 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp @@ -81,7 +81,7 @@ void ClangStaticAnalyzerUnitTests::testProject() CppTools::Tests::ProjectOpenerAndCloser projectManager; const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true); QVERIFY(projectInfo.isValid()); - AnalyzerManager::selectTool(ClangStaticAnalyzerToolId, Analyzer::StartLocal); + AnalyzerManager::selectTool(ClangStaticAnalyzerToolId); AnalyzerManager::startTool(); if (m_analyzerTool->isRunning()) { QSignalSpy waiter(m_analyzerTool, SIGNAL(finished())); -- cgit v1.2.3 From 6ac1dc95fd092c6be409d9fb6874b53558a43a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20P=C3=B6nitz?= Date: Fri, 20 Feb 2015 10:05:44 +0100 Subject: Adjust to Analyzer core changes Change-Id: I2985b1be505f9aa43f2a8615a8dfcafaeb991e21 Reviewed-by: Christian Stenger --- plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp | 3 +-- plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp | 4 +--- plugins/clangstaticanalyzer/clangstaticanalyzertool.h | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp index 55adb34d6d..52673def09 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp @@ -129,7 +129,6 @@ bool ClangStaticAnalyzerPlugin::initializeEnterpriseFeatures(const QStringList & addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory(m_analyzerTool)); addAutoReleasedObject(new ClangStaticAnalyzerOptionsPage); - auto toolStarter = [tool](StartMode mode) { return tool->startTool(mode); }; auto widgetCreator = [tool] { return tool->createWidgets(); }; auto runControlCreator = [tool](const AnalyzerStartParameters &sp, ProjectExplorer::RunConfiguration *runConfiguration) { @@ -145,7 +144,7 @@ bool ClangStaticAnalyzerPlugin::initializeEnterpriseFeatures(const QStringList & action->setActionId("ClangStaticAnalyzer"); action->setWidgetCreator(widgetCreator); action->setRunControlCreator(runControlCreator); - action->setToolStarter(toolStarter); + action->setToolStarter([tool] { tool->startTool(); }); action->setText(tr("Clang Static Analyzer")); action->setToolTip(toolTip); action->setMenuGroup(Constants::G_ANALYZER_TOOLS); diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp index c0e10fed3e..23d9b96cc4 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp @@ -191,10 +191,8 @@ static bool dontStartAfterHintForDebugMode() return false; } -void ClangStaticAnalyzerTool::startTool(StartMode mode) +void ClangStaticAnalyzerTool::startTool() { - QTC_ASSERT(mode == Analyzer::StartLocal, return); - AnalyzerManager::showMode(); if (dontStartAfterHintForDebugMode()) diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.h b/plugins/clangstaticanalyzer/clangstaticanalyzertool.h index ba4f57020d..fa402a608e 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.h +++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.h @@ -49,7 +49,7 @@ public: QWidget *createWidgets(); Analyzer::AnalyzerRunControl *createRunControl(const Analyzer::AnalyzerStartParameters &sp, ProjectExplorer::RunConfiguration *runConfiguration); - void startTool(Analyzer::StartMode mode); + void startTool(); signals: void finished(); // For testing. -- cgit v1.2.3 From 7c9c7b297a896d0b1ef82b2b23e0ed789539fdfc Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 26 Feb 2015 14:04:59 +0100 Subject: Don't fade out analyzer summary. There is no reason why the status of the analyzer run should disappear after a few seconds. Change-Id: I16c21f05a03ac31f489312fbe56373a531ecc5d5 Reviewed-by: Nikolai Kosjar --- plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp index 23d9b96cc4..6f9fb44955 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp @@ -247,7 +247,7 @@ void ClangStaticAnalyzerTool::onEngineFinished() m_goBack->setEnabled(issuesFound > 1); m_goNext->setEnabled(issuesFound > 1); - AnalyzerManager::showStatusMessage(issuesFound > 0 + AnalyzerManager::showPermanentStatusMessage(issuesFound > 0 ? AnalyzerManager::tr("Clang Static Analyzer finished, %n issues were found.", 0, issuesFound) : AnalyzerManager::tr("Clang Static Analyzer finished, no issues were found.")); m_running = false; -- cgit v1.2.3 From bba6f927e90f32e7051d5f8e0e1dfa5ae4413ff2 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 26 Feb 2015 15:14:29 +0100 Subject: Don't attempt to analyze using icecc masquerading as clang. Also warn the user in the settings page against this. Change-Id: I4dbae953aa85f8dbdc9baa8dd0fda8ff0da45b76 Reviewed-by: Nikolai Kosjar --- .../clangstaticanalyzer/clangstaticanalyzer.pro | 2 ++ .../clangstaticanalyzer/clangstaticanalyzer.qbs | 2 ++ .../clangstaticanalyzerconfigwidget.cpp | 4 --- .../clangstaticanalyzerconfigwidget.ui | 6 ++-- .../clangstaticanalyzerpathchooser.cpp | 40 ++++++++++++++++++++++ .../clangstaticanalyzerpathchooser.h | 40 ++++++++++++++++++++++ .../clangstaticanalyzerutils.cpp | 18 +++++++++- .../clangstaticanalyzer/clangstaticanalyzerutils.h | 4 +-- 8 files changed, 106 insertions(+), 10 deletions(-) create mode 100644 plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.cpp create mode 100644 plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.h diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzer.pro b/plugins/clangstaticanalyzer/clangstaticanalyzer.pro index df939e9f36..38ddda3e64 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzer.pro +++ b/plugins/clangstaticanalyzer/clangstaticanalyzer.pro @@ -10,6 +10,7 @@ SOURCES += \ clangstaticanalyzerdiagnosticmodel.cpp \ clangstaticanalyzerdiagnosticview.cpp \ clangstaticanalyzerlogfilereader.cpp \ + clangstaticanalyzerpathchooser.cpp \ clangstaticanalyzerplugin.cpp \ clangstaticanalyzerruncontrol.cpp \ clangstaticanalyzerruncontrolfactory.cpp \ @@ -26,6 +27,7 @@ HEADERS += \ clangstaticanalyzerdiagnosticview.h \ clangstaticanalyzer_global.h \ clangstaticanalyzerlogfilereader.h \ + clangstaticanalyzerpathchooser.h \ clangstaticanalyzerplugin.h \ clangstaticanalyzerruncontrolfactory.h \ clangstaticanalyzerruncontrol.h \ diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs b/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs index 78c7decc5d..9113cc94c3 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs +++ b/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs @@ -28,6 +28,8 @@ QtcPlugin { "clangstaticanalyzerdiagnosticview.h", "clangstaticanalyzerlogfilereader.cpp", "clangstaticanalyzerlogfilereader.h", + "clangstaticanalyzerpathchooser.cpp", + "clangstaticanalyzerpathchooser.h", "clangstaticanalyzerplugin.cpp", "clangstaticanalyzerplugin.h", "clangstaticanalyzerruncontrol.cpp", diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp index d6ff0fa5b8..6b8b0f0cee 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp @@ -33,10 +33,6 @@ ClangStaticAnalyzerConfigWidget::ClangStaticAnalyzerConfigWidget( { m_ui->setupUi(this); - m_ui->clangExecutableChooser->setExpectedKind(Utils::PathChooser::ExistingCommand); - m_ui->clangExecutableChooser->setHistoryCompleter( - QLatin1String("ClangStaticAnalyzer.ClangCommand.History")); - m_ui->clangExecutableChooser->setPromptDialogTitle(tr("Clang Command")); m_ui->clangExecutableChooser->setPath(settings->clangExecutable()); connect(m_ui->clangExecutableChooser, &Utils::PathChooser::changed, m_settings, &ClangStaticAnalyzerSettings::setClangExecutable); diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui b/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui index 800733a331..8997f3a7d1 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui @@ -30,7 +30,7 @@ - + @@ -88,9 +88,9 @@ - Utils::PathChooser + ClangStaticAnalyzer::Internal::PathChooser QWidget -
utils/pathchooser.h
+
clangstaticanalyzer/clangstaticanalyzerpathchooser.h
1
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.cpp new file mode 100644 index 0000000000..b5711bfeab --- /dev/null +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.cpp @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise LicenseChecker Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ +#include "clangstaticanalyzerpathchooser.h" + +#include "clangstaticanalyzerutils.h" + +namespace ClangStaticAnalyzer { +namespace Internal { + +PathChooser::PathChooser(QWidget *parent) : Utils::PathChooser(parent) +{ + setExpectedKind(Utils::PathChooser::ExistingCommand); + setHistoryCompleter(QLatin1String("ClangStaticAnalyzer.ClangCommand.History")); + setPromptDialogTitle(tr("Clang Command")); +} + +bool PathChooser::validatePath(const QString &path, QString *errorMessage) +{ + if (!Utils::PathChooser::validatePath(path, errorMessage)) + return false; + return isClangExecutableUsable(fileName().toString(), errorMessage); +} + +} // namespace Internal +} // namespace ClangStaticAnalyzer diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.h b/plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.h new file mode 100644 index 0000000000..b4bc3c5947 --- /dev/null +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.h @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise LicenseChecker Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ +#ifndef QTC_CLANGSTATICANALYZER_PATHCHOOSER_H +#define QTC_CLANGSTATICANALYZER_PATHCHOOSER_H + +#include + +namespace ClangStaticAnalyzer { +namespace Internal { + +class PathChooser : public Utils::PathChooser +{ + Q_OBJECT + +public: + PathChooser(QWidget *parent = 0); + +private: + bool validatePath(const QString &path, QString *errorMessage = 0); +}; + +} // namespace Internal +} // namespace ClangStaticAnalyzer + +#endif // Include guard. diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp index 06401eb287..3860f929a6 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp @@ -23,6 +23,7 @@ #include +#include #include static bool isFileExecutable(const QString &executablePath) @@ -63,7 +64,7 @@ QString clangExecutable(const QString &fileNameOrPath, bool *isValid) executable = executableFromPath; } - *isValid = isFileExecutable(executable); + *isValid = isFileExecutable(executable) && isClangExecutableUsable(executable); return executable; } @@ -74,5 +75,20 @@ QString createFullLocationString(const ClangStaticAnalyzer::Internal::Location & return filePath + QLatin1Char(':') + lineNumber; } +bool isClangExecutableUsable(const QString &filePath, QString *errorMessage) +{ + const QFileInfo fi(filePath); + if (fi.isSymLink() && fi.symLinkTarget().contains(QLatin1String("icecc"))) { + if (errorMessage) { + *errorMessage = QCoreApplication::translate("ClangStaticAnalyzer", + "The chosen file \"%1\" seems to point to an icecc binary not suitable " + "for analyzing.\nPlease set a real clang executable.") + .arg(filePath); + } + return false; + } + return true; +} + } // namespace Internal } // namespace ClangStaticAnalyzer diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h b/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h index e85d25f286..ca06c4874e 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h @@ -25,13 +25,13 @@ QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE - - namespace ClangStaticAnalyzer { namespace Internal { class Location; +bool isClangExecutableUsable(const QString &filePath, QString *errorMessage = 0); + QString clangExecutable(const QString &fileNameOrPath, bool *isValid); QString clangExecutableFromSettings(const QString &toolchainType, bool *isValid); -- cgit v1.2.3 From a13818f5cd3e8e60954dc75483834965926553fc Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 26 Feb 2015 16:33:10 +0100 Subject: Clear status message on start Change-Id: I82e94f0426796473b35dd2a534a4fd7c5aab2667 Reviewed-by: Christian Kandeler --- plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp index 6f9fb44955..260aae865a 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp @@ -198,6 +198,7 @@ void ClangStaticAnalyzerTool::startTool() if (dontStartAfterHintForDebugMode()) return; + AnalyzerManager::showPermanentStatusMessage(QString()); m_diagnosticModel->clear(); setBusyCursor(true); Project *project = SessionManager::startupProject(); -- cgit v1.2.3 From 6e796591f445aa0f193b280b9c89fcf82fa2236d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 19 Feb 2015 18:08:38 +0100 Subject: Allow users to suppress diagnostics. This patch deals with what is likely the most common use case: Filtering specific messages at a particular location. The current granularity is essentially per-file (and per-function, where possible), which seems more useful than taking line numbers into account, as that would not be robust with regards to code changes elsewhere in the file. We can fine-tune this if the need arises. Change-Id: I4e9b2671fa199339cc3b995953d072b840cd3205 Reviewed-by: Nikolai Kosjar --- .../clangstaticanalyzer/clangstaticanalyzer.pro | 9 +- .../clangstaticanalyzer/clangstaticanalyzer.qbs | 7 + .../clangstaticanalyzerdiagnosticmodel.cpp | 71 +++++++++ .../clangstaticanalyzerdiagnosticmodel.h | 27 ++++ .../clangstaticanalyzerdiagnosticview.cpp | 47 +++++- .../clangstaticanalyzerdiagnosticview.h | 9 ++ .../clangstaticanalyzerplugin.cpp | 8 ++ .../clangstaticanalyzerprojectsettings.cpp | 137 ++++++++++++++++++ .../clangstaticanalyzerprojectsettings.h | 87 +++++++++++ .../clangstaticanalyzerprojectsettingsmanager.cpp | 50 +++++++ .../clangstaticanalyzerprojectsettingsmanager.h | 47 ++++++ .../clangstaticanalyzerprojectsettingswidget.cpp | 160 +++++++++++++++++++++ .../clangstaticanalyzerprojectsettingswidget.h | 52 +++++++ .../clangstaticanalyzerprojectsettingswidget.ui | 87 +++++++++++ .../clangstaticanalyzertool.cpp | 18 ++- .../clangstaticanalyzer/clangstaticanalyzertool.h | 2 + 16 files changed, 808 insertions(+), 10 deletions(-) create mode 100644 plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.cpp create mode 100644 plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.h create mode 100644 plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.cpp create mode 100644 plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.h create mode 100644 plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.cpp create mode 100644 plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.h create mode 100644 plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.ui diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzer.pro b/plugins/clangstaticanalyzer/clangstaticanalyzer.pro index 38ddda3e64..67eb90ad41 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzer.pro +++ b/plugins/clangstaticanalyzer/clangstaticanalyzer.pro @@ -12,6 +12,9 @@ SOURCES += \ clangstaticanalyzerlogfilereader.cpp \ clangstaticanalyzerpathchooser.cpp \ clangstaticanalyzerplugin.cpp \ + clangstaticanalyzerprojectsettings.cpp \ + clangstaticanalyzerprojectsettingsmanager.cpp \ + clangstaticanalyzerprojectsettingswidget.cpp \ clangstaticanalyzerruncontrol.cpp \ clangstaticanalyzerruncontrolfactory.cpp \ clangstaticanalyzerrunner.cpp \ @@ -29,6 +32,9 @@ HEADERS += \ clangstaticanalyzerlogfilereader.h \ clangstaticanalyzerpathchooser.h \ clangstaticanalyzerplugin.h \ + clangstaticanalyzerprojectsettings.h \ + clangstaticanalyzerprojectsettingsmanager.h \ + clangstaticanalyzerprojectsettingswidget.h \ clangstaticanalyzerruncontrolfactory.h \ clangstaticanalyzerruncontrol.h \ clangstaticanalyzerrunner.h \ @@ -37,7 +43,8 @@ HEADERS += \ clangstaticanalyzerutils.h FORMS += \ - clangstaticanalyzerconfigwidget.ui + clangstaticanalyzerconfigwidget.ui \ + clangstaticanalyzerprojectsettingswidget.ui equals(TEST, 1) { HEADERS += clangstaticanalyzerunittests.h diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs b/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs index 9113cc94c3..a97dc9f83c 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs +++ b/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs @@ -32,6 +32,13 @@ QtcPlugin { "clangstaticanalyzerpathchooser.h", "clangstaticanalyzerplugin.cpp", "clangstaticanalyzerplugin.h", + "clangstaticanalyzerprojectsettings.cpp", + "clangstaticanalyzerprojectsettings.h", + "clangstaticanalyzerprojectsettingsmanager.cpp", + "clangstaticanalyzerprojectsettingsmanager.h", + "clangstaticanalyzerprojectsettingswidget.cpp", + "clangstaticanalyzerprojectsettingswidget.h", + "clangstaticanalyzerprojectsettingswidget.ui", "clangstaticanalyzerruncontrol.cpp", "clangstaticanalyzerruncontrol.h", "clangstaticanalyzerruncontrolfactory.cpp", diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp index 5f1d21fb9f..40f5924442 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp @@ -18,9 +18,15 @@ #include "clangstaticanalyzerdiagnosticmodel.h" +#include "clangstaticanalyzerprojectsettingsmanager.h" #include "clangstaticanalyzerutils.h" +#include +#include +#include + #include +#include namespace ClangStaticAnalyzer { namespace Internal { @@ -118,5 +124,70 @@ QVariant ClangStaticAnalyzerDiagnosticModel::data(const QModelIndex &index, int return QVariant(); } + +ClangStaticAnalyzerDiagnosticFilterModel::ClangStaticAnalyzerDiagnosticFilterModel(QObject *parent) + : QSortFilterProxyModel(parent) +{ + // So that when a user closes and re-opens a project and *then* clicks "Suppress", + // we enter that information into the project settings. + connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::projectAdded, this, + [this](ProjectExplorer::Project *project) { + if (!m_project && project->projectDirectory() == m_lastProjectDirectory) + setProject(project); + }); +} + +void ClangStaticAnalyzerDiagnosticFilterModel::setProject(ProjectExplorer::Project *project) +{ + QTC_ASSERT(project, return); + if (m_project) { + disconnect(ProjectSettingsManager::getSettings(m_project), + &ProjectSettings::suppressedDiagnosticsChanged, this, + &ClangStaticAnalyzerDiagnosticFilterModel::handleSuppressedDiagnosticsChanged); + } + m_project = project; + m_lastProjectDirectory = m_project->projectDirectory(); + connect(ProjectSettingsManager::getSettings(m_project), + &ProjectSettings::suppressedDiagnosticsChanged, + this, &ClangStaticAnalyzerDiagnosticFilterModel::handleSuppressedDiagnosticsChanged); + handleSuppressedDiagnosticsChanged(); +} + +void ClangStaticAnalyzerDiagnosticFilterModel::addSuppressedDiagnostic( + const SuppressedDiagnostic &diag) +{ + QTC_ASSERT(!m_project, return); + m_suppressedDiagnostics << diag; + invalidate(); +} + +bool ClangStaticAnalyzerDiagnosticFilterModel::filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const +{ + Q_UNUSED(sourceParent); + const Diagnostic diag = static_cast(sourceModel()) + ->diagnostics().at(sourceRow); + foreach (const SuppressedDiagnostic &d, m_suppressedDiagnostics) { + if (d.description != diag.description) + continue; + QString filePath = d.filePath.toString(); + QFileInfo fi(filePath); + if (fi.isRelative()) + filePath = m_lastProjectDirectory.toString() + QLatin1Char('/') + filePath; + if (filePath == diag.location.filePath) + return false; + } + return true; +} + +void ClangStaticAnalyzerDiagnosticFilterModel::handleSuppressedDiagnosticsChanged() +{ + QTC_ASSERT(m_project, return); + m_suppressedDiagnostics + = ProjectSettingsManager::getSettings(m_project)->suppressedDiagnostics(); + invalidate(); +} + } // namespace Internal } // namespace ClangStaticAnalyzer diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h index 68dcf7ed05..a2dc49c26c 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h @@ -20,8 +20,15 @@ #define CLANGSTATICANALYZERDIAGNOSTICMODEL_H #include "clangstaticanalyzerlogfilereader.h" +#include "clangstaticanalyzerprojectsettings.h" + +#include #include +#include +#include + +namespace ProjectExplorer { class Project; } namespace ClangStaticAnalyzer { namespace Internal { @@ -45,6 +52,26 @@ private: QList m_diagnostics; }; +class ClangStaticAnalyzerDiagnosticFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + ClangStaticAnalyzerDiagnosticFilterModel(QObject *parent = 0); + + void setProject(ProjectExplorer::Project *project); + void addSuppressedDiagnostic(const SuppressedDiagnostic &diag); + ProjectExplorer::Project *project() const { return m_project; } + +private: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + void handleSuppressedDiagnosticsChanged(); + + QPointer m_project; + Utils::FileName m_lastProjectDirectory; + SuppressedDiagnosticsList m_suppressedDiagnostics; +}; + } // namespace Internal } // namespace ClangStaticAnalyzer diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp index 54c8ef5a53..f1805f2da2 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp @@ -19,10 +19,15 @@ #include "clangstaticanalyzerdiagnosticview.h" #include "clangstaticanalyzerlogfilereader.h" +#include "clangstaticanalyzerdiagnosticmodel.h" +#include "clangstaticanalyzerprojectsettings.h" +#include "clangstaticanalyzerprojectsettingsmanager.h" #include "clangstaticanalyzerutils.h" +#include #include +#include #include #include #include @@ -196,13 +201,18 @@ DetailedErrorDelegate::SummaryLineInfo ClangStaticAnalyzerDiagnosticDelegate::su return info; } +Diagnostic ClangStaticAnalyzerDiagnosticDelegate::getDiagnostic(const QModelIndex &index) const +{ + return index.data(Qt::UserRole).value(); +} + QWidget *ClangStaticAnalyzerDiagnosticDelegate::createDetailsWidget(const QFont &font, const QModelIndex &index, QWidget *parent) const { QWidget *widget = new QWidget(parent); - const Diagnostic diagnostic = index.data(Qt::UserRole).value(); + const Diagnostic diagnostic = getDiagnostic(index); if (!diagnostic.isValid()) return widget; @@ -240,7 +250,7 @@ QString ClangStaticAnalyzerDiagnosticDelegate::textualRepresentation() const { QTC_ASSERT(m_detailsIndex.isValid(), return QString()); - const Diagnostic diagnostic = m_detailsIndex.data(Qt::UserRole).value(); + const Diagnostic diagnostic = getDiagnostic(m_detailsIndex); QTC_ASSERT(diagnostic.isValid(), return QString()); // Create summary @@ -268,6 +278,39 @@ ClangStaticAnalyzerDiagnosticView::ClangStaticAnalyzerDiagnosticView(QWidget *pa ClangStaticAnalyzerDiagnosticDelegate *delegate = new ClangStaticAnalyzerDiagnosticDelegate(this); setItemDelegate(delegate); + m_suppressAction = new QAction(tr("Suppress this diagnostic"), this); + connect(m_suppressAction, &QAction::triggered, [this](bool) { suppressCurrentDiagnostic(); }); +} + +void ClangStaticAnalyzerDiagnosticView::suppressCurrentDiagnostic() +{ + const QModelIndexList indexes = selectedIndexes(); + QTC_ASSERT(indexes.count() == 1, return); + const Diagnostic diag = static_cast(itemDelegate()) + ->getDiagnostic(indexes.first()); + QTC_ASSERT(diag.isValid(), return); + + // If the original project was closed, we work directly on the filter model, otherwise + // we go via the project settings. + auto * const filterModel = static_cast(model()); + ProjectExplorer::Project * const project = filterModel->project(); + if (project) { + Utils::FileName filePath = Utils::FileName::fromString(diag.location.filePath); + const Utils::FileName relativeFilePath + = filePath.relativeChildPath(project->projectDirectory()); + if (!relativeFilePath.isEmpty()) + filePath = relativeFilePath; + const SuppressedDiagnostic supDiag(filePath, diag.description, diag.issueContextKind, + diag.issueContext, diag.explainingSteps.count()); + ProjectSettingsManager::getSettings(project)->addSuppressedDiagnostic(supDiag); + } else { + filterModel->addSuppressedDiagnostic(SuppressedDiagnostic(diag)); + } +} + +QList ClangStaticAnalyzerDiagnosticView::customActions() const +{ + return QList() << m_suppressAction; } } // namespace Internal diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h index ed6acae4f3..4fbdc7f866 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h @@ -23,6 +23,7 @@ namespace ClangStaticAnalyzer { namespace Internal { +class Diagnostic; class ClangStaticAnalyzerDiagnosticView : public Analyzer::DetailedErrorView { @@ -30,6 +31,13 @@ class ClangStaticAnalyzerDiagnosticView : public Analyzer::DetailedErrorView public: ClangStaticAnalyzerDiagnosticView(QWidget *parent = 0); + +private: + void suppressCurrentDiagnostic(); + + QList customActions() const; + + QAction *m_suppressAction; }; class ClangStaticAnalyzerDiagnosticDelegate : public Analyzer::DetailedErrorDelegate @@ -38,6 +46,7 @@ public: ClangStaticAnalyzerDiagnosticDelegate(QListView *parent); SummaryLineInfo summaryInfo(const QModelIndex &index) const; + Diagnostic getDiagnostic(const QModelIndex &index) const; private: QWidget *createDetailsWidget(const QFont &font, const QModelIndex &index, diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp index 52673def09..dced8b03d6 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp @@ -19,6 +19,7 @@ #include "clangstaticanalyzerplugin.h" #include "clangstaticanalyzerconfigwidget.h" +#include "clangstaticanalyzerprojectsettingswidget.h" #include "clangstaticanalyzerruncontrolfactory.h" #include "clangstaticanalyzertool.h" @@ -35,6 +36,7 @@ #include #include #include +#include #include @@ -106,6 +108,12 @@ bool ClangStaticAnalyzerPlugin::initialize(const QStringList &arguments, QString // In the initialize method, a plugin can be sure that the plugins it // depends on have initialized their members. + auto panelFactory = new ProjectExplorer::ProjectPanelFactory(); + panelFactory->setPriority(100); + panelFactory->setDisplayName(tr("Clang Static Analyzer Settings")); + panelFactory->setSimpleCreateWidgetFunction(QIcon()); + ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); + LicenseChecker::LicenseCheckerPlugin *licenseChecker = ExtensionSystem::PluginManager::getObject(); diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.cpp new file mode 100644 index 0000000000..7ee14816be --- /dev/null +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Qt Quick Profiler Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ +#include "clangstaticanalyzerprojectsettings.h" + +#include "clangstaticanalyzerdiagnostic.h" + +#include + +namespace ClangStaticAnalyzer { +namespace Internal { + +static QString suppressedDiagnosticsKey() +{ + return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnostics"); +} + +static QString suppressedDiagnosticFilePathKey() +{ + return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticFilePath"); +} + +static QString suppressedDiagnosticMessageKey() +{ + return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticMessage"); +} + +static QString suppressedDiagnosticContextKindKey() +{ + return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticContextKind"); +} + +static QString suppressedDiagnosticContextKey() +{ + return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticContext"); +} + +static QString suppressedDiagnosticUniquifierKey() +{ + return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticUniquifier"); +} + +ProjectSettings::ProjectSettings(ProjectExplorer::Project *project) : m_project(project) +{ + load(); + connect(project, &ProjectExplorer::Project::aboutToSaveSettings, this, + &ProjectSettings::store); +} + +void ProjectSettings::addSuppressedDiagnostic(const SuppressedDiagnostic &diag) +{ + QTC_ASSERT(!m_suppressedDiagnostics.contains(diag), return); + m_suppressedDiagnostics << diag; + emit suppressedDiagnosticsChanged(); +} + +void ProjectSettings::removeSuppressedDiagnostic(const SuppressedDiagnostic &diag) +{ + const bool wasPresent = m_suppressedDiagnostics.removeOne(diag); + QTC_ASSERT(wasPresent, return); + emit suppressedDiagnosticsChanged(); +} + +void ProjectSettings::removeAllSuppressedDiagnostics() +{ + m_suppressedDiagnostics.clear(); + emit suppressedDiagnosticsChanged(); +} + +void ProjectSettings::load() +{ + const QVariantList list = m_project->namedSettings(suppressedDiagnosticsKey()).toList(); + foreach (const QVariant &v, list) { + const QVariantMap diag = v.toMap(); + const QString fp = diag.value(suppressedDiagnosticFilePathKey()).toString(); + if (fp.isEmpty()) + continue; + const QString message = diag.value(suppressedDiagnosticMessageKey()).toString(); + if (message.isEmpty()) + continue; + Utils::FileName fullPath = Utils::FileName::fromString(fp); + if (fullPath.toFileInfo().isRelative()) { + fullPath = m_project->projectDirectory(); + fullPath.appendPath(fp); + } + if (!fullPath.exists()) + continue; + const QString contextKind = diag.value(suppressedDiagnosticContextKindKey()).toString(); + const QString context = diag.value(suppressedDiagnosticContextKey()).toString(); + const int uniquifier = diag.value(suppressedDiagnosticUniquifierKey()).toInt(); + m_suppressedDiagnostics << SuppressedDiagnostic(Utils::FileName::fromString(fp), message, + contextKind, context, uniquifier); + } + emit suppressedDiagnosticsChanged(); +} + +void ProjectSettings::store() +{ + QVariantList list; + foreach (const SuppressedDiagnostic &diag, m_suppressedDiagnostics) { + QVariantMap diagMap; + diagMap.insert(suppressedDiagnosticFilePathKey(), diag.filePath.toString()); + diagMap.insert(suppressedDiagnosticMessageKey(), diag.description); + diagMap.insert(suppressedDiagnosticContextKindKey(), diag.contextKind); + diagMap.insert(suppressedDiagnosticContextKey(), diag.context); + diagMap.insert(suppressedDiagnosticUniquifierKey(), diag.uniquifier); + list << diagMap; + } + m_project->setNamedSettings(suppressedDiagnosticsKey(), list); +} + + +SuppressedDiagnostic::SuppressedDiagnostic(const Diagnostic &diag) + : filePath(Utils::FileName::fromString(diag.location.filePath)) + , description(diag.description) + , contextKind(diag.issueContextKind) + , context(diag.issueContext) + , uniquifier(diag.explainingSteps.count()) +{ +} + +} // namespace Internal +} // namespace ClangStaticAnalyzer diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.h b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.h new file mode 100644 index 0000000000..2a993de966 --- /dev/null +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Qt Quick Profiler Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ +#ifndef CLANGSTATICANALYZERPROJECTSETTINGS_H +#define CLANGSTATICANALYZERPROJECTSETTINGS_H + +#include +#include + +#include +#include + +namespace ClangStaticAnalyzer { +namespace Internal { +class Diagnostic; + +class SuppressedDiagnostic +{ +public: + SuppressedDiagnostic(const Utils::FileName &filePath, const QString &description, + const QString &contextKind, const QString &context, int uniquifier) + : filePath(filePath) + , description(description) + , contextKind(contextKind) + , context(context) + , uniquifier(uniquifier) + { + } + + SuppressedDiagnostic(const Diagnostic &diag); + + Utils::FileName filePath; // Relative for files in project, absolute otherwise. + QString description; + QString contextKind; + QString context; + int uniquifier; +}; + +inline bool operator==(const SuppressedDiagnostic &d1, const SuppressedDiagnostic &d2) +{ + return d1.filePath == d2.filePath && d1.description == d2.description + && d1.contextKind == d2.contextKind && d1.context == d2.context + && d1.uniquifier == d2.uniquifier; +} + +typedef QList SuppressedDiagnosticsList; + +class ProjectSettings : public QObject +{ + Q_OBJECT +public: + ProjectSettings(ProjectExplorer::Project *project); + + SuppressedDiagnosticsList suppressedDiagnostics() const { return m_suppressedDiagnostics; } + void addSuppressedDiagnostic(const SuppressedDiagnostic &diag); + void removeSuppressedDiagnostic(const SuppressedDiagnostic &diag); + void removeAllSuppressedDiagnostics(); + +signals: + void suppressedDiagnosticsChanged(); + +private: + void load(); + void store(); + + ProjectExplorer::Project * const m_project; + SuppressedDiagnosticsList m_suppressedDiagnostics; +}; + +} // namespace Internal +} // namespace ClangStaticAnalyzer + +#endif // Include guard. diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.cpp new file mode 100644 index 0000000000..8b1637bba1 --- /dev/null +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Qt Quick Profiler Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ +#include "clangstaticanalyzerprojectsettingsmanager.h" + +#include "clangstaticanalyzerprojectsettings.h" + +#include + +namespace ClangStaticAnalyzer { +namespace Internal { + +ProjectSettingsManager::ProjectSettingsManager() +{ + QObject::connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::aboutToRemoveProject, + &ProjectSettingsManager::handleProjectToBeRemoved); +} + +ProjectSettings *ProjectSettingsManager::getSettings(ProjectExplorer::Project *project) +{ + auto &settings = m_settings[project]; + if (!settings) + settings.reset(new ProjectSettings(project)); + return settings.data(); +} + +void ProjectSettingsManager::handleProjectToBeRemoved(ProjectExplorer::Project *project) +{ + m_settings.remove(project); +} + +ProjectSettingsManager::SettingsMap ProjectSettingsManager::m_settings; + +} // namespace Internal +} // namespace ClangStaticAnalyzer diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.h b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.h new file mode 100644 index 0000000000..97f8d79a99 --- /dev/null +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Qt Quick Profiler Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ +#ifndef CLANGSTATICANALYZERPROJECTSETTINGSMANAGER_H +#define CLANGSTATICANALYZERPROJECTSETTINGSMANAGER_H + +namespace ProjectExplorer { class Project; } + +#include +#include + +namespace ClangStaticAnalyzer { +namespace Internal { +class ProjectSettings; + +class ProjectSettingsManager +{ +public: + ProjectSettingsManager(); + + static ProjectSettings *getSettings(ProjectExplorer::Project *project); + +private: + static void handleProjectToBeRemoved(ProjectExplorer::Project *project); + + typedef QHash> SettingsMap; + static SettingsMap m_settings; +}; + +} // namespace Internal +} // namespace ClangStaticAnalyzer + +#endif // Include guard. diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.cpp new file mode 100644 index 0000000000..580e6f750d --- /dev/null +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Qt Quick Profiler Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ +#include "clangstaticanalyzerprojectsettingswidget.h" +#include "ui_clangstaticanalyzerprojectsettingswidget.h" + +#include "clangstaticanalyzerprojectsettings.h" +#include "clangstaticanalyzerprojectsettingsmanager.h" + +#include + +#include + +namespace ClangStaticAnalyzer { +namespace Internal { + +class SuppressedDiagnosticsModel : public QAbstractTableModel +{ + Q_OBJECT +public: + SuppressedDiagnosticsModel(QObject *parent = 0) : QAbstractTableModel(parent) { } + + void setDiagnostics(const SuppressedDiagnosticsList &diagnostics); + SuppressedDiagnostic diagnosticAt(int i) const; + +private: + enum Columns { ColumnFile, ColumnContext, ColumnDescription, ColumnLast = ColumnDescription }; + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex & = QModelIndex()) const { return ColumnLast + 1; } + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + SuppressedDiagnosticsList m_diagnostics; +}; + +ProjectSettingsWidget::ProjectSettingsWidget(ProjectExplorer::Project *project, QWidget *parent) : + QWidget(parent), + m_ui(new Ui::ProjectSettingsWidget) + , m_projectSettings(ProjectSettingsManager::getSettings(project)) +{ + m_ui->setupUi(this); + auto * const model = new SuppressedDiagnosticsModel(this); + model->setDiagnostics(m_projectSettings->suppressedDiagnostics()); + connect(m_projectSettings, &ProjectSettings::suppressedDiagnosticsChanged, + [model, this] { + model->setDiagnostics(m_projectSettings->suppressedDiagnostics()); + updateButtonStates(); + }); + m_ui->diagnosticsView->setModel(model); + updateButtonStates(); + connect(m_ui->diagnosticsView->selectionModel(), &QItemSelectionModel::selectionChanged, + [this](const QItemSelection &, const QItemSelection &) { + updateButtonStateRemoveSelected(); + }); + connect(m_ui->removeSelectedButton, &QAbstractButton::clicked, + [this](bool) { removeSelected(); }); + connect(m_ui->removeAllButton, &QAbstractButton::clicked, + [this](bool) { m_projectSettings->removeAllSuppressedDiagnostics();}); +} + +ProjectSettingsWidget::~ProjectSettingsWidget() +{ + delete m_ui; +} + +void ProjectSettingsWidget::updateButtonStates() +{ + updateButtonStateRemoveSelected(); + updateButtonStateRemoveAll(); +} + +void ProjectSettingsWidget::updateButtonStateRemoveSelected() +{ + const auto selectedRows = m_ui->diagnosticsView->selectionModel()->selectedRows(); + QTC_ASSERT(selectedRows.count() <= 1, return); + m_ui->removeSelectedButton->setEnabled(!selectedRows.isEmpty()); +} + +void ProjectSettingsWidget::updateButtonStateRemoveAll() +{ + m_ui->removeAllButton->setEnabled(m_ui->diagnosticsView->model()->rowCount() > 0); +} + +void ProjectSettingsWidget::removeSelected() +{ + const auto selectedRows = m_ui->diagnosticsView->selectionModel()->selectedRows(); + QTC_ASSERT(selectedRows.count() == 1, return); + const auto * const model + = static_cast(m_ui->diagnosticsView->model()); + m_projectSettings->removeSuppressedDiagnostic(model->diagnosticAt(selectedRows.first().row())); +} + + +void SuppressedDiagnosticsModel::setDiagnostics(const SuppressedDiagnosticsList &diagnostics) +{ + beginResetModel(); + m_diagnostics = diagnostics; + endResetModel(); +} + +SuppressedDiagnostic SuppressedDiagnosticsModel::diagnosticAt(int i) const +{ + return m_diagnostics.at(i); +} + +int SuppressedDiagnosticsModel::rowCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : m_diagnostics.count(); +} + +QVariant SuppressedDiagnosticsModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { + if (section == ColumnFile) + return tr("File"); + if (section == ColumnContext) + return tr("Context"); + if (section == ColumnDescription) + return tr("Diagnostic"); + } + return QVariant(); +} + +QVariant SuppressedDiagnosticsModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || role != Qt::DisplayRole || index.row() >= rowCount()) + return QVariant(); + const SuppressedDiagnostic &diag = m_diagnostics.at(index.row()); + if (index.column() == ColumnFile) + return diag.filePath.toUserOutput(); + if (index.column() == ColumnContext) { + if (diag.contextKind == QLatin1String("function") && !diag.context.isEmpty()) + return tr("Function \"%1\"").arg(diag.context); + return QString(); + } + if (index.column() == ColumnDescription) + return diag.description; + return QVariant(); +} + +} // namespace Internal +} // namespace ClangStaticAnalyzer + +#include "clangstaticanalyzerprojectsettingswidget.moc" diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.h b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.h new file mode 100644 index 0000000000..6669919736 --- /dev/null +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Qt Quick Profiler Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ +#ifndef CLANGSTATICANALYZERPROJECTSETTINGSWIDGET_H +#define CLANGSTATICANALYZERPROJECTSETTINGSWIDGET_H + +#include + +namespace ProjectExplorer { class Project; } + +namespace ClangStaticAnalyzer { +namespace Internal { +class ProjectSettings; + +namespace Ui { class ProjectSettingsWidget; } + +class ProjectSettingsWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ProjectSettingsWidget(ProjectExplorer::Project *project, QWidget *parent = 0); + ~ProjectSettingsWidget(); + +private: + void updateButtonStates(); + void updateButtonStateRemoveSelected(); + void updateButtonStateRemoveAll(); + void removeSelected(); + + Ui::ProjectSettingsWidget * const m_ui; + ProjectSettings * const m_projectSettings; +}; + +} // namespace Internal +} // namespace ClangStaticAnalyzer + +#endif // Include guard. diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.ui b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.ui new file mode 100644 index 0000000000..c131bbe0c2 --- /dev/null +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.ui @@ -0,0 +1,87 @@ + + + ClangStaticAnalyzer::Internal::ProjectSettingsWidget + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + Suppressed Diagnostics: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + QAbstractItemView::SingleSelection + + + + + + + + + Remove Selected + + + + + + + Remove All + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp index 260aae865a..645186cc71 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp @@ -51,6 +51,7 @@ namespace Internal { ClangStaticAnalyzerTool::ClangStaticAnalyzerTool(QObject *parent) : QObject(parent) , m_diagnosticModel(0) + , m_diagnosticFilterModel(0) , m_diagnosticView(0) , m_goBack(0) , m_goNext(0) @@ -74,10 +75,9 @@ QWidget *ClangStaticAnalyzerTool::createWidgets() m_diagnosticView->setFrameStyle(QFrame::NoFrame); m_diagnosticView->setAttribute(Qt::WA_MacShowFocusRect, false); m_diagnosticModel = new ClangStaticAnalyzerDiagnosticModel(m_diagnosticView); - // TODO: Make use of the proxy model - QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(m_diagnosticView); - proxyModel->setSourceModel(m_diagnosticModel); - m_diagnosticView->setModel(proxyModel); + m_diagnosticFilterModel = new ClangStaticAnalyzerDiagnosticFilterModel(m_diagnosticView); + m_diagnosticFilterModel->setSourceModel(m_diagnosticModel); + m_diagnosticView->setModel(m_diagnosticFilterModel); m_diagnosticView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_diagnosticView->setAutoScroll(false); m_diagnosticView->setObjectName(QLatin1String("ClangStaticAnalyzerIssuesView")); @@ -203,6 +203,7 @@ void ClangStaticAnalyzerTool::startTool() setBusyCursor(true); Project *project = SessionManager::startupProject(); QTC_ASSERT(project, return); + m_diagnosticFilterModel->setProject(project); m_projectInfoBeforeBuild = CppTools::CppModelManager::instance()->projectInfo(project); QTC_ASSERT(m_projectInfoBeforeBuild.isValid(), return); m_running = true; @@ -241,15 +242,18 @@ void ClangStaticAnalyzerTool::onEngineFinished() QTC_ASSERT(m_goBack, return); QTC_ASSERT(m_goNext, return); QTC_ASSERT(m_diagnosticModel, return); + QTC_ASSERT(m_diagnosticFilterModel, return); resetCursorAndProjectInfoBeforeBuild(); const int issuesFound = m_diagnosticModel->rowCount(); - m_goBack->setEnabled(issuesFound > 1); - m_goNext->setEnabled(issuesFound > 1); + const int issuesVisible = m_diagnosticFilterModel->rowCount(); + m_goBack->setEnabled(issuesVisible > 1); + m_goNext->setEnabled(issuesVisible > 1); AnalyzerManager::showPermanentStatusMessage(issuesFound > 0 - ? AnalyzerManager::tr("Clang Static Analyzer finished, %n issues were found.", 0, issuesFound) + ? AnalyzerManager::tr("Clang Static Analyzer finished, %n issues were found (%1 suppressed).", + 0, issuesFound).arg(issuesFound - issuesVisible) : AnalyzerManager::tr("Clang Static Analyzer finished, no issues were found.")); m_running = false; emit finished(); diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.h b/plugins/clangstaticanalyzer/clangstaticanalyzertool.h index fa402a608e..89c8851acc 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.h +++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.h @@ -27,6 +27,7 @@ namespace Analyzer { class DetailedErrorView; } namespace ClangStaticAnalyzer { namespace Internal { +class ClangStaticAnalyzerDiagnosticFilterModel; class ClangStaticAnalyzerDiagnosticModel; class ClangStaticAnalyzerDiagnosticView; class Diagnostic; @@ -65,6 +66,7 @@ private: CppTools::ProjectInfo m_projectInfoBeforeBuild; ClangStaticAnalyzerDiagnosticModel *m_diagnosticModel; + ClangStaticAnalyzerDiagnosticFilterModel *m_diagnosticFilterModel; Analyzer::DetailedErrorView *m_diagnosticView; QAction *m_goBack; -- cgit v1.2.3 From f12e53e83cb3e1e04bc6eb2ec9e8ad24c28f00d5 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 26 Feb 2015 16:24:53 +0100 Subject: Make use of the "issues" pane when errors occur during analyzing. They can otherwise easily get lost in the Application output pane. Policy is as follows: - Failure to analyze a specific file is considered a warning. - If no file could be successfully analyzed, we add an error and pop up the issues pane. This approach is neither too noisy nor too quiet. Change-Id: Ifc577a215006a6a565eee7de5099bd690427f7de Reviewed-by: Nikolai Kosjar --- .../clangstaticanalyzerruncontrol.cpp | 30 +++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp index 15deb7b9ce..e0576299e4 100644 --- a/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp +++ b/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp @@ -23,6 +23,7 @@ #include "clangstaticanalyzersettings.h" #include "clangstaticanalyzerutils.h" +#include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include @@ -51,6 +53,14 @@ static Q_LOGGING_CATEGORY(LOG, "qtc.clangstaticanalyzer.runcontrol") namespace ClangStaticAnalyzer { namespace Internal { +static void logToIssuesPane(Task::TaskType type, const QString &message) +{ + TaskHub::addTask(type, message, Analyzer::Constants::ANALYZERTASK_ID); + if (type == Task::Error) + TaskHub::requestPopup(); +} + + ClangStaticAnalyzerRunControl::ClangStaticAnalyzerRunControl( const Analyzer::AnalyzerStartParameters &startParams, ProjectExplorer::RunConfiguration *runConfiguration, @@ -191,9 +201,10 @@ bool ClangStaticAnalyzerRunControl::startEngine() const QString executable = clangExecutableFromSettings(m_toolchainType, &isValidClangExecutable); if (!isValidClangExecutable) { - emit appendMessage(tr("Clang Static Analyzer: Invalid executable \"%1\", stop.") - .arg(executable) + QLatin1Char('\n'), - Utils::ErrorMessageFormat); + const QString errorMessage = tr("Clang Static Analyzer: Invalid executable \"%1\", stop.") + .arg(executable); + appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat); + logToIssuesPane(Task::Error, errorMessage); emit finished(); return false; } @@ -203,8 +214,10 @@ bool ClangStaticAnalyzerRunControl::startEngine() QTemporaryDir temporaryDir(QDir::tempPath() + QLatin1String("/qtc-clangstaticanalyzer-XXXXXX")); temporaryDir.setAutoRemove(false); if (!temporaryDir.isValid()) { - emit appendMessage(tr("Clang Static Analyzer: Failed to create temporary dir, stop.") - + QLatin1Char('\n'), Utils::ErrorMessageFormat); + const QString errorMessage + = tr("Clang Static Analyzer: Failed to create temporary dir, stop."); + appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat); + logToIssuesPane(Task::Error, errorMessage); emit finished(); return false; } @@ -273,6 +286,10 @@ void ClangStaticAnalyzerRunControl::analyzeNextFile() .arg(m_filesNotAnalyzed) + QLatin1Char('\n'), Utils::NormalMessageFormat); + if (m_filesAnalyzed == 0 && m_filesNotAnalyzed != 0) { + logToIssuesPane(Task::Error, + tr("Clang Static Analyzer: Failed to analyze any files.")); + } m_progress.reportFinished(); emit finished(); } @@ -336,7 +353,8 @@ void ClangStaticAnalyzerRunControl::onRunnerFinishedWithFailure(const QString &e + QLatin1Char('\n') , Utils::StdErrFormat); appendMessage(errorDetails, Utils::StdErrFormat); - + logToIssuesPane(Task::Warning, errorMessage); + logToIssuesPane(Task::Warning, errorDetails); handleFinished(); } -- cgit v1.2.3