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";
|
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()
|
void CheckOther::functionVariableUsage()
|
||||||
{
|
{
|
||||||
if (!_settings->_checkCodingStyle)
|
if (!_settings->_checkCodingStyle)
|
||||||
|
@ -1738,7 +1753,7 @@ void CheckOther::functionVariableUsage()
|
||||||
// standard type declaration with possible initialization
|
// standard type declaration with possible initialization
|
||||||
// int i; int j = 0; static int k;
|
// int i; int j = 0; static int k;
|
||||||
if (Token::Match(tok, "[;{}] static| %type% %var% ;|=") &&
|
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();
|
tok = tok->next();
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,9 @@ public:
|
||||||
/** @brief %Check for suspicious code that compares string literals for equality */
|
/** @brief %Check for suspicious code that compares string literals for equality */
|
||||||
void checkAlwaysTrueOrFalseStringCompare();
|
void checkAlwaysTrueOrFalseStringCompare();
|
||||||
|
|
||||||
|
/** @brief check if token is a record type without side effects */
|
||||||
|
bool isRecordTypeWithoutSideEffects(const Token *tok);
|
||||||
|
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void cstyleCastError(const Token *tok);
|
void cstyleCastError(const Token *tok);
|
||||||
void dangerousUsageStrtolError(const Token *tok);
|
void dangerousUsageStrtolError(const Token *tok);
|
||||||
|
|
|
@ -104,6 +104,7 @@ private:
|
||||||
TEST_CASE(localvarStruct2);
|
TEST_CASE(localvarStruct2);
|
||||||
TEST_CASE(localvarStruct3);
|
TEST_CASE(localvarStruct3);
|
||||||
TEST_CASE(localvarStruct4); // Ticket #31: sigsegv on incomplete struct
|
TEST_CASE(localvarStruct4); // Ticket #31: sigsegv on incomplete struct
|
||||||
|
TEST_CASE(localvarStruct5);
|
||||||
|
|
||||||
TEST_CASE(localvarOp); // Usage with arithmetic operators
|
TEST_CASE(localvarOp); // Usage with arithmetic operators
|
||||||
TEST_CASE(localvarInvert); // Usage with inverted variable
|
TEST_CASE(localvarInvert); // Usage with inverted variable
|
||||||
|
@ -2348,6 +2349,107 @@ private:
|
||||||
" struct { \n");
|
" 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()
|
void localvarOp()
|
||||||
{
|
{
|
||||||
const char op[] = "+-*/%&|^";
|
const char op[] = "+-*/%&|^";
|
||||||
|
|
Loading…
Reference in New Issue