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));
}
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)

View File

@ -27,6 +27,7 @@
#include <algorithm>
#include <cctype> // std::isdigit, std::isalnum, etc
#include <functional> // std::bind, std::placeholders
#include <sstream>
#include <utility>
@ -217,6 +218,16 @@ std::string Suppressions::addSuppressionLine(const std::string &line)
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..
if (suppression.errorId.empty() && suppression.hash == 0)
return "Failed to add suppression. No id.";
@ -242,6 +253,16 @@ std::string Suppressions::addSuppression(const Suppressions::Suppression &suppre
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)
{
mFileName = Path::simplifyPath(s);
@ -419,3 +440,8 @@ std::list<Suppressions::Suppression> Suppressions::getUnmatchedGlobalSuppression
}
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 isMatch(const ErrorMessage &errmsg);
std::string getText() const;
bool isLocal() const {
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 fileName;
int lineNumber;
@ -147,6 +157,13 @@ public:
*/
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.
* @param errmsg error message
@ -179,6 +196,12 @@ public:
*/
std::list<Suppression> getUnmatchedGlobalSuppressions(const bool unusedFunctionChecking) const;
/**
* @brief Returns list of all suppressions.
* @return list of suppressions
*/
std::list<Suppression> getSuppressions() const;
private:
/** @brief List of error which the user doesn't want to see. */
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
import json
import os
import re
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():
ret, stdout, stderr = cppcheck(['--inline-suppr', 'proj-inline-suppress'])
assert ret == 0
@ -31,3 +44,15 @@ def test_backwards_compatibility():
ret, stdout, stderr = cppcheck(['--inline-suppr', 'proj-inline-suppress/3.cpp'])
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 os
import shutil
import subprocess
# Create Cppcheck project file
@ -47,6 +48,14 @@ def cppcheck(args):
exe = '../../cppcheck.exe'
elif os.path.isfile('../../../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'):
exe = '../../cppcheck'
else:
@ -58,4 +67,3 @@ def cppcheck(args):
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')
return p.returncode, stdout, stderr