Cppcheck: Add ability to manually run cppcheck

Run cppcheck on selected files from current project via "Analyze"->"Cppcheck...."
Show results in a separate view in the same manner as ClangTools plugin.

Fixes: QTCREATORBUG-21673
Change-Id: Ibcaf4057a387a990f1da59025f15ba58f996953f
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Sergey Morozov
2019-11-03 23:00:16 +03:00
parent 07490e76de
commit 0aa95576c2
20 changed files with 936 additions and 126 deletions

View File

@@ -1,9 +1,13 @@
add_qtc_plugin(Cppcheck
DEPENDS Qt5::Widgets
PLUGIN_DEPENDS Core CppTools ProjectExplorer TextEditor
PLUGIN_DEPENDS Core Debugger CppTools ProjectExplorer TextEditor
SOURCES
cppcheckconstants.h
cppcheckdiagnostic.h
cppcheckdiagnostic.cpp cppcheckdiagnostic.h
cppcheckdiagnosticmanager.h
cppcheckdiagnosticsmodel.cppмcppcheckdiagnosticsmodel.h
cppcheckdiagnosticview.cpp cppcheckdiagnosticview.h
cppcheckmanualrundialog.cpp cppcheckmanualrundialog.h
cppcheckoptions.cpp cppcheckoptions.h
cppcheckplugin.cpp cppcheckplugin.h
cppcheckrunner.cpp cppcheckrunner.h

View File

@@ -1,6 +1,10 @@
include(../../qtcreatorplugin.pri)
SOURCES += \
cppcheckdiagnostic.cpp \
cppcheckdiagnosticsmodel.cpp \
cppcheckdiagnosticview.cpp \
cppcheckmanualrundialog.cpp \
cppcheckoptions.cpp \
cppcheckplugin.cpp \
cppcheckrunner.cpp \
@@ -12,6 +16,10 @@ SOURCES += \
HEADERS += \
cppcheckconstants.h \
cppcheckdiagnostic.h \
cppcheckdiagnosticmanager.h \
cppcheckdiagnosticsmodel.h \
cppcheckdiagnosticview.h \
cppcheckmanualrundialog.h \
cppcheckoptions.h \
cppcheckplugin.h \
cppcheckrunner.h \

View File

@@ -5,6 +5,7 @@ QtcPlugin {
Depends { name: "Core" }
Depends { name: "CppTools" }
Depends { name: "Debugger" }
Depends { name: "ProjectExplorer" }
Depends { name: "TextEditor" }
Depends { name: "Utils" }
@@ -13,7 +14,15 @@ QtcPlugin {
files: [
"cppcheckconstants.h",
"cppcheckdiagnostic.cpp",
"cppcheckdiagnostic.h",
"cppcheckdiagnosticmanager.h",
"cppcheckdiagnosticsmodel.cpp",
"cppcheckdiagnosticsmodel.h",
"cppcheckdiagnosticview.cpp",
"cppcheckdiagnosticview.h",
"cppcheckmanualrundialog.cpp",
"cppcheckmanualrundialog.h",
"cppcheckoptions.cpp",
"cppcheckoptions.h",
"cppcheckplugin.cpp",

View File

@@ -4,5 +4,6 @@ QTC_LIB_DEPENDS += \
utils
QTC_PLUGIN_DEPENDS += \
cpptools \
debugger \
projectexplorer \
texteditor

View File

@@ -49,7 +49,11 @@ const char SETTINGS_SHOW_OUTPUT[] = "showOutput";
const char SETTINGS_ADD_INCLUDE_PATHS[] = "addIncludePaths";
const char SETTINGS_GUESS_ARGUMENTS[] = "guessArguments";
const char CHECK_PROGRESS_ID[] = "Cppcheck.Cppcheck.CheckingTask";
const char CHECK_PROGRESS_ID[] = "Cppcheck.CheckingTask";
const char MANUAL_CHECK_PROGRESS_ID[] = "Cppcheck.ManualCheckingTask";
const char MANUAL_RUN_ACTION[] = "Cppcheck.ManualRun";
const char PERSPECTIVE_ID[] = "Cppcheck.Perspective";
} // namespace Constants
} // namespace Cppcheck

View File

@@ -0,0 +1,42 @@
/****************************************************************************
**
** Copyright (C) 2019 Sergey Morozov
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cppcheckdiagnostic.h"
namespace Cppcheck {
namespace Internal {
bool Diagnostic::operator==(const Diagnostic &r) const
{
return std::tie(severity, message, fileName, lineNumber)
== std::tie(r.severity, r.message, r.fileName, r.lineNumber);
}
quint32 qHash(const Diagnostic &diagnostic)
{
return qHash(diagnostic.message) ^ qHash(diagnostic.fileName) ^ diagnostic.lineNumber;
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -39,6 +39,7 @@ public:
bool isValid() const {
return !fileName.isEmpty() && lineNumber > 0;
}
bool operator==(const Diagnostic& diagnostic) const;
Severity severity = Severity::Information;
QString severityText;
@@ -48,5 +49,7 @@ public:
int lineNumber = 0;
};
quint32 qHash(const Diagnostic &diagnostic);
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,41 @@
/****************************************************************************
**
** Copyright (C) 2018 Sergey Morozov
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
namespace Cppcheck {
namespace Internal {
class Diagnostic;
class CppcheckDiagnosticManager
{
public:
virtual ~CppcheckDiagnosticManager() = default;
virtual void add(const Diagnostic &diagnostic) = 0;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,143 @@
/****************************************************************************
**
** Copyright (C) 2019 Sergey Morozov
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cppcheckdiagnosticsmodel.h"
#include <coreplugin/fileiconprovider.h>
#include <debugger/analyzer/diagnosticlocation.h>
#include <utils/utilsicons.h>
namespace Cppcheck {
namespace Internal {
using namespace Debugger;
FilePathItem::FilePathItem(const QString &filePath)
: m_filePath(filePath)
{}
QVariant FilePathItem::data(int column, int role) const
{
if (column == DiagnosticsModel::DiagnosticColumn) {
switch (role) {
case Qt::DisplayRole:
return m_filePath;
case Qt::DecorationRole:
return Core::FileIconProvider::icon(m_filePath);
case Debugger::DetailedErrorView::FullTextRole:
return m_filePath;
default:
return QVariant();
}
}
return QVariant();
}
DiagnosticItem::DiagnosticItem(const Diagnostic &diagnostic)
: m_diagnostic(diagnostic)
{}
static QIcon getIcon(const Diagnostic::Severity severity)
{
switch (severity) {
case Diagnostic::Severity::Error:
return Utils::Icons::CRITICAL.icon();
case Diagnostic::Severity::Warning:
return Utils::Icons::WARNING.icon();
default:
return Utils::Icons::INFO.icon();
}
}
QVariant DiagnosticItem::data(int column, int role) const
{
if (column == DiagnosticsModel::DiagnosticColumn) {
switch (role) {
case DetailedErrorView::LocationRole: {
const auto location = DiagnosticLocation(m_diagnostic.fileName.toString(),
m_diagnostic.lineNumber,
0);
return QVariant::fromValue(location);
}
case Qt::DisplayRole:
return QString("%1: %2").arg(m_diagnostic.lineNumber).arg(m_diagnostic.message);
case Qt::ToolTipRole:
return QString("%1: %2").arg(m_diagnostic.severityText, m_diagnostic.checkId);
case Qt::DecorationRole:
return getIcon(m_diagnostic.severity);
case Debugger::DetailedErrorView::FullTextRole:
return QString("%1:%2: %3")
.arg(m_diagnostic.fileName.toString())
.arg(m_diagnostic.lineNumber)
.arg(m_diagnostic.message);
default:
return QVariant();
}
}
return QVariant();
}
DiagnosticsModel::DiagnosticsModel(QObject *parent)
: BaseModel(parent)
{
setHeader({tr("Diagnostic")});
}
void DiagnosticsModel::clear()
{
const auto hasData = !m_diagnostics.isEmpty();
m_filePathToItem.clear();
m_diagnostics.clear();
BaseModel::clear();
if (hasData)
emit hasDataChanged(false);
}
void DiagnosticsModel::add(const Diagnostic &diagnostic)
{
if (m_diagnostics.contains(diagnostic))
return;
const auto hasData = !m_diagnostics.isEmpty();
m_diagnostics.insert(diagnostic);
if (!hasData)
emit hasDataChanged(true);
const QString filePath = diagnostic.fileName.toString();
FilePathItem *&filePathItem = m_filePathToItem[filePath];
if (!filePathItem) {
filePathItem = new FilePathItem(filePath);
rootItem()->appendChild(filePathItem);
}
filePathItem->appendChild(new DiagnosticItem(diagnostic));
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,81 @@
/****************************************************************************
**
** Copyright (C) 2019 Sergey Morozov
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <cppcheck/cppcheckdiagnostic.h>
#include <cppcheck/cppcheckdiagnosticmanager.h>
#include <debugger/analyzer/detailederrorview.h>
#include <utils/treemodel.h>
namespace Cppcheck {
namespace Internal {
class DiagnosticsModel;
class FilePathItem : public Utils::TreeItem
{
public:
explicit FilePathItem(const QString &filePath);
QVariant data(int column, int role) const override;
private:
const QString m_filePath;
};
class DiagnosticItem : public Utils::TreeItem
{
public:
explicit DiagnosticItem(const Diagnostic &diagnostic);
QVariant data(int column, int role) const override;
private:
const Diagnostic m_diagnostic;
};
using BaseModel = Utils::TreeModel<Utils::TreeItem, FilePathItem, DiagnosticItem>;
class DiagnosticsModel : public BaseModel, public CppcheckDiagnosticManager
{
Q_OBJECT
public:
enum Column {DiagnosticColumn};
explicit DiagnosticsModel(QObject *parent = nullptr);
void clear();
void add(const Diagnostic &diagnostic) override;
signals:
void hasDataChanged(bool hasData);
private:
QHash<QString, FilePathItem *> m_filePathToItem;
QSet<Diagnostic> m_diagnostics;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,118 @@
/****************************************************************************
**
** Copyright (C) 2019 Sergey Morozov
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cppcheckdiagnosticview.h"
#include <coreplugin/editormanager/editormanager.h>
#include <debugger/analyzer/diagnosticlocation.h>
namespace Cppcheck {
namespace Internal {
using namespace Debugger;
DiagnosticView::DiagnosticView(QWidget *parent)
: DetailedErrorView(parent)
{
setFrameStyle(QFrame::NoFrame);
setAttribute(Qt::WA_MacShowFocusRect, false);
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
setAutoScroll(false);
sortByColumn(DiagnosticColumn, Qt::AscendingOrder);
setObjectName("CppcheckIssuesView");
setWindowTitle(tr("Cppcheck Diagnostics"));
setHeaderHidden(true);
}
void DiagnosticView::goNext()
{
const auto totalFiles = model()->rowCount();
if (totalFiles == 0)
return;
const QModelIndex currentIndex = selectionModel()->currentIndex();
const QModelIndex parent = currentIndex.parent();
const auto onDiagnostic = parent.isValid();
if (onDiagnostic && currentIndex.row() < model()->rowCount(parent) - 1) {
selectIndex(currentIndex.sibling(currentIndex.row() + 1, 0));
return;
}
auto newFileRow = 0;
if (!currentIndex.isValid()) // not selected
newFileRow = 0;
else if (!onDiagnostic) // selected file
newFileRow = currentIndex.row();
else // selected last item in file
newFileRow = parent.row() == totalFiles - 1 ? 0 : parent.row() + 1;
const QModelIndex newParent = model()->index(newFileRow, 0);
selectIndex(model()->index(0, 0, newParent));
}
void DiagnosticView::goBack()
{
const auto totalFiles = model()->rowCount();
if (totalFiles == 0)
return;
const QModelIndex currentIndex = selectionModel()->currentIndex();
const QModelIndex parent = currentIndex.parent();
const auto onDiagnostic = parent.isValid();
if (onDiagnostic && currentIndex.row() > 0) {
selectIndex(currentIndex.sibling(currentIndex.row() - 1, 0));
return;
}
auto newFileRow = 0;
if (!currentIndex.isValid()) // not selected
newFileRow = totalFiles - 1;
else if (!onDiagnostic) // selected file
newFileRow = currentIndex.row() == 0 ? totalFiles - 1 : currentIndex.row() - 1;
else // selected first item in file
newFileRow = parent.row() == 0 ? totalFiles - 1 : parent.row() - 1;
const QModelIndex newParent = model()->index(newFileRow, 0);
const auto newParentRows = model()->rowCount(newParent);
selectIndex(model()->index(newParentRows - 1, 0, newParent));
}
DiagnosticView::~DiagnosticView() = default;
void DiagnosticView::openEditorForCurrentIndex()
{
const QVariant v = model()->data(currentIndex(), Debugger::DetailedErrorView::LocationRole);
const auto loc = v.value<Debugger::DiagnosticLocation>();
if (loc.isValid())
Core::EditorManager::openEditorAt(loc.filePath, loc.line, loc.column - 1);
}
void DiagnosticView::mouseDoubleClickEvent(QMouseEvent *event)
{
openEditorForCurrentIndex();
DetailedErrorView::mouseDoubleClickEvent(event);
}
} // namespace Internal
} // namespace Cppcheck
//#include "clangtoolsdiagnosticview.moc"

View File

@@ -0,0 +1,49 @@
/****************************************************************************
**
** Copyright (C) 2019 Sergey Morozov
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <debugger/analyzer/detailederrorview.h>
namespace Cppcheck {
namespace Internal {
class DiagnosticView : public Debugger::DetailedErrorView
{
Q_OBJECT
public:
explicit DiagnosticView(QWidget *parent = nullptr);
~DiagnosticView() override;
void goNext() override;
void goBack() override;
private:
void openEditorForCurrentIndex();
void mouseDoubleClickEvent(QMouseEvent *event) override;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,108 @@
/****************************************************************************
**
** Copyright (C) 2019 Sergey Morozov
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cppcheckmanualrundialog.h"
#include "cppcheckoptions.h"
#include <projectexplorer/selectablefilesmodel.h>
#include <cpptools/projectinfo.h>
#include <utils/qtcassert.h>
#include <QBoxLayout>
#include <QDialogButtonBox>
#include <QPushButton>
namespace Cppcheck {
namespace Internal {
ManualRunDialog::ManualRunDialog(const CppcheckOptions &options,
const ProjectExplorer::Project *project)
: QDialog(),
m_options(new OptionsWidget(this)),
m_model(new ProjectExplorer::SelectableFilesFromDirModel(this))
{
QTC_ASSERT(project, return );
setWindowTitle(tr("Cppcheck run configuration"));
auto view = new QTreeView;
view->setHeaderHidden(true);
view->setModel(m_model);
connect(m_model, &ProjectExplorer::SelectableFilesFromDirModel::parsingFinished,
view, [this, view] {
m_model->applyFilter("*.cpp;*.cxx;*.c;*.cc;*.C", {});
view->expandToDepth(0);
});
m_model->startParsing(project->rootProjectDirectory());
auto buttons = new QDialogButtonBox;
buttons->setStandardButtons(QDialogButtonBox::Cancel);
connect(buttons, &QDialogButtonBox::accepted,
this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected,
this, &QDialog::reject);
auto analyzeButton = new QPushButton(tr("Analyze"));
buttons->addButton(analyzeButton, QDialogButtonBox::AcceptRole);
analyzeButton->setEnabled(m_model->hasCheckedFiles());
connect(m_model, &QAbstractItemModel::dataChanged,
analyzeButton, [this, analyzeButton]() {
analyzeButton->setEnabled(m_model->hasCheckedFiles());
});
auto layout = new QVBoxLayout(this);
layout->addWidget(m_options);
layout->addWidget(view);
layout->addWidget(buttons);
if (auto layout = m_options->layout())
layout->setMargin(0);
m_options->load(options);
}
CppcheckOptions ManualRunDialog::options() const
{
CppcheckOptions result;
m_options->save(result);
return result;
}
Utils::FilePathList ManualRunDialog::filePaths() const
{
return m_model->selectedFiles();
}
QSize ManualRunDialog::sizeHint() const
{
const auto original = QDialog::sizeHint();
return {original.width() * 2, original.height()};
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,63 @@
/****************************************************************************
**
** Copyright (C) 2019 Sergey Morozov
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QDialog>
namespace Utils {
class FilePath;
using FilePathList = QList<FilePath>;
} // namespace Utils
namespace ProjectExplorer {
class Project;
class SelectableFilesFromDirModel;
} // namespace ProjectExplorer
namespace Cppcheck {
namespace Internal {
class OptionsWidget;
class CppcheckOptions;
class ManualRunDialog : public QDialog
{
Q_OBJECT
public:
ManualRunDialog(const CppcheckOptions &options,
const ProjectExplorer::Project *project);
CppcheckOptions options() const;
Utils::FilePathList filePaths() const;
QSize sizeHint() const override;
private:
OptionsWidget *m_options;
ProjectExplorer::SelectableFilesFromDirModel *m_model;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -45,11 +45,7 @@
namespace Cppcheck {
namespace Internal {
class OptionsWidget final : public QWidget
{
Q_DECLARE_TR_FUNCTIONS(CppcheckOptionsPage)
public:
explicit OptionsWidget(QWidget *parent = nullptr)
OptionsWidget::OptionsWidget(QWidget *parent)
: QWidget(parent),
m_binary(new Utils::PathChooser(this)),
m_customArguments(new QLineEdit(this)),
@@ -66,7 +62,7 @@ public:
m_showOutput(new QCheckBox(tr("Show raw output"), this)),
m_addIncludePaths(new QCheckBox(tr("Add include paths"), this)),
m_guessArguments(new QCheckBox(tr("Calculate additional arguments"), this))
{
{
m_binary->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_binary->setCommandVersionArguments({"--version"});
@@ -102,10 +98,10 @@ public:
flags->addWidget(m_showOutput);
flags->addWidget(m_addIncludePaths);
flags->addWidget(m_guessArguments);
}
}
void load(const CppcheckOptions &options)
{
void OptionsWidget::load(const CppcheckOptions &options)
{
m_binary->setPath(options.binary);
m_customArguments->setText(options.customArguments);
m_ignorePatterns->setText(options.ignoredPatterns);
@@ -121,10 +117,10 @@ public:
m_showOutput->setChecked(options.showOutput);
m_addIncludePaths->setChecked(options.addIncludePaths);
m_guessArguments->setChecked(options.guessArguments);
}
}
void save(CppcheckOptions &options) const
{
void OptionsWidget::save(CppcheckOptions &options) const
{
options.binary = m_binary->path();
options.customArguments = m_customArguments->text();
options.ignoredPatterns = m_ignorePatterns->text();
@@ -140,25 +136,7 @@ public:
options.showOutput = m_showOutput->isChecked();
options.addIncludePaths = m_addIncludePaths->isChecked();
options.guessArguments = m_guessArguments->isChecked();
}
private:
Utils::PathChooser *m_binary = nullptr;
QLineEdit *m_customArguments = nullptr;
QLineEdit *m_ignorePatterns = nullptr;
QCheckBox *m_warning = nullptr;
QCheckBox *m_style = nullptr;
QCheckBox *m_performance = nullptr;
QCheckBox *m_portability = nullptr;
QCheckBox *m_information = nullptr;
QCheckBox *m_unusedFunction = nullptr;
QCheckBox *m_missingInclude = nullptr;
QCheckBox *m_inconclusive = nullptr;
QCheckBox *m_forceDefines = nullptr;
QCheckBox *m_showOutput = nullptr;
QCheckBox *m_addIncludePaths = nullptr;
QCheckBox *m_guessArguments = nullptr;
};
}
CppcheckOptionsPage::CppcheckOptionsPage(CppcheckTool &tool, CppcheckTrigger &trigger):
m_tool(tool),

View File

@@ -27,7 +27,16 @@
#include <coreplugin/dialogs/ioptionspage.h>
#include <QCoreApplication>
#include <QPointer>
#include <QWidget>
class QLineEdit;
class QCheckBox;
namespace Utils {
class PathChooser;
}
namespace Cppcheck {
namespace Internal {
@@ -58,6 +67,32 @@ public:
bool guessArguments = true;
};
class OptionsWidget final : public QWidget
{
Q_DECLARE_TR_FUNCTIONS(CppcheckOptionsPage)
public:
explicit OptionsWidget(QWidget *parent = nullptr);
void load(const CppcheckOptions &options);
void save(CppcheckOptions &options) const;
private:
Utils::PathChooser *m_binary = nullptr;
QLineEdit *m_customArguments = nullptr;
QLineEdit *m_ignorePatterns = nullptr;
QCheckBox *m_warning = nullptr;
QCheckBox *m_style = nullptr;
QCheckBox *m_performance = nullptr;
QCheckBox *m_portability = nullptr;
QCheckBox *m_information = nullptr;
QCheckBox *m_unusedFunction = nullptr;
QCheckBox *m_missingInclude = nullptr;
QCheckBox *m_inconclusive = nullptr;
QCheckBox *m_forceDefines = nullptr;
QCheckBox *m_showOutput = nullptr;
QCheckBox *m_addIncludePaths = nullptr;
QCheckBox *m_guessArguments = nullptr;
};
class CppcheckOptionsPage final : public Core::IOptionsPage
{
Q_OBJECT

View File

@@ -23,16 +23,34 @@
**
****************************************************************************/
#include "cppcheckoptions.h"
#include "cppcheckplugin.h"
#include "cppcheckconstants.h"
#include "cppcheckdiagnosticview.h"
#include "cppchecktextmarkmanager.h"
#include "cppchecktool.h"
#include "cppchecktrigger.h"
#include "cppcheckdiagnosticsmodel.h"
#include "cppcheckmanualrundialog.h"
#include <projectexplorer/session.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/project.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <debugger/analyzer/analyzerconstants.h>
#include <debugger/debuggermainwindow.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
namespace Cppcheck {
namespace Internal {
class CppcheckPluginPrivate final
class CppcheckPluginPrivate final : public QObject
{
public:
explicit CppcheckPluginPrivate();
@@ -40,13 +58,98 @@ public:
CppcheckTool tool;
CppcheckTrigger trigger;
CppcheckOptionsPage options;
DiagnosticsModel manualRunModel;
CppcheckTool manualRunTool;
Utils::Perspective perspective{Constants::PERSPECTIVE_ID,
tr("Cppcheck", "CppcheckPlugin")};
QAction *manualRunAction;
void startManualRun();
void updateManualRunAction();
};
CppcheckPluginPrivate::CppcheckPluginPrivate() :
tool(marks),
tool(marks, Constants::CHECK_PROGRESS_ID),
trigger(marks, tool),
options(tool, trigger)
options(tool, trigger),
manualRunTool(manualRunModel, Constants::MANUAL_CHECK_PROGRESS_ID)
{
manualRunTool.updateOptions(tool.options());
auto manualRunView = new DiagnosticView;
manualRunView->setModel(&manualRunModel);
perspective.addWindow(manualRunView, Utils::Perspective::SplitVertical, nullptr);
{
// Go to previous diagnostic
auto action = new QAction(this);
action->setEnabled(false);
action->setIcon(Utils::Icons::PREV_TOOLBAR.icon());
action->setToolTip(tr("Go to previous diagnostic."));
connect(action, &QAction::triggered,
manualRunView, &Debugger::DetailedErrorView::goBack);
connect (&manualRunModel, &DiagnosticsModel::hasDataChanged,
action, &QAction::setEnabled);
perspective.addToolBarAction(action);
}
{
// Go to next diagnostic
auto action = new QAction(this);
action->setEnabled(false);
action->setIcon(Utils::Icons::NEXT_TOOLBAR.icon());
action->setToolTip(tr("Go to next diagnostic."));
connect(action, &QAction::triggered,
manualRunView, &Debugger::DetailedErrorView::goNext);
connect (&manualRunModel, &DiagnosticsModel::hasDataChanged,
action, &QAction::setEnabled);
perspective.addToolBarAction(action);
}
{
// Clear data
auto action = new QAction(this);
action->setEnabled(false);
action->setIcon(Utils::Icons::CLEAN_TOOLBAR.icon());
action->setToolTip(tr("Clear"));
connect(action, &QAction::triggered,
&manualRunModel, &DiagnosticsModel::clear);
connect (&manualRunModel, &DiagnosticsModel::hasDataChanged,
action, &QAction::setEnabled);
perspective.addToolBarAction(action);
}
}
void CppcheckPluginPrivate::startManualRun() {
auto project = ProjectExplorer::SessionManager::startupProject();
if (!project)
return;
ManualRunDialog dialog(manualRunTool.options(), project);
if (dialog.exec() == ManualRunDialog::Rejected)
return;
manualRunModel.clear();
const auto files = dialog.filePaths();
if (files.isEmpty())
return;
manualRunTool.setProject(project);
manualRunTool.updateOptions(dialog.options());
manualRunTool.check(files);
perspective.select();
}
void CppcheckPluginPrivate::updateManualRunAction()
{
using namespace ProjectExplorer;
const Project *project = SessionManager::startupProject();
const Target *target = SessionManager::startupTarget();
const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
const bool canRun = target && project->projectLanguages().contains(cxx)
&& ToolChainKitAspect::toolChain(target->kit(), cxx);
manualRunAction->setEnabled(canRun);
}
CppcheckPlugin::CppcheckPlugin() = default;
@@ -60,6 +163,23 @@ bool CppcheckPlugin::initialize(const QStringList &arguments, QString *errorStri
d.reset(new CppcheckPluginPrivate);
using namespace Core;
ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER);
{
auto action = new QAction(tr("Cppcheck..."), this);
menu->addAction(ActionManager::registerAction(action, Constants::MANUAL_RUN_ACTION),
Debugger::Constants::G_ANALYZER_TOOLS);
connect(action, &QAction::triggered,
d.get(), &CppcheckPluginPrivate::startManualRun);
d->manualRunAction = action;
}
using ProjectExplorer::ProjectExplorerPlugin;
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
d.get(), &CppcheckPluginPrivate::updateManualRunAction);
d->updateManualRunAction();
return true;
}

View File

@@ -25,6 +25,8 @@
#pragma once
#include <cppcheck/cppcheckdiagnosticmanager.h>
#include <utils/fileutils.h>
#include <unordered_map>
@@ -35,13 +37,13 @@ namespace Internal {
class Diagnostic;
class CppcheckTextMark;
class CppcheckTextMarkManager final
class CppcheckTextMarkManager final : public CppcheckDiagnosticManager
{
public:
explicit CppcheckTextMarkManager();
~CppcheckTextMarkManager();
~CppcheckTextMarkManager() override;
void add(const Diagnostic &diagnostic);
void add(const Diagnostic &diagnostic) override;
void clearFiles(const Utils::FilePathList &files);
private:

View File

@@ -23,7 +23,6 @@
**
****************************************************************************/
#include "cppcheckconstants.h"
#include "cppcheckdiagnostic.h"
#include "cppcheckoptions.h"
#include "cppcheckrunner.h"
@@ -45,10 +44,12 @@
namespace Cppcheck {
namespace Internal {
CppcheckTool::CppcheckTool(CppcheckTextMarkManager &marks) :
m_marks(marks),
CppcheckTool::CppcheckTool(CppcheckDiagnosticManager &manager,
const Core::Id &progressId) :
m_manager(manager),
m_progressRegexp("^.* checked (\\d+)% done$"),
m_messageRegexp("^(.+),(\\d+),(\\w+),(\\w+),(.*)$")
m_messageRegexp("^(.+),(\\d+),(\\w+),(\\w+),(.*)$"),
m_progressId(progressId)
{
m_runner = std::make_unique<CppcheckRunner>(*this);
QTC_ASSERT(m_progressRegexp.isValid(), return);
@@ -246,8 +247,7 @@ void CppcheckTool::startParsing()
m_progress = std::make_unique<QFutureInterface<void>>();
const Core::FutureProgress *progress = Core::ProgressManager::addTask(
m_progress->future(), QObject::tr("Cppcheck"),
Constants::CHECK_PROGRESS_ID);
m_progress->future(), QObject::tr("Cppcheck"), m_progressId);
QObject::connect(progress, &Core::FutureProgress::canceled,
this, [this]{stop({});});
m_progress->setProgressRange(0, 100);
@@ -310,7 +310,7 @@ void CppcheckTool::parseErrorLine(const QString &line)
diagnostic.checkId = match.captured(Id);
diagnostic.message = match.captured(Message);
if (diagnostic.isValid())
m_marks.add(diagnostic);
m_manager.add(diagnostic);
}
void CppcheckTool::finishParsing()

View File

@@ -50,7 +50,7 @@ namespace Cppcheck {
namespace Internal {
class CppcheckRunner;
class CppcheckTextMarkManager;
class CppcheckDiagnosticManager;
class CppcheckOptions;
class CppcheckTool final : public QObject
@@ -58,7 +58,7 @@ class CppcheckTool final : public QObject
Q_OBJECT
public:
explicit CppcheckTool(CppcheckTextMarkManager &marks);
CppcheckTool(CppcheckDiagnosticManager &manager, const Core::Id &progressId);
~CppcheckTool() override;
void updateOptions(const CppcheckOptions &options);
@@ -78,7 +78,7 @@ private:
void addToQueue(const Utils::FilePathList &files, CppTools::ProjectPart &part);
QStringList additionalArguments(const CppTools::ProjectPart &part) const;
CppcheckTextMarkManager &m_marks;
CppcheckDiagnosticManager &m_manager;
CppcheckOptions m_options;
QPointer<ProjectExplorer::Project> m_project;
std::unique_ptr<CppcheckRunner> m_runner;
@@ -87,6 +87,7 @@ private:
QVector<QRegExp> m_filters;
QRegularExpression m_progressRegexp;
QRegularExpression m_messageRegexp;
Core::Id m_progressId;
};
} // namespace Internal