Fix #11485 FN unusedFunction / Fix #7739 FP unusedFunction (#4707)

This commit is contained in:
chrchr-github 2023-01-14 20:16:55 +01:00 committed by GitHub
parent a79dff15ab
commit a102ff3c2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 19 deletions

View File

@ -55,6 +55,13 @@ CheckUnusedFunctions CheckUnusedFunctions::instance;
static const struct CWE CWE561(561U); // Dead Code
static std::string stripTemplateParameters(const std::string& funcName) {
std::string name = funcName;
const auto pos = name.find('<');
if (pos > 0 && pos != std::string::npos)
name.erase(pos - 1);
return name;
}
//---------------------------------------------------------------------------
// FUNCTION USAGE - Check for unused functions etc
@ -78,13 +85,9 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
if (func->isExtern())
continue;
// Don't care about templates
if (tokenizer.isCPP() && func->templateDef != nullptr)
continue;
mFunctionDecl.emplace_back(func);
FunctionUsage &usage = mFunctions[func->name()];
FunctionUsage &usage = mFunctions[stripTemplateParameters(func->name())];
if (!usage.lineNumber)
usage.lineNumber = func->token->linenr();
@ -223,11 +226,11 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
while (Token::Match(funcname, "%name% :: %name%"))
funcname = funcname->tokAt(2);
if (!Token::Match(funcname, "%name% [(),;]:}>]"))
if (!Token::Match(funcname, "%name% [(),;]:}>]") || funcname->varId())
continue;
}
if (!funcname)
if (!funcname || funcname->isKeyword() || funcname->isStandardType())
continue;
// funcname ( => Assert that the end parentheses isn't followed by {
@ -240,7 +243,8 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
}
if (funcname) {
FunctionUsage &func = mFunctions[funcname->str()];
const auto baseName = stripTemplateParameters(funcname->str());
FunctionUsage &func = mFunctions[baseName];
const std::string& called_from_file = tokenizer.list.getSourceFilePath();
if (func.filename.empty() || func.filename == "+" || func.filename != called_from_file)
@ -248,7 +252,7 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const char Fi
else
func.usedSameFile = true;
mFunctionCalls.insert(funcname->str());
mFunctionCalls.insert(baseName);
}
}
}

View File

@ -255,16 +255,6 @@ struct ForwardTraversal {
return traverseRecursive(tok, f, false);
}
template<class T, class F>
T* findRange(T* start, const Token* end, F pred) {
for (T* tok = start; tok && tok != end; tok = tok->next()) {
Analyzer::Action action = analyzer->analyze(tok, Analyzer::Direction::Forward);
if (pred(action))
return tok;
}
return nullptr;
}
Analyzer::Action analyzeRecursive(const Token* start) {
Analyzer::Action result = Analyzer::Action::None;
auto f = [&](const Token* tok) {

View File

@ -68,6 +68,7 @@ Token::~Token()
* e.g. for the sequence of tokens A B C D E, C.until(E) would yield the Range C D
* note t can be nullptr to iterate all the way to the end.
*/
// cppcheck-suppress unusedFunction // only used in testtokenrange.cpp
ConstTokenRange Token::until(const Token* t) const
{
return ConstTokenRange(this, t);

View File

@ -50,6 +50,8 @@ private:
TEST_CASE(template5);
TEST_CASE(template6); // #10475 crash
TEST_CASE(template7); // #9766 crash
TEST_CASE(template8);
TEST_CASE(template9);
TEST_CASE(throwIsNotAFunction);
TEST_CASE(unusedError);
TEST_CASE(unusedMain);
@ -282,6 +284,50 @@ private:
ASSERT_EQUALS("[test.cpp:1]: (style) The function 'f' is never used.\n", errout.str());
}
void template8() { // #11485
check("struct S {\n"
" template<typename T>\n"
" void tf(const T&) { }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:3]: (style) The function 'tf' is never used.\n", errout.str());
check("struct S {\n"
" template<typename T>\n"
" void tf(const T&) { }\n"
"};\n"
"int main() {\n"
" C c;\n"
" c.tf(1.5);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("struct S {\n"
" template<typename T>\n"
" void tf(const T&) { }\n"
"};\n"
"int main() {\n"
" C c;\n"
" c.tf<int>(1);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void template9() { // #7739
check("template<class T>\n"
"void f(T const& t) {}\n"
"template<class T>\n"
"void g(T const& t) {\n"
" f(t);\n"
"}\n"
"template<>\n"
"void f<double>(double const& d) {}\n"
"int main() {\n"
" g(2);\n"
" g(3.14);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void throwIsNotAFunction() {
check("struct A {void f() const throw () {}}; int main() {A a; a.f();}");
ASSERT_EQUALS("", errout.str());