diff --git a/Makefile b/Makefile
index 8cc4ead63c8..d1aa9cc093c 100644
--- a/Makefile
+++ b/Makefile
@@ -200,6 +200,7 @@ LIBOBJ = $(libcppdir)/analyzerinfo.o \
$(libcppdir)/checkbufferoverrun.o \
$(libcppdir)/checkclass.o \
$(libcppdir)/checkcondition.o \
+ $(libcppdir)/checkersreport.o \
$(libcppdir)/checkexceptionsafety.o \
$(libcppdir)/checkfunctions.o \
$(libcppdir)/checkinternal.o \
@@ -488,6 +489,9 @@ $(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/
$(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/astutils.h lib/check.h lib/checkcondition.h lib/checkother.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkcondition.cpp
+$(libcppdir)/checkersreport.o: lib/checkersreport.cpp lib/checkers.h lib/checkersreport.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h
+ $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersreport.cpp
+
$(libcppdir)/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/check.h lib/checkexceptionsafety.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkexceptionsafety.cpp
@@ -638,7 +642,7 @@ $(libcppdir)/vfvalue.o: lib/vfvalue.cpp lib/config.h lib/errortypes.h lib/mathli
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cmdlineparser.cpp
-cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h cli/cppcheckexecutorsig.h cli/executor.h cli/filelister.h cli/processexecutor.h cli/singleexecutor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h
+cli/cppcheckexecutor.o: cli/cppcheckexecutor.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h cli/cppcheckexecutorsig.h cli/executor.h cli/filelister.h cli/processexecutor.h cli/singleexecutor.h cli/threadexecutor.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/checkersreport.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h
$(CXX) ${INCLUDE_FOR_CLI} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ cli/cppcheckexecutor.cpp
cli/cppcheckexecutorseh.o: cli/cppcheckexecutorseh.cpp cli/cppcheckexecutor.h cli/cppcheckexecutorseh.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/utils.h
diff --git a/cli/cli.vcxproj.filters b/cli/cli.vcxproj.filters
index e8385a6c84d..2b107b060f4 100644
--- a/cli/cli.vcxproj.filters
+++ b/cli/cli.vcxproj.filters
@@ -14,9 +14,6 @@
-
- Header Files
-
Header Files
@@ -44,6 +41,9 @@
Header Files
+
+ Header Files
+
@@ -76,6 +76,9 @@
Source Files
+
+ Source Files
+
diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp
index 041c051dc76..f906ca96c3b 100644
--- a/cli/cppcheckexecutor.cpp
+++ b/cli/cppcheckexecutor.cpp
@@ -20,6 +20,7 @@
#include "analyzerinfo.h"
#include "checkers.h"
+#include "checkersreport.h"
#include "cmdlineparser.h"
#include "color.h"
#include "config.h"
@@ -337,60 +338,13 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck)
return 0;
}
-static bool isCppcheckPremium(const Settings& settings) {
- return (settings.cppcheckCfgProductName.compare(0, 16, "Cppcheck Premium") == 0);
-}
-
-static std::string getMisraRuleSeverity(const std::string& rule) {
- if (checkers::misraRuleSeverity.count(rule) > 0)
- return checkers::misraRuleSeverity.at(rule);
- return "style";
-}
-
-static bool isMisraRuleInconclusive(const std::string& rule) {
- return rule == "8.3";
-}
-
-static bool isMisraRuleActive(const std::string& rule, int amendment, const std::string& severity, const Settings& settings) {
- if (!isCppcheckPremium(settings) && amendment >= 3)
- return false;
- const bool inconclusive = isMisraRuleInconclusive(rule);
- if (inconclusive && !settings.certainty.isEnabled(Certainty::inconclusive))
- return false;
- if (severity == "warning")
- return settings.severity.isEnabled(Severity::warning);
- if (severity == "style")
- return settings.severity.isEnabled(Severity::style);
- return true; // error severity
-}
-
void CppCheckExecutor::writeCheckersReport(const Settings& settings) const
{
+ CheckersReport checkersReport(settings, mActiveCheckers);
+
if (!settings.quiet) {
- int activeCheckers = 0;
- int totalCheckers = 0;
- for (const auto& checkReq: checkers::allCheckers) {
- if (mActiveCheckers.count(checkReq.first) > 0)
- ++activeCheckers;
- ++totalCheckers;
- }
- if (isCppcheckPremium(settings)) {
- for (const auto& checkReq: checkers::premiumCheckers) {
- if (mActiveCheckers.count(checkReq.first) > 0)
- ++activeCheckers;
- ++totalCheckers;
- }
- }
- if (mSettings->premiumArgs.find("misra-c-") != std::string::npos || mSettings->addons.count("misra")) {
- for (const checkers::MisraInfo& info: checkers::misraC2012Rules) {
- const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b);
- const std::string severity = getMisraRuleSeverity(rule);
- const bool active = isMisraRuleActive(rule, info.amendment, severity, settings);
- if (active)
- ++activeCheckers;
- ++totalCheckers;
- }
- }
+ const int activeCheckers = checkersReport.getActiveCheckersCount();
+ const int totalCheckers = checkersReport.getAllCheckersCount();
const std::string extra = settings.verbose ? " (use --checkers-report= to see details)" : "";
if (mCriticalErrors.empty())
@@ -403,111 +357,9 @@ void CppCheckExecutor::writeCheckersReport(const Settings& settings) const
return;
std::ofstream fout(settings.checkersReportFilename);
- if (!fout.is_open())
- return;
+ if (fout.is_open())
+ fout << checkersReport.getReport(mCriticalErrors);
- fout << "Critical errors" << std::endl;
- fout << "---------------" << std::endl;
- if (!mCriticalErrors.empty()) {
- fout << "There was critical errors (" << mCriticalErrors << ")" << std::endl;
- fout << "All checking is skipped for a file with such error" << std::endl;
- } else {
- fout << "No critical errors, all files were checked." << std::endl;
- fout << "Important: Analysis is still not guaranteed to be 'complete' it is possible there are false negatives." << std::endl;
- }
-
- fout << std::endl << std::endl;
- fout << "Open source checkers" << std::endl;
- fout << "--------------------" << std::endl;
-
- int maxCheckerSize = 0;
- for (const auto& checkReq: checkers::allCheckers) {
- const std::string& checker = checkReq.first;
- if (checker.size() > maxCheckerSize)
- maxCheckerSize = checker.size();
- }
- for (const auto& checkReq: checkers::allCheckers) {
- const std::string& checker = checkReq.first;
- const bool active = mActiveCheckers.count(checkReq.first) > 0;
- const std::string& req = checkReq.second;
- fout << (active ? "Yes " : "No ") << checker;
- if (!active && !req.empty())
- fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << "require:" + req;
- fout << std::endl;
- }
-
- const bool cppcheckPremium = isCppcheckPremium(settings);
-
- if (cppcheckPremium) {
- fout << std::endl << std::endl;
- fout << "Premium checkers" << std::endl;
- fout << "----------------" << std::endl;
-
- maxCheckerSize = 0;
- for (const auto& checkReq: checkers::premiumCheckers) {
- const std::string& checker = checkReq.first;
- if (checker.size() > maxCheckerSize)
- maxCheckerSize = checker.size();
- }
- for (const auto& checkReq: checkers::premiumCheckers) {
- const std::string& checker = checkReq.first;
- std::string req = checkReq.second;
- bool active = cppcheckPremium;
- if (req == "warning")
- active &= mSettings->severity.isEnabled(Severity::warning);
- else if (req == "style")
- active &= mSettings->severity.isEnabled(Severity::style);
- fout << (active ? "Yes " : "No ") << checker;
- if (!req.empty())
- req = "premium," + req;
- else
- req = "premium";
- if (!active)
- fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << "require:" + req;
- fout << std::endl;
- }
- }
-
- int misra = 0;
- if (mSettings->premiumArgs.find("misra-c-2012") != std::string::npos)
- misra = 2012;
- else if (mSettings->premiumArgs.find("misra-c-2023") != std::string::npos)
- misra = 2023;
- else if (mSettings->addons.count("misra"))
- misra = 2012;
-
- if (misra == 0) {
- fout << std::endl << std::endl;
- fout << "Misra C" << std::endl;
- fout << "-------" << std::endl;
- fout << "Misra is not enabled" << std::endl;
- } else {
- fout << std::endl << std::endl;
- fout << "Misra C " << misra << std::endl;
- fout << "------------" << std::endl;
- for (const checkers::MisraInfo& info: checkers::misraC2012Rules) {
- const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b);
- const std::string severity = getMisraRuleSeverity(rule);
- const bool active = isMisraRuleActive(rule, info.amendment, severity, settings);
- const bool inconclusive = isMisraRuleInconclusive(rule);
- fout << (active ? "Yes " : "No ") << rule;
- std::string extra;
- if (misra == 2012 && info.amendment >= 1)
- extra = " amendment:" + std::to_string(info.amendment);
- std::string reqs;
- if (info.amendment >= 3)
- reqs += ",premium";
- if (severity != "error")
- reqs += "," + severity;
- if (inconclusive)
- reqs += ",inconclusive";
- if (!active && !reqs.empty())
- extra += " require:" + reqs.substr(1);
- if (!extra.empty())
- fout << std::string(7 - rule.size(), ' ') << extra;
- fout << '\n';
- }
- }
}
bool CppCheckExecutor::loadLibraries(Settings& settings)
@@ -607,7 +459,7 @@ void CppCheckExecutor::reportErr(const ErrorMessage &msg)
{
assert(mSettings != nullptr);
- if (msg.severity == Severity::none && msg.id == "logChecker") {
+ if (msg.severity == Severity::none && (msg.id == "logChecker" || endsWith(msg.id, "-logChecker"))) {
const std::string& checker = msg.shortMessage();
mActiveCheckers.emplace(checker);
return;
diff --git a/gui/checkstatistics.cpp b/gui/checkstatistics.cpp
index a8f75c9a8f1..4f812b8ee43 100644
--- a/gui/checkstatistics.cpp
+++ b/gui/checkstatistics.cpp
@@ -65,6 +65,11 @@ void CheckStatistics::addItem(const QString &tool, ShowTypes::ShowType type)
}
}
+void CheckStatistics::addChecker(const QString &checker)
+{
+ mActiveCheckers.insert(checker.toStdString());
+}
+
void CheckStatistics::clear()
{
mStyle.clear();
@@ -73,6 +78,8 @@ void CheckStatistics::clear()
mPortability.clear();
mInformation.clear();
mError.clear();
+ mActiveCheckers.clear();
+ mCheckersReport.clear();
}
unsigned CheckStatistics::getCount(const QString &tool, ShowTypes::ShowType type) const
diff --git a/gui/checkstatistics.h b/gui/checkstatistics.h
index f487c39c854..d53be128834 100644
--- a/gui/checkstatistics.h
+++ b/gui/checkstatistics.h
@@ -23,9 +23,13 @@
#include
#include
+#include
#include
#include
+#include
+#include
+
/// @addtogroup GUI
/// @{
@@ -44,6 +48,11 @@ class CheckStatistics : public QObject {
*/
void addItem(const QString &tool, ShowTypes::ShowType type);
+ /**
+ * @brief Add checker to statistics
+ */
+ void addChecker(const QString& checker);
+
/**
* @brief Clear the statistics.
*
@@ -59,9 +68,24 @@ class CheckStatistics : public QObject {
*/
unsigned getCount(const QString &tool, ShowTypes::ShowType type) const;
+ std::set getActiveCheckers() const {
+ return mActiveCheckers;
+ }
+
+ int getNumberOfActiveCheckers() const {
+ return mActiveCheckers.size();
+ }
+
/** Get tools with results */
QStringList getTools() const;
+ void setCheckersReport(QString report) {
+ mCheckersReport = std::move(report);
+ }
+ QString getCheckersReport() const {
+ return mCheckersReport;
+ }
+
private:
QMap mStyle;
QMap mWarning;
@@ -69,6 +93,8 @@ class CheckStatistics : public QObject {
QMap mPortability;
QMap mInformation;
QMap mError;
+ std::set mActiveCheckers;
+ QString mCheckersReport;
};
/// @}
diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp
index 5f28d8b98cf..fb3a3081f49 100644
--- a/gui/mainwindow.cpp
+++ b/gui/mainwindow.cpp
@@ -540,6 +540,7 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons
}
mThread->setProject(p);
mThread->check(checkSettings);
+ mUI->mResults->setCheckSettings(checkSettings);
}
void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrary, const bool checkConfiguration)
@@ -603,6 +604,7 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar
mThread->setCheckFiles(true);
mThread->check(checkSettings);
+ mUI->mResults->setCheckSettings(checkSettings);
}
void MainWindow::analyzeCode(const QString& code, const QString& filename)
@@ -1208,7 +1210,9 @@ void MainWindow::reAnalyzeSelected(const QStringList& files)
// considered in "Modified Files Check" performed after "Selected Files Check"
// TODO: Should we store per file CheckStartTime?
QDateTime saveCheckStartTime = mThread->getCheckStartTime();
- mThread->check(getCppcheckSettings());
+ const Settings& checkSettings = getCppcheckSettings();
+ mThread->check(checkSettings);
+ mUI->mResults->setCheckSettings(checkSettings);
mThread->setCheckStartTime(saveCheckStartTime);
}
@@ -1232,7 +1236,9 @@ void MainWindow::reAnalyze(bool all)
qDebug() << "Rechecking project file" << mProjectFile->getFilename();
mThread->setCheckFiles(all);
- mThread->check(getCppcheckSettings());
+ const Settings& checkSettings = getCppcheckSettings();
+ mThread->check(checkSettings);
+ mUI->mResults->setCheckSettings(checkSettings);
}
void MainWindow::clearResults()
diff --git a/gui/mainwindow.h b/gui/mainwindow.h
index 78782b22bdd..969e1c28e9d 100644
--- a/gui/mainwindow.h
+++ b/gui/mainwindow.h
@@ -193,7 +193,7 @@ public slots:
/** @brief Slot for showing the library editor */
void showLibraryEditor();
-protected slots:
+private slots:
/** @brief Slot for checkthread's done signal */
void analysisDone();
diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp
index e1cea88330b..891d80a4973 100644
--- a/gui/resultsview.cpp
+++ b/gui/resultsview.cpp
@@ -19,6 +19,7 @@
#include "resultsview.h"
#include "checkstatistics.h"
+#include "checkersreport.h"
#include "codeeditor.h"
#include "codeeditorstyle.h"
#include "common.h"
@@ -105,6 +106,7 @@ void ResultsView::initialize(QSettings *settings, ApplicationList *list, ThreadH
ResultsView::~ResultsView()
{
delete mUI;
+ delete mCheckSettings;
}
void ResultsView::clear(bool results)
@@ -116,6 +118,8 @@ void ResultsView::clear(bool results)
mUI->mDetails->setText(QString());
mStatistics->clear();
+ delete mCheckSettings;
+ mCheckSettings = nullptr;
//Clear the progressbar
mUI->mProgress->setMaximum(PROGRESS_MAX);
@@ -150,6 +154,11 @@ void ResultsView::progress(int value, const QString& description)
void ResultsView::error(const ErrorItem &item)
{
+ if (item.severity == Severity::none && (item.errorId == "logChecker" || item.errorId.endsWith("-logChecker"))) {
+ mStatistics->addChecker(item.message);
+ return;
+ }
+
handleCriticalError(item);
if (mUI->mTree->addErrorItem(item)) {
@@ -282,6 +291,13 @@ QString ResultsView::getCheckDirectory()
return mUI->mTree->getCheckDirectory();
}
+void ResultsView::setCheckSettings(const Settings &settings)
+{
+ delete mCheckSettings;
+ mCheckSettings = new Settings;
+ *mCheckSettings = settings;
+}
+
void ResultsView::checkingStarted(int count)
{
mSuccess = true;
@@ -296,6 +312,13 @@ void ResultsView::checkingFinished()
mUI->mProgress->setVisible(false);
mUI->mProgress->setFormat("%p%");
+ {
+ Settings checkSettings;
+ const std::set activeCheckers = mStatistics->getActiveCheckers();
+ CheckersReport checkersReport(mCheckSettings ? *mCheckSettings : checkSettings, activeCheckers);
+ mStatistics->setCheckersReport(QString::fromStdString(checkersReport.getReport(mCriticalErrors.toStdString())));
+ }
+
// TODO: Items can be mysteriously hidden when checking is finished, this function
// call should be redundant but it "unhides" the wrongly hidden items.
mUI->mTree->refreshTree();
@@ -528,6 +551,11 @@ void ResultsView::stopAnalysis()
void ResultsView::handleCriticalError(const ErrorItem &item)
{
if (ErrorLogger::isCriticalErrorId(item.errorId.toStdString())) {
+ if (!mCriticalErrors.contains(item.errorId)) {
+ if (!mCriticalErrors.isEmpty())
+ mCriticalErrors += ",";
+ mCriticalErrors += item.errorId;
+ }
QString msg = tr("There was a critical error with id '%1'").arg(item.errorId);
if (!item.file0.isEmpty())
msg += ", " + tr("when checking %1").arg(item.file0);
diff --git a/gui/resultsview.h b/gui/resultsview.h
index 70c8ddfa2b9..d978afab936 100644
--- a/gui/resultsview.h
+++ b/gui/resultsview.h
@@ -29,6 +29,7 @@
#include
class ErrorItem;
+class Settings;
class ApplicationList;
class ThreadHandler;
class QModelIndex;
@@ -136,6 +137,11 @@ class ResultsView : public QWidget {
QString getCheckDirectory();
+ /**
+ * Set settings used in checking
+ */
+ void setCheckSettings(const Settings& settings);
+
/**
* @brief Inform the view that checking has started
*
@@ -368,11 +374,16 @@ public slots:
CheckStatistics *mStatistics;
+ Settings* mCheckSettings = nullptr;
+
/**
* Set to true when checking finish successfully. Set to false whenever analysis starts.
*/
bool mSuccess = false;
+ /** Critical error ids */
+ QString mCriticalErrors;
+
private slots:
/**
* @brief Custom context menu for Analysis Log
diff --git a/gui/statsdialog.cpp b/gui/statsdialog.cpp
index 4f5ce9a85bf..5dfd8a589e0 100644
--- a/gui/statsdialog.cpp
+++ b/gui/statsdialog.cpp
@@ -75,6 +75,10 @@ StatsDialog::StatsDialog(QWidget *parent)
{
mUI->setupUi(this);
+ QFont font("courier");
+ font.setStyleHint(QFont::Monospace);
+ mUI->mCheckersReport->setFont(font);
+
setWindowFlags(Qt::Window);
connect(mUI->mCopyToClipboard, &QPushButton::pressed, this, &StatsDialog::copyToClipboard);
@@ -366,12 +370,14 @@ void StatsDialog::copyToClipboard()
void StatsDialog::setStatistics(const CheckStatistics *stats)
{
mStatistics = stats;
- mUI->mLblErrors->setText(QString("%1").arg(stats->getCount(CPPCHECK,ShowTypes::ShowErrors)));
- mUI->mLblWarnings->setText(QString("%1").arg(stats->getCount(CPPCHECK,ShowTypes::ShowWarnings)));
- mUI->mLblStyle->setText(QString("%1").arg(stats->getCount(CPPCHECK,ShowTypes::ShowStyle)));
- mUI->mLblPortability->setText(QString("%1").arg(stats->getCount(CPPCHECK,ShowTypes::ShowPortability)));
- mUI->mLblPerformance->setText(QString("%1").arg(stats->getCount(CPPCHECK,ShowTypes::ShowPerformance)));
- mUI->mLblInformation->setText(QString("%1").arg(stats->getCount(CPPCHECK,ShowTypes::ShowInformation)));
+ mUI->mLblErrors->setText(QString::number(stats->getCount(CPPCHECK,ShowTypes::ShowErrors)));
+ mUI->mLblWarnings->setText(QString::number(stats->getCount(CPPCHECK,ShowTypes::ShowWarnings)));
+ mUI->mLblStyle->setText(QString::number(stats->getCount(CPPCHECK,ShowTypes::ShowStyle)));
+ mUI->mLblPortability->setText(QString::number(stats->getCount(CPPCHECK,ShowTypes::ShowPortability)));
+ mUI->mLblPerformance->setText(QString::number(stats->getCount(CPPCHECK,ShowTypes::ShowPerformance)));
+ mUI->mLblInformation->setText(QString::number(stats->getCount(CPPCHECK,ShowTypes::ShowInformation)));
+ mUI->mLblActiveCheckers->setText(QString::number(stats->getNumberOfActiveCheckers()));
+ mUI->mCheckersReport->setPlainText(stats->getCheckersReport());
}
#ifdef QT_CHARTS_LIB
diff --git a/gui/statsdialog.ui b/gui/statsdialog.ui
index 8147b8e7ec6..a749c51e676 100644
--- a/gui/statsdialog.ui
+++ b/gui/statsdialog.ui
@@ -6,8 +6,8 @@
0
0
- 502
- 274
+ 500
+ 414
@@ -247,114 +247,150 @@
Statistics
-
+
-
-
-
-
-
-
- Errors:
-
-
-
- -
-
-
- TextLabel
-
-
-
-
+
+
+ Errors:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ TextLabel
+
+
-
-
-
-
-
-
- Warnings:
-
-
-
- -
-
-
- TextLabel
-
-
-
-
+
+
+ Warnings:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ TextLabel
+
+
-
-
-
-
-
-
- Stylistic warnings:
-
-
-
- -
-
-
- TextLabel
-
-
-
-
+
+
+ Stylistic warnings:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ TextLabel
+
+
-
-
-
-
-
-
- Portability warnings:
-
-
-
- -
-
-
- TextLabel
-
-
-
-
+
+
+ Portability warnings:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ TextLabel
+
+
-
-
-
-
-
-
- Performance issues:
-
-
-
- -
-
-
- TextLabel
-
-
-
-
+
+
+ Performance issues:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ TextLabel
+
+
-
-
-
-
-
-
- Information messages:
-
-
-
- -
-
-
- TextLabel
-
-
-
-
+
+
+ Information messages:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ TextLabel
+
+
+
+ -
+
+
+ Active checkers:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ TextLabel
+
+
+
+
+
+
+
+ Checkers
+
+
+ -
+
+
+ true
+
+
+
+ Courier 10 Pitch
+
+
+
+ true
+
+
+ true
+
+
diff --git a/lib/checkers.h b/lib/checkers.h
index 5cc61a518a3..cec27c53f0b 100644
--- a/lib/checkers.h
+++ b/lib/checkers.h
@@ -206,22 +206,21 @@ namespace checkers {
static std::map premiumCheckers{
- {"CheckBufferOverrun::addressOfPointerArithmetic","warning"},
- {"CheckBufferOverrun::negativeBufferSizeCheckedNonZero","warning"},
- {"CheckBufferOverrun::negativeBufferSizeCheckedNonZero","warning"},
- {"CheckHang::infiniteLoop",""},
- {"CheckHang::infiniteLoopContinue",""},
- {"CheckOther::arrayPointerComparison","style"},
- {"CheckOther::knownResult","style"},
- {"CheckOther::lossOfPrecision","style"},
- {"CheckOther::pointerCast","style"},
- {"CheckOther::reassignInLoop","style"},
- {"CheckOther::unreachableCode","style"},
- {"CheckStrictAlias::strictAliasCondition","warning"},
- {"CheckUninitVar::uninitvar",""},
- {"CheckUninitVar::uninitmember",""},
- {"CheckUnusedVar::unreadVariable","style"},
- {"CheckUnusedVar::unusedPrivateMember","style"},
+ {"PremiumCheckBufferOverrun::addressOfPointerArithmetic","warning"},
+ {"PremiumCheckBufferOverrun::negativeBufferSizeCheckedNonZero","warning"},
+ {"PremiumCheckBufferOverrun::negativeBufferSizeCheckedNonZero","warning"},
+ {"PremiumCheckHang::infiniteLoop",""},
+ {"PremiumCheckHang::infiniteLoopContinue",""},
+ {"PremiumCheckOther::arrayPointerComparison","style"},
+ {"PremiumCheckOther::knownResult","style"},
+ {"PremiumCheckOther::lossOfPrecision","style"},
+ {"PremiumCheckOther::pointerCast","style"},
+ {"PremiumCheckOther::reassignInLoop","style"},
+ {"PremiumCheckOther::unreachableCode","style"},
+ {"PremiumCheckUninitVar::uninitvar",""},
+ {"PremiumCheckUninitVar::uninitmember",""},
+ {"PremiumCheckUnusedVar::unreadVariable","style"},
+ {"PremiumCheckUnusedVar::unusedPrivateMember","style"},
};
diff --git a/lib/checkersreport.cpp b/lib/checkersreport.cpp
new file mode 100644
index 00000000000..a90cdf595c7
--- /dev/null
+++ b/lib/checkersreport.cpp
@@ -0,0 +1,207 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2023 Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "checkersreport.h"
+#include "checkers.h"
+#include
+
+static bool isCppcheckPremium(const Settings& settings) {
+ return (settings.cppcheckCfgProductName.compare(0, 16, "Cppcheck Premium") == 0);
+}
+
+static std::string getMisraRuleSeverity(const std::string& rule) {
+ if (checkers::misraRuleSeverity.count(rule) > 0)
+ return checkers::misraRuleSeverity.at(rule);
+ return "style";
+}
+
+static bool isMisraRuleInconclusive(const std::string& rule) {
+ return rule == "8.3";
+}
+
+static bool isMisraRuleActive(const std::string& rule, int amendment, const std::string& severity, const Settings& settings) {
+ if (!isCppcheckPremium(settings) && amendment >= 3)
+ return false;
+ const bool inconclusive = isMisraRuleInconclusive(rule);
+ if (inconclusive && !settings.certainty.isEnabled(Certainty::inconclusive))
+ return false;
+ if (severity == "warning")
+ return settings.severity.isEnabled(Severity::warning);
+ if (severity == "style")
+ return settings.severity.isEnabled(Severity::style);
+ return true; // error severity
+}
+
+CheckersReport::CheckersReport(const Settings& settings, const std::set& activeCheckers)
+ : mSettings(settings), mActiveCheckers(activeCheckers)
+{}
+
+int CheckersReport::getActiveCheckersCount()
+{
+ if (mAllCheckersCount == 0) {
+ countCheckers();
+ }
+ return mActiveCheckersCount;
+}
+
+int CheckersReport::getAllCheckersCount()
+{
+ if (mAllCheckersCount == 0) {
+ countCheckers();
+ }
+ return mAllCheckersCount;
+}
+
+void CheckersReport::countCheckers()
+{
+ mActiveCheckersCount = mAllCheckersCount = 0;
+
+ for (const auto& checkReq: checkers::allCheckers) {
+ if (mActiveCheckers.count(checkReq.first) > 0)
+ ++mActiveCheckersCount;
+ ++mAllCheckersCount;
+ }
+ for (const auto& checkReq: checkers::premiumCheckers) {
+ if (mActiveCheckers.count(checkReq.first) > 0)
+ ++mActiveCheckersCount;
+ ++mAllCheckersCount;
+ }
+ if (mSettings.premiumArgs.find("misra-c-") != std::string::npos || mSettings.addons.count("misra")) {
+ for (const checkers::MisraInfo& info: checkers::misraC2012Rules) {
+ const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b);
+ const std::string severity = getMisraRuleSeverity(rule);
+ const bool active = isMisraRuleActive(rule, info.amendment, severity, mSettings);
+ if (active)
+ ++mActiveCheckersCount;
+ ++mAllCheckersCount;
+ }
+ }
+}
+
+std::string CheckersReport::getReport(const std::string& criticalErrors) const
+{
+ std::ostringstream fout;
+
+ fout << "Critical errors" << std::endl;
+ fout << "---------------" << std::endl;
+ if (!criticalErrors.empty()) {
+ fout << "There was critical errors (" << criticalErrors << ")" << std::endl;
+ fout << "All checking is skipped for a file with such error" << std::endl;
+ } else {
+ fout << "No critical errors, all files were checked." << std::endl;
+ fout << "Important: Analysis is still not guaranteed to be 'complete' it is possible there are false negatives." << std::endl;
+ }
+
+ fout << std::endl << std::endl;
+ fout << "Open source checkers" << std::endl;
+ fout << "--------------------" << std::endl;
+
+ int maxCheckerSize = 0;
+ for (const auto& checkReq: checkers::allCheckers) {
+ const std::string& checker = checkReq.first;
+ if (checker.size() > maxCheckerSize)
+ maxCheckerSize = checker.size();
+ }
+ for (const auto& checkReq: checkers::allCheckers) {
+ const std::string& checker = checkReq.first;
+ const bool active = mActiveCheckers.count(checkReq.first) > 0;
+ const std::string& req = checkReq.second;
+ fout << (active ? "Yes " : "No ") << checker;
+ if (!active && !req.empty())
+ fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << "require:" + req;
+ fout << std::endl;
+ }
+
+ const bool cppcheckPremium = isCppcheckPremium(mSettings);
+
+ fout << std::endl << std::endl;
+ fout << "Premium checkers" << std::endl;
+ fout << "----------------" << std::endl;
+ if (!cppcheckPremium) {
+ fout << "Cppcheck Premium is not used" << std::endl;
+ } else {
+ maxCheckerSize = 0;
+ for (const auto& checkReq: checkers::premiumCheckers) {
+ const std::string& checker = checkReq.first;
+ if (checker.size() > maxCheckerSize)
+ maxCheckerSize = checker.size();
+ }
+ for (const auto& checkReq: checkers::premiumCheckers) {
+ const std::string& checker = checkReq.first;
+ std::string req = checkReq.second;
+ bool active = cppcheckPremium && mActiveCheckers.count(checkReq.first) > 0;
+ if (req == "warning")
+ active &= mSettings.severity.isEnabled(Severity::warning);
+ else if (req == "style")
+ active &= mSettings.severity.isEnabled(Severity::style);
+ else if (!req.empty())
+ active = false; // FIXME: handle req
+ fout << (active ? "Yes " : "No ") << checker;
+ if (!req.empty())
+ req = "premium," + req;
+ else
+ req = "premium";
+ if (!active)
+ fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << "require:" + req;
+ fout << std::endl;
+ }
+ }
+
+ int misra = 0;
+ if (mSettings.premiumArgs.find("misra-c-2012") != std::string::npos)
+ misra = 2012;
+ else if (mSettings.premiumArgs.find("misra-c-2023") != std::string::npos)
+ misra = 2023;
+ else if (mSettings.addons.count("misra"))
+ misra = 2012;
+
+ if (misra == 0) {
+ fout << std::endl << std::endl;
+ fout << "Misra C" << std::endl;
+ fout << "-------" << std::endl;
+ fout << "Misra is not enabled" << std::endl;
+ } else {
+ fout << std::endl << std::endl;
+ fout << "Misra C " << misra << std::endl;
+ fout << "------------" << std::endl;
+ for (const checkers::MisraInfo& info: checkers::misraC2012Rules) {
+ const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b);
+ const std::string severity = getMisraRuleSeverity(rule);
+ const bool active = isMisraRuleActive(rule, info.amendment, severity, mSettings);
+ const bool inconclusive = isMisraRuleInconclusive(rule);
+ fout << (active ? "Yes " : "No ") << rule;
+ std::string extra;
+ if (misra == 2012 && info.amendment >= 1)
+ extra = " amendment:" + std::to_string(info.amendment);
+ std::string reqs;
+ if (info.amendment >= 3)
+ reqs += ",premium";
+ if (severity != "error")
+ reqs += "," + severity;
+ if (inconclusive)
+ reqs += ",inconclusive";
+ if (!active && !reqs.empty())
+ extra += " require:" + reqs.substr(1);
+ if (!extra.empty())
+ fout << std::string(7 - rule.size(), ' ') << extra;
+ fout << '\n';
+ }
+ }
+
+ return fout.str();
+}
diff --git a/lib/checkersreport.h b/lib/checkersreport.h
new file mode 100644
index 00000000000..b6acab8800b
--- /dev/null
+++ b/lib/checkersreport.h
@@ -0,0 +1,44 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2023 Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include "settings.h"
+#include
+#include
+
+class CPPCHECKLIB CheckersReport {
+public:
+ CheckersReport(const Settings& settings, const std::set& activeCheckers);
+
+ int getActiveCheckersCount();
+ int getAllCheckersCount();
+
+ std::string getReport(const std::string& criticalErrors) const;
+
+private:
+ const Settings& mSettings;
+ const std::set& mActiveCheckers;
+
+ void countCheckers();
+
+ int mActiveCheckersCount = 0;
+ int mAllCheckersCount = 0;
+};
+
+
diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp
index fe9b6005034..ca6ebd1b2f6 100644
--- a/lib/cppcheck.cpp
+++ b/lib/cppcheck.cpp
@@ -1500,9 +1500,11 @@ void CppCheck::executeAddons(const std::vector& files)
errmsg.setmsg(text);
const std::string severity = obj["severity"].get();
errmsg.severity = Severity::fromString(severity);
- if (errmsg.severity == Severity::SeverityType::none)
- continue;
- if (!mSettings.severity.isEnabled(errmsg.severity))
+ if (errmsg.severity == Severity::SeverityType::none) {
+ if (!endsWith(errmsg.id, "-logChecker"))
+ continue;
+ }
+ else if (!mSettings.severity.isEnabled(errmsg.severity))
continue;
errmsg.file0 = ((files.size() == 1) ? files[0] : "");
@@ -1605,7 +1607,7 @@ void CppCheck::purgedConfigurationMessage(const std::string &file, const std::st
void CppCheck::reportErr(const ErrorMessage &msg)
{
- if (msg.severity == Severity::none && msg.id == "logChecker") {
+ if (msg.severity == Severity::none && (msg.id == "logChecker" || endsWith(msg.id, "-logChecker"))) {
mErrorLogger.reportErr(msg);
return;
}
diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj
index 28e4752d6b6..db5906ad8d0 100644
--- a/lib/cppcheck.vcxproj
+++ b/lib/cppcheck.vcxproj
@@ -56,6 +56,7 @@
+
@@ -122,6 +123,7 @@
+
diff --git a/lib/cppcheck.vcxproj.filters b/lib/cppcheck.vcxproj.filters
index 2bba20684fa..c3e5d34664f 100644
--- a/lib/cppcheck.vcxproj.filters
+++ b/lib/cppcheck.vcxproj.filters
@@ -194,6 +194,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
@@ -406,6 +412,15 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp
index 5b69bd489f6..2e868453fcc 100644
--- a/lib/errorlogger.cpp
+++ b/lib/errorlogger.cpp
@@ -45,6 +45,7 @@ const std::set ErrorLogger::mCriticalErrorIds{
"internalAstError",
"instantiationError",
"internalError",
+ "premium-internalError",
"preprocessorErrorDirective",
"syntaxError",
"unknownMacro"
diff --git a/lib/lib.pri b/lib/lib.pri
index 09676f2dede..6c31cc91c34 100644
--- a/lib/lib.pri
+++ b/lib/lib.pri
@@ -16,6 +16,7 @@ HEADERS += $${PWD}/analyzer.h \
$${PWD}/checkbufferoverrun.h \
$${PWD}/checkclass.h \
$${PWD}/checkcondition.h \
+ $${PWD}/checkersreport.h \
$${PWD}/checkexceptionsafety.h \
$${PWD}/checkfunctions.h \
$${PWD}/checkinternal.h \
@@ -85,6 +86,7 @@ SOURCES += $${PWD}/analyzerinfo.cpp \
$${PWD}/checkbufferoverrun.cpp \
$${PWD}/checkclass.cpp \
$${PWD}/checkcondition.cpp \
+ $${PWD}/checkersreport.cpp \
$${PWD}/checkexceptionsafety.cpp \
$${PWD}/checkfunctions.cpp \
$${PWD}/checkinternal.cpp \
diff --git a/releasenotes.txt b/releasenotes.txt
index c54c20094a9..f544955b439 100644
--- a/releasenotes.txt
+++ b/releasenotes.txt
@@ -10,8 +10,12 @@ Improved checking:
- constParameter*/constVariable* checks find more instances of pointers/references that can be const, e.g. when calling library functions
GUI:
+- Show in statistics which checkers have been activated in latest analysis
+- Make it more visible if there has been critical errors that caused checkers to be skipped
Changed interface:
+- Write how many checkers was activated after a run
+- Added --checkers-report that can be used to generate a report in a file that shows what checkers was activated and disabled
Deprecations:
- The qmake build system has been deprecated and will be removed in a future version.
diff --git a/test/testrunner.vcxproj.filters b/test/testrunner.vcxproj.filters
index db85b4d9e37..7aa2676a830 100644
--- a/test/testrunner.vcxproj.filters
+++ b/test/testrunner.vcxproj.filters
@@ -256,6 +256,9 @@
Source Files
+
+ Source Files
+
diff --git a/tools/get_checkers.py b/tools/get_checkers.py
index b43e457a08f..510b2d82718 100644
--- a/tools/get_checkers.py
+++ b/tools/get_checkers.py
@@ -44,22 +44,22 @@
premium_checkers = """
$ grep logChecker *.cpp | sed 's/.*logChecker/logChecker/'
-logChecker("CheckBufferOverrun::addressOfPointerArithmetic"); // warning
-logChecker("CheckBufferOverrun::negativeBufferSizeCheckedNonZero"); // warning
-logChecker("CheckBufferOverrun::negativeBufferSizeCheckedNonZero"); // warning
-logChecker("CheckHang::infiniteLoop");
-logChecker("CheckHang::infiniteLoopContinue");
-logChecker("CheckOther::arrayPointerComparison"); // style
-logChecker("CheckOther::knownResult"); // style
-logChecker("CheckOther::lossOfPrecision"); // style
-logChecker("CheckOther::pointerCast"); // style
-logChecker("CheckOther::reassignInLoop"); // style
-logChecker("CheckOther::unreachableCode"); // style
-logChecker("CheckStrictAlias::strictAliasCondition"); // warning
-logChecker("CheckUninitVar::uninitvar");
-logChecker("CheckUninitVar::uninitmember");
-logChecker("CheckUnusedVar::unreadVariable"); // style
-logChecker("CheckUnusedVar::unusedPrivateMember"); // style
+logChecker("PremiumCheckBufferOverrun::addressOfPointerArithmetic"); // warning
+logChecker("PremiumCheckBufferOverrun::negativeBufferSizeCheckedNonZero"); // warning
+logChecker("PremiumCheckBufferOverrun::negativeBufferSizeCheckedNonZero"); // warning
+logChecker("PremiumCheckHang::infiniteLoop");
+logChecker("PremiumCheckHang::infiniteLoopContinue");
+logChecker("PremiumCheckOther::arrayPointerComparison"); // style
+logChecker("PremiumCheckOther::knownResult"); // style
+logChecker("PremiumCheckOther::lossOfPrecision"); // style
+logChecker("PremiumCheckOther::pointerCast"); // style
+logChecker("PremiumCheckOther::reassignInLoop"); // style
+logChecker("PremiumCheckOther::unreachableCode"); // style
+logChecker("PremiumCheckStrictAlias::strictAliasCondition"); // warning
+logChecker("PremiumCheckUninitVar::uninitvar");
+logChecker("PremiumCheckUninitVar::uninitmember");
+logChecker("PremiumCheckUnusedVar::unreadVariable"); // style
+logChecker("PremiumCheckUnusedVar::unusedPrivateMember"); // style
"""
for line in premium_checkers.split('\n'):