Fix #9567 (Inline suppression of unusedFunction errors not working when using compile database) (#2870)

This commit is contained in:
Jesse Boswell 2020-11-04 14:01:48 -06:00 committed by GitHub
parent 05b804d126
commit f70e8de315
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 104 additions and 2 deletions

View File

@ -420,7 +420,9 @@ unsigned int CppCheck::check(const ImportProject::FileSettings &fs)
temp.check(Path::simplifyPath(fs.filename)); temp.check(Path::simplifyPath(fs.filename));
} }
std::ifstream fin(fs.filename); std::ifstream fin(fs.filename);
return temp.checkFile(Path::simplifyPath(fs.filename), fs.cfg, fin); unsigned int returnValue = temp.checkFile(Path::simplifyPath(fs.filename), fs.cfg, fin);
mSettings.nomsg.addSuppressions(temp.mSettings.nomsg.getSuppressions());
return returnValue;
} }
unsigned int CppCheck::checkFile(const std::string& filename, const std::string &cfgname, std::istream& fileStream) unsigned int CppCheck::checkFile(const std::string& filename, const std::string &cfgname, std::istream& fileStream)

View File

@ -27,6 +27,7 @@
#include <algorithm> #include <algorithm>
#include <cctype> // std::isdigit, std::isalnum, etc #include <cctype> // std::isdigit, std::isalnum, etc
#include <functional> // std::bind, std::placeholders
#include <sstream> #include <sstream>
#include <utility> #include <utility>
@ -217,6 +218,16 @@ std::string Suppressions::addSuppressionLine(const std::string &line)
std::string Suppressions::addSuppression(const Suppressions::Suppression &suppression) std::string Suppressions::addSuppression(const Suppressions::Suppression &suppression)
{ {
// Check if suppression is already in list
auto foundSuppression = std::find_if(mSuppressions.begin(), mSuppressions.end(),
std::bind(&Suppression::isSameParameters, &suppression, std::placeholders::_1));
if (foundSuppression != mSuppressions.end()) {
// Update matched state of existing global suppression
if (!suppression.isLocal() && suppression.matched)
foundSuppression->matched = suppression.matched;
return "";
}
// Check that errorId is valid.. // Check that errorId is valid..
if (suppression.errorId.empty() && suppression.hash == 0) if (suppression.errorId.empty() && suppression.hash == 0)
return "Failed to add suppression. No id."; return "Failed to add suppression. No id.";
@ -242,6 +253,16 @@ std::string Suppressions::addSuppression(const Suppressions::Suppression &suppre
return ""; return "";
} }
std::string Suppressions::addSuppressions(const std::list<Suppression> &suppressions)
{
for (const auto &newSuppression : suppressions) {
auto errmsg = addSuppression(newSuppression);
if (errmsg != "")
return errmsg;
}
return "";
}
void Suppressions::ErrorMessage::setFileName(const std::string &s) void Suppressions::ErrorMessage::setFileName(const std::string &s)
{ {
mFileName = Path::simplifyPath(s); mFileName = Path::simplifyPath(s);
@ -419,3 +440,8 @@ std::list<Suppressions::Suppression> Suppressions::getUnmatchedGlobalSuppression
} }
return result; return result;
} }
std::list<Suppressions::Suppression> Suppressions::getSuppressions() const
{
return mSuppressions;
}

View File

@ -93,12 +93,22 @@ public:
bool isSuppressed(const ErrorMessage &errmsg) const; bool isSuppressed(const ErrorMessage &errmsg) const;
bool isMatch(const ErrorMessage &errmsg); bool isMatch(const ErrorMessage &errmsg);
std::string getText() const; std::string getText() const;
bool isLocal() const { bool isLocal() const {
return !fileName.empty() && fileName.find_first_of("?*") == std::string::npos; return !fileName.empty() && fileName.find_first_of("?*") == std::string::npos;
} }
bool isSameParameters(const Suppression &other) const {
return errorId == other.errorId &&
fileName == other.fileName &&
lineNumber == other.lineNumber &&
symbolName == other.symbolName &&
hash == other.hash &&
thisAndNextLine == other.thisAndNextLine;
}
std::string errorId; std::string errorId;
std::string fileName; std::string fileName;
int lineNumber; int lineNumber;
@ -147,6 +157,13 @@ public:
*/ */
std::string addSuppression(const Suppression &suppression); std::string addSuppression(const Suppression &suppression);
/**
* @brief Combine list of suppressions into the current suppressions.
* @param suppressions list of suppression details
* @return error message. empty upon success
*/
std::string addSuppressions(const std::list<Suppression> &suppressions);
/** /**
* @brief Returns true if this message should not be shown to the user. * @brief Returns true if this message should not be shown to the user.
* @param errmsg error message * @param errmsg error message
@ -179,6 +196,12 @@ public:
*/ */
std::list<Suppression> getUnmatchedGlobalSuppressions(const bool unusedFunctionChecking) const; std::list<Suppression> getUnmatchedGlobalSuppressions(const bool unusedFunctionChecking) const;
/**
* @brief Returns list of all suppressions.
* @return list of suppressions
*/
std::list<Suppression> getSuppressions() const;
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

