parent
a79dff15ab
commit
a102ff3c2f
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue