Fix #9567 (Inline suppression of unusedFunction errors not working when using compile database) (#2870)
This commit is contained in:
parent
05b804d126
commit
f70e8de315
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "B.hpp"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
B b();
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "B.hpp"
|
||||||
|
|
||||||
|
B::B() {}
|
||||||
|
|
||||||
|
// cppcheck-suppress unusedFunction
|
||||||
|
void B::unusedFunctionTest() {}
|
|
@ -0,0 +1,6 @@
|
||||||
|
class B {
|
||||||
|
public:
|
||||||
|
B();
|
||||||
|
|
||||||
|
void unusedFunctionTest();
|
||||||
|
};
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue