Skip to content

Commit

Permalink
Fix #11897 (Safety: show what checks are enabled/disabled)
Browse files Browse the repository at this point in the history
  • Loading branch information
danmar committed Aug 30, 2023
1 parent 7c992ce commit 7e6bfd7
Show file tree
Hide file tree
Showing 19 changed files with 540 additions and 302 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
164 changes: 8 additions & 156 deletions cli/cppcheckexecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "analyzerinfo.h"
#include "checkers.h"
#include "checkersreport.h"
#include "cmdlineparser.h"
#include "color.h"
#include "config.h"
Expand Down Expand Up @@ -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=<filename> to see details)" : "";
if (mCriticalErrors.empty())
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions gui/checkstatistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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
Expand Down
26 changes: 26 additions & 0 deletions gui/checkstatistics.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@

#include <QMap>
#include <QObject>
#include <QSet>
#include <QString>
#include <QStringList>

#include <set>
#include <string>

/// @addtogroup GUI
/// @{

Expand All @@ -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.
*
Expand All @@ -59,16 +68,33 @@ class CheckStatistics : public QObject {
*/
unsigned getCount(const QString &tool, ShowTypes::ShowType type) const;

std::set<std::string> getActiveCheckers() const {
return mActiveCheckers;
}

int getNumberOfActiveCheckers() const {
return mActiveCheckers.size();
}

/** Get tools with results */
QStringList getTools() const;

void setCheckersReport(QString report) {
mCheckersReport = report;
}
QString getCheckersReport() const {
return mCheckersReport;
}

private:
QMap<QString, unsigned> mStyle;
QMap<QString, unsigned> mWarning;
QMap<QString, unsigned> mPerformance;
QMap<QString, unsigned> mPortability;
QMap<QString, unsigned> mInformation;
QMap<QString, unsigned> mError;
std::set<std::string> mActiveCheckers;
QString mCheckersReport;
};

/// @}
Expand Down
10 changes: 8 additions & 2 deletions gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}

Expand All @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion gui/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading

0 comments on commit 7e6bfd7

Please sign in to comment.