Fix unmatched suppression (#5704) (#3886)

This commit is contained in:
Jens Yllman 2022-03-30 19:24:53 +02:00 committed by GitHub
parent 343a23135d
commit 34a11c1673
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 73 additions and 6 deletions

View File

@ -554,7 +554,7 @@ $(libcppdir)/settings.o: lib/settings.cpp externals/picojson/picojson.h lib/conf
$(libcppdir)/summaries.o: lib/summaries.cpp lib/analyzerinfo.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/summaries.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(libcppdir)/summaries.o: lib/summaries.cpp lib/analyzerinfo.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/summaries.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/summaries.o $(libcppdir)/summaries.cpp $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/summaries.o $(libcppdir)/summaries.cpp
$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/mathlib.h lib/path.h lib/suppressions.h lib/utils.h $(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/mathlib.h lib/path.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/suppressions.o $(libcppdir)/suppressions.cpp $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/suppressions.o $(libcppdir)/suppressions.cpp
$(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp lib/astutils.h lib/color.h lib/config.h lib/errorlogger.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/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(libcppdir)/symboldatabase.o: lib/symboldatabase.cpp lib/astutils.h lib/color.h lib/config.h lib/errorlogger.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/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h

View File

@ -861,6 +861,9 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
fdump << "</dump>" << std::endl; fdump << "</dump>" << std::endl;
} }
// Need to call this even if the checksum will skip this configuration
mSettings.nomsg.markUnmatchedInlineSuppressionsAsChecked(tokenizer);
// Skip if we already met the same simplified token list // Skip if we already met the same simplified token list
if (mSettings.force || mSettings.maxConfigs > 1) { if (mSettings.force || mSettings.maxConfigs > 1) {
const unsigned long long checksum = tokenizer.list.calculateChecksum(); const unsigned long long checksum = tokenizer.list.calculateChecksum();

View File

@ -22,6 +22,7 @@
#include "mathlib.h" #include "mathlib.h"
#include "path.h" #include "path.h"
#include "utils.h" #include "utils.h"
#include "tokenize.h"
#include <algorithm> #include <algorithm>
#include <cctype> // std::isdigit, std::isalnum, etc #include <cctype> // std::isdigit, std::isalnum, etc
@ -340,6 +341,7 @@ bool Suppressions::Suppression::isMatch(const Suppressions::ErrorMessage &errmsg
if (!isSuppressed(errmsg)) if (!isSuppressed(errmsg))
return false; return false;
matched = true; matched = true;
checked = true;
return true; return true;
} }
@ -411,7 +413,7 @@ std::list<Suppressions::Suppression> Suppressions::getUnmatchedLocalSuppressions
std::string tmpFile = Path::simplifyPath(file); std::string tmpFile = Path::simplifyPath(file);
std::list<Suppression> result; std::list<Suppression> result;
for (const Suppression &s : mSuppressions) { for (const Suppression &s : mSuppressions) {
if (s.matched) if (s.matched || ((s.lineNumber != Suppression::NO_LINE) && !s.checked))
continue; continue;
if (s.hash > 0) if (s.hash > 0)
continue; continue;
@ -428,7 +430,7 @@ std::list<Suppressions::Suppression> Suppressions::getUnmatchedGlobalSuppression
{ {
std::list<Suppression> result; std::list<Suppression> result;
for (const Suppression &s : mSuppressions) { for (const Suppression &s : mSuppressions) {
if (s.matched) if (s.matched || ((s.lineNumber != Suppression::NO_LINE) && !s.checked))
continue; continue;
if (s.hash > 0) if (s.hash > 0)
continue; continue;
@ -445,3 +447,19 @@ const std::list<Suppressions::Suppression> &Suppressions::getSuppressions() cons
{ {
return mSuppressions; return mSuppressions;
} }
void Suppressions::markUnmatchedInlineSuppressionsAsChecked(const Tokenizer &tokenizer) {
int currLineNr = -1;
int currFileIdx = -1;
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
if (currFileIdx != tok->fileIndex() || currLineNr != tok->linenr()) {
currLineNr = tok->linenr();
currFileIdx = tok->fileIndex();
for (auto &suppression : mSuppressions) {
if (!suppression.checked && (suppression.lineNumber == currLineNr) && (suppression.fileName == tokenizer.list.file(tok))) {
suppression.checked = true;
}
}
}
}
}

View File

@ -32,6 +32,8 @@
/// @addtogroup Core /// @addtogroup Core
/// @{ /// @{
class Tokenizer;
/** @brief class for handling suppressions */ /** @brief class for handling suppressions */
class CPPCHECKLIB Suppressions { class CPPCHECKLIB Suppressions {
public: public:
@ -51,11 +53,11 @@ public:
}; };
struct CPPCHECKLIB Suppression { struct CPPCHECKLIB Suppression {
Suppression() : lineNumber(NO_LINE), hash(0), thisAndNextLine(false), matched(false) {} Suppression() : lineNumber(NO_LINE), hash(0), thisAndNextLine(false), matched(false), checked(false) {}
Suppression(const Suppression &other) { Suppression(const Suppression &other) {
*this = other; *this = other;
} }
Suppression(const std::string &id, const std::string &file, int line=NO_LINE) : errorId(id), fileName(file), lineNumber(line), hash(0), thisAndNextLine(false), matched(false) {} Suppression(const std::string &id, const std::string &file, int line=NO_LINE) : errorId(id), fileName(file), lineNumber(line), hash(0), thisAndNextLine(false), matched(false), checked(false) {}
Suppression & operator=(const Suppression &other) { Suppression & operator=(const Suppression &other) {
errorId = other.errorId; errorId = other.errorId;
@ -65,6 +67,7 @@ public:
hash = other.hash; hash = other.hash;
thisAndNextLine = other.thisAndNextLine; thisAndNextLine = other.thisAndNextLine;
matched = other.matched; matched = other.matched;
checked = other.checked;
return *this; return *this;
} }
@ -118,6 +121,7 @@ public:
std::size_t hash; std::size_t hash;
bool thisAndNextLine; // Special case for backwards compatibility: { // cppcheck-suppress something bool thisAndNextLine; // Special case for backwards compatibility: { // cppcheck-suppress something
bool matched; bool matched;
bool checked; // for inline suppressions, checked or not
enum { NO_LINE = -1 }; enum { NO_LINE = -1 };
}; };
@ -204,6 +208,12 @@ public:
*/ */
const std::list<Suppression> &getSuppressions() const; const std::list<Suppression> &getSuppressions() const;
/**
* @brief Marks Inline Suppressions as checked if source line is in the token stream
* @return No return.
*/
void markUnmatchedInlineSuppressionsAsChecked(const Tokenizer &tokenizer);
private: private:
/** @brief List of error which the user doesn't want to see. */ /** @brief List of error which the user doesn't want to see. */
std::list<Suppression> mSuppressions; std::list<Suppression> mSuppressions;

View File

@ -59,6 +59,18 @@ def test_compile_commands_unused_function_suppression():
assert 'unusedFunction' not in stderr assert 'unusedFunction' not in stderr
def test_unmatched_suppression_ifdef():
ret, stdout, stderr = cppcheck(['--enable=all', '--suppress=missingIncludeSystem', '--inline-suppr', '-DNO_ZERO_DIV', 'trac5704/trac5704a.c'])
assert ret == 0, stdout
assert 'unmatchedSuppression' not in stderr
def test_unmatched_suppression_ifdef_0():
ret, stdout, stderr = cppcheck(['--enable=all', '--suppress=missingIncludeSystem', '--inline-suppr', 'trac5704/trac5704b.c'])
assert ret == 0, stdout
assert 'unmatchedSuppression' not in stderr
def test_build_dir(): def test_build_dir():
with tempfile.TemporaryDirectory() as tempdir: with tempfile.TemporaryDirectory() as tempdir:
args = f'--cppcheck-build-dir={tempdir} --enable=all --inline-suppr proj-inline-suppress/4.c'.split() args = f'--cppcheck-build-dir={tempdir} --enable=all --inline-suppr proj-inline-suppress/4.c'.split()

View File

@ -0,0 +1,11 @@
#include <stdio.h>
int main(int argc, char *argv[])
{
#ifdef INCLUDE_ZERO_DIV
// cppcheck-suppress zerodiv
int i = 1/0;
printf("i = %d\n", i);
#endif
return 0;
}

View File

@ -0,0 +1,11 @@
#include <stdio.h>
int main(int argc, char *argv[])
{
#ifdef 0
// cppcheck-suppress zerodiv
int i = 1/0;
printf("i = %d\n", i);
#endif
return 0;
}

View File

@ -669,7 +669,9 @@ private:
void inlinesuppress_unusedFunction() const { // #4210, #4946 - wrong report of "unmatchedSuppression" for "unusedFunction" void inlinesuppress_unusedFunction() const { // #4210, #4946 - wrong report of "unmatchedSuppression" for "unusedFunction"
Suppressions suppressions; Suppressions suppressions;
suppressions.addSuppression(Suppressions::Suppression("unusedFunction", "test.c", 3)); auto suppression = Suppressions::Suppression("unusedFunction", "test.c", 3);
suppression.checked = true; // have to do this because fixes for #5704
suppressions.addSuppression(suppression);
ASSERT_EQUALS(true, !suppressions.getUnmatchedLocalSuppressions("test.c", true).empty()); ASSERT_EQUALS(true, !suppressions.getUnmatchedLocalSuppressions("test.c", true).empty());
ASSERT_EQUALS(false, !suppressions.getUnmatchedGlobalSuppressions(true).empty()); ASSERT_EQUALS(false, !suppressions.getUnmatchedGlobalSuppressions(true).empty());
ASSERT_EQUALS(false, !suppressions.getUnmatchedLocalSuppressions("test.c", false).empty()); ASSERT_EQUALS(false, !suppressions.getUnmatchedLocalSuppressions("test.c", false).empty());