@ -0,0 +1,6 @@
#include "B.hpp"
int main()
{
B b();
}

View File

@ -0,0 +1,6 @@
#include "B.hpp"
B::B() {}
// cppcheck-suppress unusedFunction
void B::unusedFunctionTest() {}

View File

@ -0,0 +1,6 @@
class B {
public:
B();
void unusedFunctionTest();
};

View File

@ -1,10 +1,23 @@
# python -m pytest test-inline-suppress.py # python -m pytest test-inline-suppress.py
import json
import os import os
import re import re
from testutils import cppcheck from testutils import cppcheck
def create_unused_function_compile_commands():
compile_commands = os.path.join('proj-inline-suppress-unusedFunction', 'compile_commands.json')
prjpath = os.path.join(os.getcwd(), 'proj-inline-suppress-unusedFunction')
j = [{'directory': prjpath,
'command': '/usr/bin/c++ -I"' + prjpath + '" -o "' + os.path.join(prjpath, 'B.cpp.o') + '" -c "' + os.path.join(prjpath, 'B.cpp') + '"',
'file': os.path.join(prjpath, 'B.cpp')},
{'directory': prjpath,
'command': '/usr/bin/c++ -I"' + prjpath + '" -o "' + os.path.join(prjpath, 'A.cpp.o') + '" -c "' + os.path.join(prjpath, 'A.cpp') + '"',
'file': os.path.join(prjpath, 'A.cpp')}]
with open(compile_commands, 'wt') as f:
f.write(json.dumps(j, indent=4))
def test1(): def test1():
ret, stdout, stderr = cppcheck(['--inline-suppr', 'proj-inline-suppress']) ret, stdout, stderr = cppcheck(['--inline-suppr', 'proj-inline-suppress'])
assert ret == 0 assert ret == 0
@ -31,3 +44,15 @@ def test_backwards_compatibility():
ret, stdout, stderr = cppcheck(['--inline-suppr', 'proj-inline-suppress/3.cpp']) ret, stdout, stderr = cppcheck(['--inline-suppr', 'proj-inline-suppress/3.cpp'])
assert stderr == '' assert stderr == ''
def test_compile_commands_unused_function():
create_unused_function_compile_commands()
ret, stdout, stderr = cppcheck(['--enable=all', '--error-exitcode=1', '--project=./proj-inline-suppress-unusedFunction/compile_commands.json'])
assert ret == 1
assert 'unusedFunction' in stderr
def test_compile_commands_unused_function_suppression():
create_unused_function_compile_commands()
ret, stdout, stderr = cppcheck(['--enable=all', '--inline-suppr', '--error-exitcode=1', '--project=./proj-inline-suppress-unusedFunction/compile_commands.json'])
assert ret == 0
assert 'unusedFunction' not in stderr

View File

@ -1,6 +1,7 @@
import logging import logging
import os import os
import shutil
import subprocess import subprocess
# Create Cppcheck project file # Create Cppcheck project file
@ -47,6 +48,14 @@ def cppcheck(args):
exe = '../../cppcheck.exe' exe = '../../cppcheck.exe'
elif os.path.isfile('../../../cppcheck.exe'): elif os.path.isfile('../../../cppcheck.exe'):
exe = '../../../cppcheck.exe' exe = '../../../cppcheck.exe'
elif os.path.isfile('../../bin/cppcheck.exe'):
exe = '../../bin/cppcheck.exe'
elif os.path.isfile('../../../bin/cppcheck.exe'):
exe = '../../../bin/cppcheck.exe'
elif os.path.isfile('../../bin/cppcheck'):
exe = '../../bin/cppcheck'
elif os.path.isfile('../../../bin/cppcheck'):
exe = '../../../bin/cppcheck'
elif os.path.isfile('../../cppcheck'): elif os.path.isfile('../../cppcheck'):
exe = '../../cppcheck' exe = '../../cppcheck'
else: else:
@ -58,4 +67,3 @@ def cppcheck(args):
stdout = comm[0].decode(encoding='utf-8', errors='ignore').replace('\r\n', '\n') stdout = comm[0].decode(encoding='utf-8', errors='ignore').replace('\r\n', '\n')
stderr = comm[1].decode(encoding='utf-8', errors='ignore').replace('\r\n', '\n') stderr = comm[1].decode(encoding='utf-8', errors='ignore').replace('\r\n', '\n')
return p.returncode, stdout, stderr return p.returncode, stdout, stderr