Cppcheck: Add cppcheck static analysis tool

Automatically checks currently opened documents and displays results via text marks/annotations.

CppcheckTrigger detects when to check files or clear results.
CppcheckTextMarkManager stores/clears text marks with checks' results.
CppcheckTool generates run arguments and parses output.
CppcheckRunner runs cppcheck binary.
CppcheckOptions configures CppcheckTool.

Task-number: QTCREATORBUG-20418
Change-Id: I8eafeac7af6137d2c9061ae75d4a56c85b3b5a2d
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Sergey Morozov
2018-07-30 21:42:47 +03:00
parent 20f3c8d654
commit 31b595314c
22 changed files with 1919 additions and 1 deletions

View File

@@ -0,0 +1,20 @@
{
\"Name\" : \"Cppcheck\",
\"Version\" : \"$$QTCREATOR_VERSION\",
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
\"Experimental\" : true,
\"Vendor\" : \"Sergey Morozov\",
\"Copyright\" : \"(C) 2018 Sergey Morozov, (C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\",
\"License\" : [ \"Commercial 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.\"
],
\"Category\" : \"Code Analyzer\",
\"Description\" : \"Cppcheck static analyzer tool integration. See http://cppcheck.sourceforge.net.\",
\"Url\" : \"http://www.qt.io\",
$$dependencyList
}

View File

@@ -0,0 +1,21 @@
include(../../qtcreatorplugin.pri)
SOURCES += \
cppcheckoptions.cpp \
cppcheckplugin.cpp \
cppcheckrunner.cpp \
cppchecktextmark.cpp \
cppchecktextmarkmanager.cpp \
cppchecktool.cpp \
cppchecktrigger.cpp
HEADERS += \
cppcheckconstants.h \
cppcheckdiagnostic.h \
cppcheckoptions.h \
cppcheckplugin.h \
cppcheckrunner.h \
cppchecktextmark.h \
cppchecktextmarkmanager.h \
cppchecktool.h \
cppchecktrigger.h

View File

@@ -0,0 +1,33 @@
import qbs
QtcPlugin {
name: "Cppcheck"
Depends { name: "Core" }
Depends { name: "CppTools" }
Depends { name: "ExtensionSystem" }
Depends { name: "ProjectExplorer" }
Depends { name: "TextEditor" }
Depends { name: "Utils" }
Depends { name: "Qt.widgets" }
files: [
"cppcheckconstants.h",
"cppcheckdiagnostic.h",
"cppcheckoptions.cpp",
"cppcheckoptions.h",
"cppcheckplugin.cpp",
"cppcheckplugin.h",
"cppcheckrunner.cpp",
"cppcheckrunner.h",
"cppchecktextmark.cpp",
"cppchecktextmark.h",
"cppchecktextmarkmanager.cpp",
"cppchecktextmarkmanager.h",
"cppchecktool.cpp",
"cppchecktool.h",
"cppchecktrigger.cpp",
"cppchecktrigger.h"
]
}

View File

@@ -0,0 +1,8 @@
QTC_PLUGIN_NAME = Cppcheck
QTC_LIB_DEPENDS += \
extensionsystem \
utils
QTC_PLUGIN_DEPENDS += \
cpptools \
projectexplorer \
texteditor

View File

