add support for detecting unused function variables of type class or struct
This commit is contained in:
parent
6d4799e0b8
commit
7826b5e22d
|
@ -1671,6 +1671,21 @@ static bool nextIsStandardTypeOrVoid(const Token *tok)
|
|||
return tok->isStandardType() || tok->str() == "void";
|
||||
}
|
||||
|
||||
bool CheckOther::isRecordTypeWithoutSideEffects(const Token *tok)
|
||||
{
|
||||
const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok->varId());
|
||||
|
||||
// a type that has no side effects (no constructors and no members with constructors)
|
||||
/** @todo false negative: check base class for side effects */
|
||||
/** @todo false negative: check constructors for side effects */
|
||||
if (var && var->type() && var->type()->numConstructors == 0 &&
|
||||
(var->type()->varlist.empty() || var->type()->needInitialization == Scope::True) &&
|
||||
var->type()->derivedFrom.empty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CheckOther::functionVariableUsage()
|
||||
{
|
||||
if (!_settings->_checkCodingStyle)
|
||||
|
@ -1738,7 +1753,7 @@ void CheckOther::functionVariableUsage()
|
|||
// standard type declaration with possible initialization
|
||||
// int i; int j = 0; static int k;
|
||||
if (Token::Match(tok, "[;{}] static| %type% %var% ;|=") &&
|
||||
nextIsStandardType(tok))
|
||||
(nextIsStandardType(tok) || isRecordTypeWithoutSideEffects(tok->strAt(1) == "static" ? tok->tokAt(3) : tok->tokAt(2))))
|
||||
{
|
||||
tok = tok->next();
|
||||
|
||||
|
|
|
@ -224,6 +224,9 @@ public:
|
|||
/** @brief %Check for suspicious code that compares string literals for equality */
|
||||
void checkAlwaysTrueOrFalseStringCompare();
|
||||
|
||||
/** @brief check if token is a record type without side effects */
|
||||
bool isRecordTypeWithoutSideEffects(const Token *tok);
|
||||
|
||||
// Error messages..
|
||||
void cstyleCastError(const Token *tok);
|
||||
void dangerousUsageStrtolError(const Token *tok);
|
||||
|
|
|
@ -104,6 +104,7 @@ private:
|
|||
TEST_CASE(localvarStruct2);
|
||||
TEST_CASE(localvarStruct3);
|
||||
TEST_CASE(localvarStruct4); // Ticket #31: sigsegv on incomplete struct
|
||||
TEST_CASE(localvarStruct5);
|
||||
|
||||
TEST_CASE(localvarOp); // Usage with arithmetic operators
|
||||
TEST_CASE(localvarInvert); // Usage with inverted variable
|
||||
|
@ -2348,6 +2349,107 @@ private:
|
|||
" struct { \n");
|
||||
}
|
||||
|
||||
void localvarStruct5()
|
||||
{
|
||||
functionVariableUsage("int foo() {\n"
|
||||
" A a;\n"
|
||||
" return a.i;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("int foo() {\n"
|
||||
" A a;\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("struct A { int i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" return a.i;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("class A { int i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" return a.i;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("struct A { int i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" a.i = 0;\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("class A { int i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" a.i = 0;\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("struct A { int i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a = { 0 };\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
|
||||
|
||||
functionVariableUsage("class A { int i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a = { 0 };\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used\n", errout.str());
|
||||
|
||||
functionVariableUsage("class A { int i; public: A(); { } };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("struct A { int i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: a\n", errout.str());
|
||||
|
||||
functionVariableUsage("class A { int i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: a\n", errout.str());
|
||||
|
||||
functionVariableUsage("class A { int i; public: A(); { } };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("class A { unknown i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
functionVariableUsage("class A : public Fred { int i; };\n"
|
||||
"int foo() {\n"
|
||||
" A a;\n"
|
||||
" return 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void localvarOp()
|
||||
{
|
||||
const char op[] = "+-*/%&|^";
|
||||
|
|
Loading…
Reference in New Issue