summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@theqtcompany.com>2015-03-02 12:06:32 +0100
committerEike Ziller <eike.ziller@theqtcompany.com>2015-03-02 12:06:32 +0100
commit5b565ea657f2821a3fdd6d84211968812d9829a9 (patch)
tree65cc9d5ad6bd42b8c71048ead69ea2e86b66d063
parentc87737d97fd76b177b18bd7d0f1f2c4abe31f34f (diff)
parentf12e53e83cb3e1e04bc6eb2ec9e8ad24c28f00d5 (diff)
downloadqt-creator-5b565ea657f2821a3fdd6d84211968812d9829a9.tar.gz
Merge remote-tracking branch 'origin/3.4'
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzer.pro11
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzer.qbs9
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp4
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui6
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp71
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h27
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp47
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h9
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.cpp40
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerpathchooser.h40
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp24
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.cpp137
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.h87
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.cpp50
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.h47
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.cpp160
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.h52
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.ui87
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp30
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp34
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzertool.h16
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp2
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp18
-rw-r--r--plugins/clangstaticanalyzer/clangstaticanalyzerutils.h4
24 files changed, 967 insertions, 45 deletions
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzer.pro b/plugins/clangstaticanalyzer/clangstaticanalyzer.pro
index df939e9f36..67eb90ad41 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzer.pro
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzer.pro
@@ -10,7 +10,11 @@ SOURCES += \
clangstaticanalyzerdiagnosticmodel.cpp \
clangstaticanalyzerdiagnosticview.cpp \
clangstaticanalyzerlogfilereader.cpp \
+ clangstaticanalyzerpathchooser.cpp \
clangstaticanalyzerplugin.cpp \
+ clangstaticanalyzerprojectsettings.cpp \
+ clangstaticanalyzerprojectsettingsmanager.cpp \
+ clangstaticanalyzerprojectsettingswidget.cpp \
clangstaticanalyzerruncontrol.cpp \
clangstaticanalyzerruncontrolfactory.cpp \
clangstaticanalyzerrunner.cpp \
@@ -26,7 +30,11 @@ HEADERS += \
clangstaticanalyzerdiagnosticview.h \
clangstaticanalyzer_global.h \
clangstaticanalyzerlogfilereader.h \
+ clangstaticanalyzerpathchooser.h \
clangstaticanalyzerplugin.h \
+ clangstaticanalyzerprojectsettings.h \
+ clangstaticanalyzerprojectsettingsmanager.h \
+ clangstaticanalyzerprojectsettingswidget.h \
clangstaticanalyzerruncontrolfactory.h \
clangstaticanalyzerruncontrol.h \
clangstaticanalyzerrunner.h \
@@ -35,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 78c7decc5d..a97dc9f83c 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs
@@ -28,8 +28,17 @@ QtcPlugin {
"clangstaticanalyzerdiagnosticview.h",
"clangstaticanalyzerlogfilereader.cpp",
"clangstaticanalyzerlogfilereader.h",
+ "clangstaticanalyzerpathchooser.cpp",
+ "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/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 @@
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
- <widget class="Utils::PathChooser" name="clangExecutableChooser" native="true"/>
+ <widget class="ClangStaticAnalyzer::Internal::PathChooser" name="clangExecutableChooser" native="true"/>
</item>
</layout>
</item>
@@ -88,9 +88,9 @@
</widget>
<customwidgets>
<customwidget>
- <class>Utils::PathChooser</class>
+ <class>ClangStaticAnalyzer::Internal::PathChooser</class>
<extends>QWidget</extends>
- <header location="global">utils/pathchooser.h</header>
+ <header location="global">clangstaticanalyzer/clangstaticanalyzerpathchooser.h</header>
<container>1</container>
</customwidget>
</customwidgets>
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 <projectexplorer/project.h>
+#include <projectexplorer/session.h>
+#include <utils/qtcassert.h>
+
#include <QCoreApplication>
+#include <QFileInfo>
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<ClangStaticAnalyzerDiagnosticModel *>(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 <utils/fileutils.h>
#include <QAbstractListModel>
+#include <QPointer>
+#include <QSortFilterProxyModel>
+
+namespace ProjectExplorer { class Project; }
namespace ClangStaticAnalyzer {
namespace Internal {
@@ -45,6 +52,26 @@ private:
QList<Diagnostic> 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<ProjectExplorer::Project> 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 <utils/fileutils.h>
#include <utils/qtcassert.h>
+#include <QAction>
#include <QCoreApplication>
#include <QDebug>
#include <QFileInfo>
@@ -196,13 +201,18 @@ DetailedErrorDelegate::SummaryLineInfo ClangStaticAnalyzerDiagnosticDelegate::su
return info;
}
+Diagnostic ClangStaticAnalyzerDiagnosticDelegate::getDiagnostic(const QModelIndex &index) const
+{
+ return index.data(Qt::UserRole).value<Diagnostic>();
+}
+
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<Diagnostic>();
+ 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<Diagnostic>();
+ 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<ClangStaticAnalyzerDiagnosticDelegate *>(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<ClangStaticAnalyzerDiagnosticFilterModel *>(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<QAction *> ClangStaticAnalyzerDiagnosticView::customActions() const
+{
+ return QList<QAction *>() << 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<QAction *> 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/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 <utils/pathchooser.h>
+
+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/clangstaticanalyzerplugin.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp
index 1c09b0039e..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 <coreplugin/coreconstants.h>
#include <coreplugin/dialogs/ioptionspage.h>
#include <licensechecker/licensecheckerplugin.h>
+#include <projectexplorer/projectpanelfactory.h>
#include <extensionsystem/pluginmanager.h>
@@ -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<ProjectSettingsWidget>(QIcon());
+ ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);
+
LicenseChecker::LicenseCheckerPlugin *licenseChecker
= ExtensionSystem::PluginManager::getObject<LicenseChecker::LicenseCheckerPlugin>();
@@ -125,16 +133,26 @@ 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 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([tool] { tool->startTool(); });
action->setText(tr("Clang Static Analyzer"));
action->setToolTip(toolTip);
action->setMenuGroup(Constants::G_ANALYZER_TOOLS);
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 <utils/qtcassert.h>
+
+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 <projectexplorer/project.h>
+#include <utils/fileutils.h>
+
+#include <QList>
+#include <QObject>
+
+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<SuppressedDiagnostic> 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 <projectexplorer/session.h>
+
+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 <QHash>
+#include <QSharedPointer>
+
+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<ProjectExplorer::Project *, QSharedPointer<ProjectSettings>> 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 <utils/qtcassert.h>
+
+#include <QAbstractTableModel>
+
+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<SuppressedDiagnosticsModel *>(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 <QWidget>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ClangStaticAnalyzer::Internal::ProjectSettingsWidget</class>
+ <widget class="QWidget" name="ClangStaticAnalyzer::Internal::ProjectSettingsWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Suppressed Diagnostics:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QTreeView" name="diagnosticsView">
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="removeSelectedButton">
+ <property name="text">
+ <string>Remove Selected</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeAllButton">
+ <property name="text">
+ <string>Remove All</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
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 <analyzerbase/analyzerconstants.h>
#include <analyzerbase/analyzermanager.h>
#include <clangcodemodel/clangutils.h>
@@ -37,6 +38,7 @@
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
+#include <projectexplorer/taskhub.h>
#include <utils/algorithm.h>
@@ -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();
}
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
index 4fbc2aa5b5..645186cc71 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
@@ -49,16 +49,15 @@ namespace ClangStaticAnalyzer {
namespace Internal {
ClangStaticAnalyzerTool::ClangStaticAnalyzerTool(QObject *parent)
- : IAnalyzerTool(parent)
+ : QObject(parent)
, m_diagnosticModel(0)
+ , m_diagnosticFilterModel(0)
, m_diagnosticView(0)
, m_goBack(0)
, m_goNext(0)
, m_running(false)
{
setObjectName(QLatin1String("ClangStaticAnalyzerTool"));
- setRunMode(ProjectExplorer::ClangStaticAnalyzerMode);
- setToolMode(AnyMode);
}
QWidget *ClangStaticAnalyzerTool::createWidgets()
@@ -76,16 +75,16 @@ 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"));
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);
@@ -192,23 +191,23 @@ static bool dontStartAfterHintForDebugMode()
return false;
}
-void ClangStaticAnalyzerTool::startTool(StartMode mode)
+void ClangStaticAnalyzerTool::startTool()
{
- QTC_ASSERT(mode == Analyzer::StartLocal, return);
-
AnalyzerManager::showMode();
if (dontStartAfterHintForDebugMode())
return;
+ AnalyzerManager::showPermanentStatusMessage(QString());
m_diagnosticModel->clear();
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;
- ProjectExplorerPlugin::instance()->runProject(project, runMode());
+ ProjectExplorerPlugin::runProject(project, ProjectExplorer::ClangStaticAnalyzerMode);
}
CppTools::ProjectInfo ClangStaticAnalyzerTool::projectInfoBeforeBuild() const
@@ -243,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::showStatusMessage(issuesFound > 0
- ? AnalyzerManager::tr("Clang Static Analyzer finished, %n issues were found.", 0, issuesFound)
+ AnalyzerManager::showPermanentStatusMessage(issuesFound > 0
+ ? 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 24c39e3b39..89c8851acc 100644
--- a/plugins/clangstaticanalyzer/clangstaticanalyzertool.h
+++ b/plugins/clangstaticanalyzer/clangstaticanalyzertool.h
@@ -27,11 +27,14 @@ namespace Analyzer { class DetailedErrorView; }
namespace ClangStaticAnalyzer {
namespace Internal {
+class ClangStaticAnalyzerDiagnosticFilterModel;
class ClangStaticAnalyzerDiagnosticModel;
class ClangStaticAnalyzerDiagnosticView;
class Diagnostic;
-class ClangStaticAnalyzerTool : public Analyzer::IAnalyzerTool
+const char ClangStaticAnalyzerToolId[] = "ClangStaticAnalyzer";
+
+class ClangStaticAnalyzerTool : public QObject
{
Q_OBJECT
@@ -44,15 +47,15 @@ public:
bool isRunning() const { return m_running; }
QList<Diagnostic> 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);
+ void startTool();
+signals:
+ void finished(); // For testing.
+
+private:
void onEngineIsStarting();
void onNewDiagnosticsAvailable(const QList<Diagnostic> &diagnostics);
void onEngineFinished();
@@ -63,6 +66,7 @@ private:
CppTools::ProjectInfo m_projectInfoBeforeBuild;
ClangStaticAnalyzerDiagnosticModel *m_diagnosticModel;
+ ClangStaticAnalyzerDiagnosticFilterModel *m_diagnosticFilterModel;
Analyzer::DetailedErrorView *m_diagnosticView;
QAction *m_goBack;
diff --git a/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp b/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp
index 401359cc6c..21b086858e 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);
AnalyzerManager::startTool();
if (m_analyzerTool->isRunning()) {
QSignalSpy waiter(m_analyzerTool, SIGNAL(finished()));
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 <utils/environment.h>
+#include <QCoreApplication>
#include <QFileInfo>
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);