Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #11897 (Safety: show what checks are enabled/disabled) #5378

Merged
merged 4 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
9 changes: 6 additions & 3 deletions cli/cli.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
</Filter>
</ItemGroup>
<ItemGroup Label="HeaderFiles">
<ClInclude Include="..\lib\config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cmdlineparser.h">
<Filter>Header Files</Filter>
</ClInclude>
Expand Down Expand Up @@ -44,6 +41,9 @@
<ClInclude Include="stacktrace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="singleexecutor.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup Label="SourceFiles">
<ClCompile Include="main.cpp">
Expand Down Expand Up @@ -76,6 +76,9 @@
<ClCompile Include="stacktrace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="singleexecutor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="version.rc">
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 = std::move(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
Loading