@@ -0,0 +1,55 @@
/****************************************************************************
**
** 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 Constants {
const char TEXTMARK_CATEGORY_ID[] = "Cppcheck";
const char OPTIONS_PAGE_ID[] = "Analyzer.Cppcheck.Settings";
const char SETTINGS_ID[] = "Cppcheck";
const char SETTINGS_BINARY[] = "binary";
const char SETTINGS_WARNING[] = "warning";
const char SETTINGS_STYLE[] = "style";
const char SETTINGS_PERFORMANCE[] = "performance";
const char SETTINGS_PORTABILITY[] = "portability";
const char SETTINGS_INFORMATION[] = "information";
const char SETTINGS_UNUSED_FUNCTION[] = "unusedFunction";
const char SETTINGS_MISSING_INCLUDE[] = "missingInclude";
const char SETTINGS_INCONCLUSIVE[] = "inconclusive";
const char SETTINGS_FORCE_DEFINES[] = "forceDefines";
const char SETTINGS_CUSTOM_ARGUMENTS[] = "customArguments";
const char SETTINGS_IGNORE_PATTERNS[] = "ignorePatterns";
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";
} // namespace Constants
} // namespace Cppcheck

View File

@@ -0,0 +1,52 @@
/****************************************************************************
**
** 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
#include <utils/fileutils.h>
namespace Cppcheck {
namespace Internal {
class Diagnostic final
{
public:
enum class Severity {
Error, Warning, Performance, Portability, Style, Information
};
bool isValid() const {
return !fileName.isEmpty() && lineNumber > 0;
}
Severity severity = Severity::Information;
QString severityText;
QString checkId;
QString message;
Utils::FileName fileName;
int lineNumber = 0;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,267 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "cppcheckconstants.h"
#include "cppcheckoptions.h"
#include "cppchecktool.h"
#include "cppchecktrigger.h"
#include <utils/flowlayout.h>
#include <utils/hostosinfo.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
#include <coreplugin/variablechooser.h>
#include <QCheckBox>
#include <QDir>
#include <QFormLayout>
namespace Cppcheck {
namespace Internal {
class OptionsWidget final : public QWidget
{
public:
explicit OptionsWidget(QWidget *parent = nullptr)
: QWidget(parent),
m_binary(new Utils::PathChooser(this)),
m_customArguments(new QLineEdit(this)),
m_ignorePatterns(new QLineEdit(this)),
m_warning(new QCheckBox(tr("Warnings"), this)),
m_style(new QCheckBox(tr("Style"), this)),
m_performance(new QCheckBox(tr("Performance"), this)),
m_portability(new QCheckBox(tr("Portability"), this)),
m_information(new QCheckBox(tr("Information"), this)),
m_unusedFunction(new QCheckBox(tr("Unused functions"), this)),
m_missingInclude(new QCheckBox(tr("Missing include"), this)),
m_inconclusive(new QCheckBox(tr("Inconclusive errors"), this)),
m_forceDefines(new QCheckBox(tr("Check all define combinations"), this)),
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"});
const auto variableChooser = new Core::VariableChooser (this);
variableChooser->addSupportedWidget (m_customArguments);
m_unusedFunction->setToolTip(tr("Disables multithreaded check."));
m_ignorePatterns->setToolTip(tr("Comma-separated wildcards of full file paths."
"Files still can be checked if others include them."));
m_addIncludePaths->setToolTip(tr("Can find missing includes but makes "
"checking slower. Use only when needed."));
m_guessArguments->setToolTip(tr("Like C++ standard and language."));
const auto layout = new QFormLayout(this);
layout->addRow(tr("Binary:"), m_binary);
const auto checks = new Utils::FlowLayout;
layout->addRow(tr("Checks:"), checks);
checks->addWidget(m_warning);
checks->addWidget(m_style);
checks->addWidget(m_performance);
checks->addWidget(m_portability);
checks->addWidget(m_information);
checks->addWidget(m_unusedFunction);
checks->addWidget(m_missingInclude);
layout->addRow(tr("Custom arguments:"), m_customArguments);
layout->addRow(tr("Ignored file patterns:"), m_ignorePatterns);
const auto flags = new Utils::FlowLayout;
layout->addRow(flags);
flags->addWidget(m_inconclusive);
flags->addWidget(m_forceDefines);
flags->addWidget(m_showOutput);
flags->addWidget(m_addIncludePaths);
flags->addWidget(m_guessArguments);
}
void load(const CppcheckOptions &options)
{
m_binary->setPath(options.binary);
m_customArguments->setText(options.customArguments);
m_ignorePatterns->setText(options.ignoredPatterns);
m_warning->setChecked(options.warning);
m_style->setChecked(options.style);
m_performance->setChecked(options.performance);
m_portability->setChecked(options.portability);
m_information->setChecked(options.information);
m_unusedFunction->setChecked(options.unusedFunction);
m_missingInclude->setChecked(options.missingInclude);
m_inconclusive->setChecked(options.inconclusive);
m_forceDefines->setChecked(options.forceDefines);
m_showOutput->setChecked(options.showOutput);
m_addIncludePaths->setChecked(options.addIncludePaths);
m_guessArguments->setChecked(options.guessArguments);
}
void save(CppcheckOptions &options) const
{
options.binary = m_binary->path();
options.customArguments = m_customArguments->text();
options.ignoredPatterns = m_ignorePatterns->text();
options.warning = m_warning->isChecked();
options.style = m_style->isChecked();
options.performance = m_performance->isChecked();
options.portability = m_portability->isChecked();
options.information = m_information->isChecked();
options.unusedFunction = m_unusedFunction->isChecked();
options.missingInclude = m_missingInclude->isChecked();
options.inconclusive = m_inconclusive->isChecked();
options.forceDefines = m_forceDefines->isChecked();
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),
m_trigger(trigger)
{
setId(Constants::OPTIONS_PAGE_ID);
setDisplayName(tr("Cppcheck"));
setCategory("T.Analyzer");
CppcheckOptions options;
if (Utils::HostOsInfo::isAnyUnixHost()) {
options.binary = "cppcheck";
} else {
auto programFiles = QDir::fromNativeSeparators(
QString::fromLocal8Bit(qgetenv("PROGRAMFILES")));
if (programFiles.isEmpty())
programFiles = "C:/Program Files";
options.binary = programFiles + "/Cppcheck/cppcheck.exe";
}
load(options);
m_tool.updateOptions(options);
}
QWidget *CppcheckOptionsPage::widget()
{
if (!m_widget)
m_widget = new OptionsWidget;
m_widget->load(m_tool.options());
return m_widget.data();
}
void CppcheckOptionsPage::apply()
{
CppcheckOptions options;
m_widget->save(options);
save(options);
m_tool.updateOptions(options);
m_trigger.recheck();
}
void CppcheckOptionsPage::finish()
{
}
void CppcheckOptionsPage::save(const CppcheckOptions &options) const
{
const auto s = Core::ICore::settings();
QTC_ASSERT(s, return);
s->beginGroup(Constants::SETTINGS_ID);
s->setValue(Constants::SETTINGS_BINARY, options.binary);
s->setValue(Constants::SETTINGS_CUSTOM_ARGUMENTS, options.customArguments);
s->setValue(Constants::SETTINGS_IGNORE_PATTERNS, options.ignoredPatterns);
s->setValue(Constants::SETTINGS_WARNING, options.warning);
s->setValue(Constants::SETTINGS_STYLE, options.style);
s->setValue(Constants::SETTINGS_PERFORMANCE, options.performance);
s->setValue(Constants::SETTINGS_PORTABILITY, options.portability);
s->setValue(Constants::SETTINGS_INFORMATION, options.information);
s->setValue(Constants::SETTINGS_UNUSED_FUNCTION, options.unusedFunction);
s->setValue(Constants::SETTINGS_MISSING_INCLUDE, options.missingInclude);
s->setValue(Constants::SETTINGS_INCONCLUSIVE, options.inconclusive);
s->setValue(Constants::SETTINGS_FORCE_DEFINES, options.forceDefines);
s->setValue(Constants::SETTINGS_SHOW_OUTPUT, options.showOutput);
s->setValue(Constants::SETTINGS_ADD_INCLUDE_PATHS, options.addIncludePaths);
s->setValue(Constants::SETTINGS_GUESS_ARGUMENTS, options.guessArguments);
s->endGroup();
}
void CppcheckOptionsPage::load(CppcheckOptions &options) const
{
const auto s = Core::ICore::settings();
QTC_ASSERT(s, return);
s->beginGroup(Constants::SETTINGS_ID);
options.binary = s->value(Constants::SETTINGS_BINARY,
options.binary).toString();
options.customArguments = s->value(Constants::SETTINGS_CUSTOM_ARGUMENTS,
options.customArguments).toString();
options.ignoredPatterns = s->value(Constants::SETTINGS_IGNORE_PATTERNS,
options.ignoredPatterns).toString();
options.warning = s->value(Constants::SETTINGS_WARNING,
options.warning).toBool();
options.style = s->value(Constants::SETTINGS_STYLE,
options.style).toBool();
options.performance = s->value(Constants::SETTINGS_PERFORMANCE,
options.performance).toBool();
options.portability = s->value(Constants::SETTINGS_PORTABILITY,
options.portability).toBool();
options.information = s->value(Constants::SETTINGS_INFORMATION,
options.information).toBool();
options.unusedFunction = s->value(Constants::SETTINGS_UNUSED_FUNCTION,
options.unusedFunction).toBool();
options.missingInclude = s->value(Constants::SETTINGS_MISSING_INCLUDE,
options.missingInclude).toBool();
options.inconclusive = s->value(Constants::SETTINGS_INCONCLUSIVE,
options.inconclusive).toBool();
options.forceDefines = s->value(Constants::SETTINGS_FORCE_DEFINES,
options.forceDefines).toBool();
options.showOutput = s->value(Constants::SETTINGS_SHOW_OUTPUT,
options.showOutput).toBool();
options.addIncludePaths = s->value(Constants::SETTINGS_ADD_INCLUDE_PATHS,
options.addIncludePaths).toBool();
options.guessArguments = s->value(Constants::SETTINGS_GUESS_ARGUMENTS,
options.guessArguments).toBool();
s->endGroup();
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,81 @@
/****************************************************************************
**
** 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
#include <coreplugin/dialogs/ioptionspage.h>
#include <QPointer>
namespace Cppcheck {
namespace Internal {
class CppcheckTool;
class CppcheckTrigger;
class OptionsWidget;
class CppcheckOptions final
{
public:
QString binary;
bool warning = true;
bool style = true;
bool performance = true;
bool portability = true;
bool information = true;
bool unusedFunction = false;
bool missingInclude = false;
bool inconclusive = false;
bool forceDefines = false;
QString customArguments;
QString ignoredPatterns;
bool showOutput = false;
bool addIncludePaths = false;
bool guessArguments = true;
};
class CppcheckOptionsPage final : public Core::IOptionsPage
{
Q_OBJECT
public:
explicit CppcheckOptionsPage(CppcheckTool &tool, CppcheckTrigger &trigger);
QWidget *widget() final;
void apply() final;
void finish() final;
private:
void save(const CppcheckOptions &options) const;
void load(CppcheckOptions &options) const;
CppcheckTool &m_tool;
CppcheckTrigger &m_trigger;
QPointer<OptionsWidget> m_widget;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,67 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "cppcheckoptions.h"
#include "cppcheckplugin.h"
#include "cppchecktextmarkmanager.h"
#include "cppchecktool.h"
#include "cppchecktrigger.h"
namespace Cppcheck {
namespace Internal {
class CppcheckPluginPrivate final
{
public:
explicit CppcheckPluginPrivate();
CppcheckTextMarkManager marks;
CppcheckTool tool;
CppcheckTrigger trigger;
CppcheckOptionsPage options;
};
CppcheckPluginPrivate::CppcheckPluginPrivate() :
tool(marks),
trigger(marks, tool),
options(tool, trigger)
{
}
CppcheckPlugin::CppcheckPlugin() = default;
CppcheckPlugin::~CppcheckPlugin() = default;
bool CppcheckPlugin::initialize(const QStringList &arguments, QString *errorString)
{
Q_UNUSED(arguments);
Q_UNUSED(errorString);
d.reset(new CppcheckPluginPrivate);
return true;
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,54 @@
/****************************************************************************
**
** 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
#include <extensionsystem/iplugin.h>
#include <memory>
namespace Cppcheck {
namespace Internal {
class CppcheckPluginPrivate;
class CppcheckPlugin final : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Cppcheck.json")
public:
CppcheckPlugin();
~CppcheckPlugin() override;
private:
bool initialize(const QStringList &arguments, QString *errorString) final;
void extensionsInitialized() final {}
std::unique_ptr<CppcheckPluginPrivate> d;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,216 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "cppcheckrunner.h"
#include "cppchecktool.h"
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <coreplugin/messagemanager.h>
namespace Cppcheck {
namespace Internal {
CppcheckRunner::CppcheckRunner(CppcheckTool &tool) :
m_tool(tool),
m_process(new Utils::QtcProcess(this))
{
if (Utils::HostOsInfo::hostOs() == Utils::OsTypeLinux) {
QProcess getConf;
getConf.start("getconf ARG_MAX");
getConf.waitForFinished(2000);
const auto argMax = getConf.readAllStandardOutput().replace("\n", "");
m_maxArgumentsLength = std::max(argMax.toInt(), m_maxArgumentsLength);
}
connect(m_process, &QProcess::readyReadStandardOutput,
this, &CppcheckRunner::readOutput);
connect(m_process, &QProcess::readyReadStandardOutput,
this, &CppcheckRunner::readError);
connect(m_process, &QProcess::started,
this, &CppcheckRunner::handleStarted);
connect(m_process, QOverload<int>::of(&QProcess::finished),
this, &CppcheckRunner::handleFinished);
m_queueTimer.setSingleShot(true);
const auto checkDelayInMs = 200;
m_queueTimer.setInterval(checkDelayInMs);
connect(&m_queueTimer, &QTimer::timeout,
this, &CppcheckRunner::checkQueued);
}
CppcheckRunner::~CppcheckRunner()
{
stop();
m_queueTimer.stop();
}
void CppcheckRunner::reconfigure(const QString &binary, const QString &arguments)
{
m_binary = binary;
m_arguments = arguments;
}
void CppcheckRunner::addToQueue(const Utils::FileNameList &files,
const QString &additionalArguments)
{
auto &existing = m_queue[additionalArguments];
if (existing.isEmpty()) {
existing = files;
} else {
std::copy_if(files.cbegin(), files.cend(), std::back_inserter(existing),
[&existing](const Utils::FileName &file) { return !existing.contains(file); });
}
if (m_isRunning) {
if (existing == m_currentFiles)
m_process->kill(); // Further processing in handleFinished
return;
}
m_queueTimer.start();
}
void CppcheckRunner::stop()
{
if (m_isRunning)
m_process->kill();
}
void CppcheckRunner::removeFromQueue(const Utils::FileNameList &files)
{
if (m_queue.isEmpty())
return;
if (files.isEmpty()) {
m_queue.clear();
} else {
for (auto it = m_queue.begin(), end = m_queue.end(); it != end;) {
for (const auto &file : files)
it.value().removeOne(file);
it = !it.value().isEmpty() ? ++it : m_queue.erase(it);
}
}
}
const Utils::FileNameList &CppcheckRunner::currentFiles() const
{
return m_currentFiles;
}
QString CppcheckRunner::currentCommand() const
{
return m_process->program() + ' ' +
m_process->arguments().join(' ');
}
void CppcheckRunner::checkQueued()
{
if (m_queue.isEmpty() || m_binary.isEmpty())
return;
auto files = m_queue.begin().value();
QString arguments = m_arguments + ' ' + m_queue.begin().key();
m_currentFiles.clear();
int argumentsLength = arguments.length();
while (!files.isEmpty()) {
argumentsLength += files.first().length() + 1; // +1 for separator
if (argumentsLength >= m_maxArgumentsLength)
break;
m_currentFiles.push_back(files.first());
arguments += ' ' + files.first().toString();
files.pop_front();
}
if (files.isEmpty())
m_queue.erase(m_queue.begin());
else
m_queue.begin().value() = files;
m_process->setCommand(m_binary, arguments);
m_process->start();
}
void CppcheckRunner::readOutput()
{
if (!m_isRunning) // workaround for QTBUG-30929
handleStarted();
m_process->setReadChannel(QProcess::StandardOutput);
while (!m_process->atEnd() && m_process->canReadLine()) {
auto line = QString::fromUtf8(m_process->readLine());
if (line.endsWith('\n'))
line.chop(1);
m_tool.parseOutputLine(line);
}
}
void CppcheckRunner::readError()
{
if (!m_isRunning) // workaround for QTBUG-30929
handleStarted();
m_process->setReadChannel(QProcess::StandardError);
while (!m_process->atEnd() && m_process->canReadLine()) {
auto line = QString::fromUtf8(m_process->readLine());
if (line.endsWith('\n'))
line.chop(1);
m_tool.parseErrorLine(line);
}
}
void CppcheckRunner::handleStarted()
{
if (m_isRunning)
return;
m_isRunning = true;
m_tool.startParsing();
}
void CppcheckRunner::handleFinished(int)
{
if (m_process->error() != QProcess::FailedToStart) {
readOutput();
readError();
m_tool.finishParsing();
} else {
const QString message = tr("Cppcheck failed to start: \"%1\".").arg(currentCommand());
Core::MessageManager::write(message, Core::MessageManager::Silent);
}
m_currentFiles.clear();
m_process->close();
m_isRunning = false;
if (!m_queue.isEmpty())
checkQueued();
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,78 @@
/****************************************************************************
**
** 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
#include <QHash>
#include <QTimer>
namespace Utils {
class QtcProcess;
class FileName;
using FileNameList = QList<FileName>;
}
namespace Cppcheck {
namespace Internal {
class CppcheckTool;
class CppcheckRunner final : public QObject
{
Q_OBJECT
public:
explicit CppcheckRunner(CppcheckTool &tool);
~CppcheckRunner() override;
void reconfigure(const QString &binary, const QString &arguments);
void addToQueue(const Utils::FileNameList &files,
const QString &additionalArguments = {});
void removeFromQueue(const Utils::FileNameList &files);
void stop();
const Utils::FileNameList &currentFiles() const;
QString currentCommand() const;
private:
void checkQueued();
void readOutput();
void readError();
void handleStarted();
void handleFinished(int);
CppcheckTool &m_tool;
Utils::QtcProcess *m_process = nullptr;
QString m_binary;
QString m_arguments;
QHash<QString, Utils::FileNameList> m_queue;
Utils::FileNameList m_currentFiles;
QTimer m_queueTimer;
int m_maxArgumentsLength = 32767;
bool m_isRunning = false;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,96 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "cppcheckconstants.h"
#include "cppcheckdiagnostic.h"
#include "cppchecktextmark.h"
#include <utils/utilsicons.h>
#include <QMap>
namespace Cppcheck {
namespace Internal {
struct Visual
{
Visual(Utils::Theme::Color color, TextEditor::TextMark::Priority priority,
const QIcon &icon)
: color(color),
priority(priority),
icon(icon)
{}
Utils::Theme::Color color;
TextEditor::TextMark::Priority priority;
QIcon icon;
};
static Visual getVisual(Diagnostic::Severity type)
{
using Color = Utils::Theme::Color;
using Priority = TextEditor::TextMark::Priority;
static const QMap<Diagnostic::Severity, Visual> visuals{
{Diagnostic::Severity::Error, {Color::IconsErrorColor, Priority::HighPriority,
Utils::Icons::CRITICAL.icon()}},
{Diagnostic::Severity::Warning, {Color::IconsWarningColor, Priority::NormalPriority,
Utils::Icons::WARNING.icon()}},
};
return visuals.value(type, {Color::IconsInfoColor, Priority::LowPriority,
Utils::Icons::INFO.icon()});
}
CppcheckTextMark::CppcheckTextMark (const Diagnostic &diagnostic)
: TextEditor::TextMark (diagnostic.fileName, diagnostic.lineNumber,
Core::Id(Constants::TEXTMARK_CATEGORY_ID)),
m_severity(diagnostic.severity),
m_checkId(diagnostic.checkId),
m_message(diagnostic.message)
{
const auto visual = getVisual(diagnostic.severity);
setPriority(visual.priority);
setColor(visual.color);
setIcon(visual.icon);
setToolTip(toolTipText(diagnostic.severityText));
setLineAnnotation(diagnostic.message);
}
QString CppcheckTextMark::toolTipText(const QString &severityText) const
{
return QString(
"<table cellspacing='0' cellpadding='0' width='100%'>"
" <tr>"
" <td align='left'><b>Cppcheck</b></td>"
" <td align='right'>&nbsp;<font color='gray'>%1: %2</font></td>"
" </tr>"
" <tr>"
" <td colspan='2' align='left' style='padding-left:10px'>%3</td>"
" </tr>"
"</table>").arg(m_checkId, severityText, m_message);
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,55 @@
/****************************************************************************
**
** 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
#include "cppcheckdiagnostic.h"
#include <texteditor/textmark.h>
namespace Cppcheck {
namespace Internal {
class CppcheckTextMark final : public TextEditor::TextMark
{
public:
explicit CppcheckTextMark(const Diagnostic &diagnostic);
bool operator==(const Diagnostic &r) const {
return lineNumber() == r.lineNumber
&& (std::tie(m_severity, m_checkId, m_message) ==
std::tie(r.severity, r.checkId, r.message));
}
private:
QString toolTipText(const QString &severityText) const;
Diagnostic::Severity m_severity = Diagnostic::Severity::Information;
QString m_checkId;
QString m_message;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,63 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "cppcheckdiagnostic.h"
#include "cppchecktextmark.h"
#include "cppchecktextmarkmanager.h"
#include <utils/algorithm.h>
namespace Cppcheck {
namespace Internal {
CppcheckTextMarkManager::CppcheckTextMarkManager() = default;
CppcheckTextMarkManager::~CppcheckTextMarkManager() = default;
void CppcheckTextMarkManager::add(const Diagnostic &diagnostic)
{
auto &fileMarks = m_marks[diagnostic.fileName];
const auto finder = [diagnostic] (const MarkPtr &mark) {return *mark == diagnostic;};
if (Utils::contains(fileMarks, finder))
return;
fileMarks.push_back(std::make_unique<CppcheckTextMark>(diagnostic));
}
void CppcheckTextMarkManager::clearFiles(const Utils::FileNameList &files)
{
if (m_marks.empty())
return;
if (!files.empty()) {
for (const auto &file: files)
m_marks.erase(file);
} else {
m_marks.clear();
}
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,53 @@
/****************************************************************************
**
** 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
#include <utils/fileutils.h>
#include <unordered_map>
namespace Cppcheck {
namespace Internal {
class Diagnostic;
class CppcheckTextMark;
class CppcheckTextMarkManager final
{
public:
explicit CppcheckTextMarkManager();
~CppcheckTextMarkManager();
void add(const Diagnostic &diagnostic);
void clearFiles(const Utils::FileNameList &files);
private:
using MarkPtr = std::unique_ptr<CppcheckTextMark>;
std::unordered_map<Utils::FileName, std::vector<MarkPtr>> m_marks;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,324 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "cppcheckconstants.h"
#include "cppcheckdiagnostic.h"
#include "cppcheckoptions.h"
#include "cppcheckrunner.h"
#include "cppchecktextmarkmanager.h"
#include "cppchecktool.h"
#include <coreplugin/messagemanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <cpptools/cppmodelmanager.h>
#include <utils/algorithm.h>
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <QThread>
namespace Cppcheck {
namespace Internal {
CppcheckTool::CppcheckTool(CppcheckTextMarkManager &marks) :
m_marks(marks),
m_progressRegexp("^.* checked (\\d)% done$"),
m_messageRegexp("^(.+),(\\d+),(\\w+),(\\w+),(.*)$")
{
m_runner = std::make_unique<CppcheckRunner>(*this);
QTC_ASSERT(m_progressRegexp.isValid(), return);
QTC_ASSERT(m_messageRegexp.isValid(), return);
}
CppcheckTool::~CppcheckTool() = default;
void CppcheckTool::updateOptions(const CppcheckOptions &options)
{
m_options = options;
m_filters.clear();
const auto patterns = m_options.ignoredPatterns.split(',');
for (const auto &pattern : patterns) {
const auto trimmedPattern = pattern.trimmed();
if (trimmedPattern.isEmpty())
continue;
const QRegExp re(trimmedPattern, Qt::CaseSensitive, QRegExp::Wildcard);
if (re.isValid())
m_filters.push_back(re);
}
updateArguments();
}
void CppcheckTool::setProject(ProjectExplorer::Project *project)
{
m_project = project;
updateArguments();
}
void CppcheckTool::updateArguments()
{
if (!m_project)
return;
m_cachedAdditionalArguments.clear();
QStringList arguments;
if (!m_options.customArguments.isEmpty()) {
auto expander = Utils::globalMacroExpander();
const auto expanded = expander->expand(m_options.customArguments);
arguments.push_back(expanded);
}
if (m_options.warning)
arguments.push_back("--enable=warning");
if (m_options.style)
arguments.push_back("--enable=style");
if (m_options.performance)
arguments.push_back("--enable=performance");
if (m_options.portability)
arguments.push_back("--enable=portability");
if (m_options.information)
arguments.push_back("--enable=information");
if (m_options.unusedFunction)
arguments.push_back("--enable=unusedFunction");
if (m_options.missingInclude)
arguments.push_back("--enable=missingInclude");
if (m_options.inconclusive)
arguments.push_back("--inconclusive");
if (m_options.forceDefines)
arguments.push_back("--force");
if (!m_options.unusedFunction && !m_options.customArguments.contains("-j "))
arguments.push_back("-j " + QString::number(QThread::idealThreadCount()));
arguments.push_back("--template={file},{line},{severity},{id},{message}");
m_runner->reconfigure(m_options.binary, arguments.join(' '));
}
QStringList CppcheckTool::additionalArguments(const CppTools::ProjectPart &part) const
{
QStringList result;
if (m_options.addIncludePaths) {
for (const auto &path : qAsConst(part.headerPaths)) {
const auto projectDir = m_project->projectDirectory().toString();
if (path.type == ProjectExplorer::HeaderPathType::User
&& path.path.startsWith(projectDir))
result.push_back("-I " + path.path);
}
}
if (!m_options.guessArguments)
return result;
using Version = CppTools::ProjectPart::LanguageVersion;
switch (part.languageVersion) {
case Version::C89:
result.push_back("--std=c89 --language=c");
break;
case Version::C99:
result.push_back("--std=c99 --language=c");
break;
case Version::C11:
result.push_back("--std=c11 --language=c");
break;
case Version::CXX03:
result.push_back("--std=c++03 --language=c++");
break;
case Version::CXX11:
result.push_back("--std=c++11 --language=c++");
break;
case Version::CXX14:
result.push_back("--std=c++14 --language=c++");
break;
case Version::CXX98:
case Version::CXX17:
result.push_back("--language=c++");
break;
}
using QtVersion = CppTools::ProjectPart::QtVersion;
if (part.qtVersion != QtVersion::NoQt)
result.push_back("--library=qt");
return result;
}
const CppcheckOptions &CppcheckTool::options() const
{
return m_options;
}
void CppcheckTool::check(const Utils::FileNameList &files)
{
QTC_ASSERT(m_project, return);
Utils::FileNameList filtered;
if (m_filters.isEmpty()) {
filtered = files;
} else {
std::copy_if(files.cbegin(), files.cend(), std::back_inserter(filtered),
[this](const Utils::FileName &file) {
const auto stringed = file.toString();
const auto filter = [stringed](const QRegExp &re) {return re.exactMatch(stringed);};
return !Utils::contains(m_filters, filter);
});
}
if (filtered.isEmpty())
return;
const auto info = CppTools::CppModelManager::instance()->projectInfo(m_project);
const auto parts = info.projectParts();
if (parts.size() == 1) {
QTC_ASSERT(parts.first(), return);
addToQueue(filtered, *parts.first());
return;
}
std::map<CppTools::ProjectPart::Ptr, Utils::FileNameList> groups;
for (const auto &file : qAsConst(filtered)) {
const auto stringed = file.toString();
for (const auto &part : parts) {
QTC_ASSERT(part, continue);
const auto &partFiles = part->files;
using File = CppTools::ProjectFile;
const auto match = [stringed](const File &file){return file.path == stringed;};
if (Utils::contains(partFiles, match))
groups[part].push_back(file);
}
}
for (const auto &group : groups)
addToQueue(group.second, *group.first);
}
void CppcheckTool::addToQueue(const Utils::FileNameList &files, CppTools::ProjectPart &part)
{
const auto key = part.id();
if (!m_cachedAdditionalArguments.contains(key))
m_cachedAdditionalArguments.insert(key, additionalArguments(part).join(' '));
m_runner->addToQueue(files, m_cachedAdditionalArguments[key]);
}
void CppcheckTool::stop(const Utils::FileNameList &files)
{
m_runner->removeFromQueue(files);
m_runner->stop();
}
void CppcheckTool::startParsing()
{
if (m_options.showOutput) {
const auto message = tr("Cppcheck started: \"%1\".").arg(m_runner->currentCommand());
Core::MessageManager::write(message, Core::MessageManager::Silent);
}
m_progress = std::make_unique<QFutureInterface<void>>();
const auto progress = Core::ProgressManager::addTask(
m_progress->future(), QObject::tr("Cppcheck"),
Constants::CHECK_PROGRESS_ID);
QObject::connect(progress, &Core::FutureProgress::canceled,
this, [this]{stop({});});
m_progress->setProgressRange(0, 100);
m_progress->reportStarted();
}
void CppcheckTool::parseOutputLine(const QString &line)
{
if (line.isEmpty())
return;
if (m_options.showOutput)
Core::MessageManager::write(line, Core::MessageManager::Silent);
enum Matches { Percentage = 1 };
const auto match = m_progressRegexp.match(line);
if (!match.hasMatch())
return;
const auto done = match.captured(Percentage).toInt();
QTC_ASSERT(m_progress, return);
m_progress->setProgressValue(done);
}
static Diagnostic::Severity toSeverity(const QString &text)
{
static const QMap<QString, Diagnostic::Severity> values{
{"error", Diagnostic::Severity::Error},
{"warning", Diagnostic::Severity::Warning},
{"performance", Diagnostic::Severity::Performance},
{"portability", Diagnostic::Severity::Portability},
{"style", Diagnostic::Severity::Style},
{"information", Diagnostic::Severity::Information}
};
return values.value(text, Diagnostic::Severity::Information);
}
void CppcheckTool::parseErrorLine(const QString &line)
{
if (line.isEmpty())
return;
if (m_options.showOutput)
Core::MessageManager::write(line, Core::MessageManager::Silent);
enum Matches { File = 1, Line, Severity, Id, Message };
const auto match = m_messageRegexp.match(line);
if (!match.hasMatch())
return;
const auto fileName = Utils::FileName::fromString(
QDir::fromNativeSeparators(match.captured(File)));
if (!m_runner->currentFiles().contains(fileName))
return;
Diagnostic diagnostic;
diagnostic.fileName = fileName;
diagnostic.lineNumber = std::max(match.captured(Line).toInt(), 1);
diagnostic.severityText = match.captured(Severity);
diagnostic.severity = toSeverity(diagnostic.severityText);
diagnostic.checkId = match.captured(Id);
diagnostic.message = match.captured(Message);
if (diagnostic.isValid())
m_marks.add(diagnostic);
}
void CppcheckTool::finishParsing()
{
if (m_options.showOutput)
Core::MessageManager::write(tr("Cppcheck finished."), Core::MessageManager::Silent);
QTC_ASSERT(m_progress, return);
m_progress->reportFinished();
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,94 @@
/****************************************************************************
**
** 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
#include <cppcheck/cppcheckoptions.h>
#include <QFuture>
#include <QPointer>
#include <QRegularExpression>
#include <memory>
namespace Utils {
class FileName;
using FileNameList = QList<FileName>;
}
namespace CppTools {
class ProjectPart;
}
namespace ProjectExplorer {
class Project;
}
namespace Cppcheck {
namespace Internal {
class Diagnostic;
class CppcheckRunner;
class CppcheckTextMarkManager;
class CppcheckOptions;
class CppcheckTool final : public QObject
{
Q_OBJECT
public:
explicit CppcheckTool(CppcheckTextMarkManager &marks);
~CppcheckTool() override;
void updateOptions(const CppcheckOptions &options);
void setProject(ProjectExplorer::Project *project);
void check(const Utils::FileNameList &files);
void stop(const Utils::FileNameList &files);
void startParsing();
void parseOutputLine(const QString &line);
void parseErrorLine(const QString &line);
void finishParsing();
const CppcheckOptions &options() const;
private:
void updateArguments();
void addToQueue(const Utils::FileNameList &files, CppTools::ProjectPart &part);
QStringList additionalArguments(const CppTools::ProjectPart &part) const;
CppcheckTextMarkManager &m_marks;
CppcheckOptions m_options;
QPointer<ProjectExplorer::Project> m_project;
std::unique_ptr<CppcheckRunner> m_runner;
std::unique_ptr<QFutureInterface<void>> m_progress;
QHash<QString, QString> m_cachedAdditionalArguments;
QVector<QRegExp> m_filters;
QRegularExpression m_progressRegexp;
QRegularExpression m_messageRegexp;
};
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,198 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
#include "cppchecktextmarkmanager.h"
#include "cppchecktool.h"
#include "cppchecktrigger.h"
#include <cpptools/cppmodelmanager.h>
#include <utils/qtcassert.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
namespace Cppcheck {
namespace Internal {
CppcheckTrigger::CppcheckTrigger(CppcheckTextMarkManager &marks, CppcheckTool &tool) :
m_marks(marks),
m_tool(tool)
{
using EditorManager = Core::EditorManager;
using SessionManager = ProjectExplorer::SessionManager;
using CppModelManager = CppTools::CppModelManager;
connect(EditorManager::instance(), &EditorManager::editorOpened,
this, [this](Core::IEditor *editor) {checkEditors({editor});});
connect(EditorManager::instance(), &EditorManager::editorsClosed,
this, &CppcheckTrigger::removeEditors);
connect(EditorManager::instance(), &EditorManager::aboutToSave,
this, &CppcheckTrigger::checkChangedDocument);
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
this, &CppcheckTrigger::changeCurrentProject);
connect(CppModelManager::instance(), &CppModelManager::projectPartsUpdated,
this, &CppcheckTrigger::updateProjectFiles);
}
CppcheckTrigger::~CppcheckTrigger() = default;
void CppcheckTrigger::recheck()
{
removeEditors();
checkEditors();
}
void CppcheckTrigger::checkEditors(const QList<Core::IEditor *> &editors)
{
if (!m_currentProject)
return;
using CppModelManager = CppTools::CppModelManager;
const auto info = CppModelManager::instance()->projectInfo(m_currentProject);
if (!info.isValid())
return;
const auto editorList = !editors.isEmpty()
? editors : Core::DocumentModel::editorsForOpenedDocuments();
Utils::FileNameList toCheck;
for (const auto editor: editorList) {
QTC_ASSERT(editor, continue);
const auto document = editor->document();
QTC_ASSERT(document, continue);
const auto &path = document->filePath();
QTC_ASSERT(!path.isEmpty(), continue);
if (m_checkedFiles.contains(path))
continue;
if (!m_currentProject->isKnownFile(path))
continue;
const auto &pathString = path.toString();
if (!info.sourceFiles().contains(pathString))
continue;
connect(document, &Core::IDocument::aboutToReload,
this, [this, document]{checkChangedDocument(document);});
connect(document, &Core::IDocument::contentsChanged,
this, [this, document] {
if (!document->isModified())
checkChangedDocument(document);
});
m_checkedFiles.insert(path, QDateTime::currentDateTime());
toCheck.push_back(path);
}
if (!toCheck.isEmpty()) {
remove(toCheck);
check(toCheck);
}
}
void CppcheckTrigger::removeEditors(const QList<Core::IEditor *> &editors)
{
if (!m_currentProject)
return;
const auto editorList = !editors.isEmpty()
? editors : Core::DocumentModel::editorsForOpenedDocuments();
Utils::FileNameList toRemove;
for (const auto editor: editorList) {
QTC_ASSERT(editor, return);
const auto document = editor->document();
QTC_ASSERT(document, return);
const auto &path = document->filePath();
QTC_ASSERT(!path.isEmpty(), return);
if (!m_checkedFiles.contains(path))
continue;
disconnect(document, nullptr, this, nullptr);
m_checkedFiles.remove(path);
toRemove.push_back(path);
}
if (!toRemove.isEmpty())
remove(toRemove);
}
void CppcheckTrigger::checkChangedDocument(Core::IDocument *document)
{
QTC_ASSERT(document, return);
if (!m_currentProject)
return;
const auto &path = document->filePath();
QTC_ASSERT(!path.isEmpty(), return);
if (!m_checkedFiles.contains(path))
return;
remove({path});
check({path});
}
void CppcheckTrigger::changeCurrentProject(ProjectExplorer::Project *project)
{
m_currentProject = project;
m_checkedFiles.clear();
remove({});
m_tool.setProject(project);
checkEditors(Core::DocumentModel::editorsForOpenedDocuments());
}
void CppcheckTrigger::updateProjectFiles(ProjectExplorer::Project *project)
{
if (project != m_currentProject)
return;
m_checkedFiles.clear();
remove({});
m_tool.setProject(project);
checkEditors(Core::DocumentModel::editorsForOpenedDocuments());
}
void CppcheckTrigger::check(const Utils::FileNameList &files)
{
m_tool.check(files);
}
void CppcheckTrigger::remove(const Utils::FileNameList &files)
{
m_marks.clearFiles(files);
m_tool.stop(files);
}
} // namespace Internal
} // namespace Cppcheck

View File

@@ -0,0 +1,81 @@
/****************************************************************************
**
** 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
#include <QHash>
#include <QPointer>
namespace Utils {
class FileName;
using FileNameList = QList<FileName>;
}
namespace ProjectExplorer {
class Project;
}
namespace Core {
class IDocument;
class IEditor;
}
namespace CppTools {
class ProjectInfo;
}
namespace Cppcheck {
namespace Internal {
class CppcheckTextMarkManager;
class CppcheckTool;
class CppcheckTrigger final : public QObject
{
Q_OBJECT
public:
explicit CppcheckTrigger(CppcheckTextMarkManager &marks, CppcheckTool &tool);
~CppcheckTrigger() override;
void recheck();
private:
void checkEditors(const QList<Core::IEditor *> &editors = {});
void removeEditors(const QList<Core::IEditor *> &editors = {});
void checkChangedDocument(Core::IDocument *document);
void changeCurrentProject(ProjectExplorer::Project *project);
void updateProjectFiles(ProjectExplorer::Project *project);
void check(const Utils::FileNameList &files);
void remove(const Utils::FileNameList &files);
CppcheckTextMarkManager &m_marks;
CppcheckTool &m_tool;
QPointer<ProjectExplorer::Project> m_currentProject;
QHash<Utils::FileName, QDateTime> m_checkedFiles;
};
} // namespace Internal
} // namespace Cppcheck