Fixed #3583 (False positive Variable X is assigned a value that is never used)

This commit is contained in:
Daniel Marjamäki 2012-02-25 12:56:33 +01:00
parent 9431fb1b7e
commit bbfae8e3ae
2 changed files with 55 additions and 46 deletions

View File

@ -584,52 +584,52 @@ static const Token * skipBrackets(const Token *tok)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables) void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables)
{ {
if (scope->type == Scope::eClass || scope->type == Scope::eUnion || scope->type == Scope::eStruct) // Find declarations if the scope is executable..
return; if (scope->type != Scope::eClass && scope->type != Scope::eUnion && scope->type != Scope::eStruct) {
// Find declarations
// Find declarations for (std::list<Variable>::const_iterator i = scope->varlist.begin(); i != scope->varlist.end(); ++i) {
for (std::list<Variable>::const_iterator i = scope->varlist.begin(); i != scope->varlist.end(); ++i) { Variables::VariableType type = Variables::none;
Variables::VariableType type = Variables::none; if (i->isArray() && (i->nameToken()->previous()->str() == "*" || i->nameToken()->strAt(-2) == "*"))
if (i->isArray() && (i->nameToken()->previous()->str() == "*" || i->nameToken()->strAt(-2) == "*")) type = Variables::pointerArray;
type = Variables::pointerArray; else if (i->isArray() && i->nameToken()->previous()->str() == "&")
else if (i->isArray() && i->nameToken()->previous()->str() == "&") type = Variables::referenceArray;
type = Variables::referenceArray; else if (i->isArray())
else if (i->isArray()) type = Variables::array;
type = Variables::array; else if (i->isReference())
else if (i->isReference()) type = Variables::reference;
type = Variables::reference; else if (i->nameToken()->previous()->str() == "*" && i->nameToken()->strAt(-2) == "*")
else if (i->nameToken()->previous()->str() == "*" && i->nameToken()->strAt(-2) == "*") type = Variables::pointerPointer;
type = Variables::pointerPointer; else if (i->isPointer())
else if (i->isPointer()) type = Variables::pointer;
type = Variables::pointer; else if (i->typeEndToken()->isStandardType() || isRecordTypeWithoutSideEffects(*i) || Token::simpleMatch(i->nameToken()->tokAt(-3), "std :: string"))
else if (i->typeEndToken()->isStandardType() || isRecordTypeWithoutSideEffects(*i) || Token::simpleMatch(i->nameToken()->tokAt(-3), "std :: string")) type = Variables::standard;
type = Variables::standard; if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken()))
if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken())) continue;
continue; const Token* defValTok = i->nameToken()->next();
const Token* defValTok = i->nameToken()->next(); for (; defValTok; defValTok = defValTok->next()) {
for (; defValTok; defValTok = defValTok->next()) { if (defValTok->str() == "[")
if (defValTok->str() == "[") defValTok = defValTok->link();
defValTok = defValTok->link(); else if (defValTok->str() == "(" || defValTok->str() == "=") {
else if (defValTok->str() == "(" || defValTok->str() == "=") { variables.addVar(i->nameToken(), type, scope, true);
variables.addVar(i->nameToken(), type, scope, true); break;
break; } else if (defValTok->str() == ";" || defValTok->str() == "," || defValTok->str() == ")") {
} else if (defValTok->str() == ";" || defValTok->str() == "," || defValTok->str() == ")") { variables.addVar(i->nameToken(), type, scope, i->isStatic());
variables.addVar(i->nameToken(), type, scope, i->isStatic()); break;
break; }
} }
} if (i->isArray() && Token::Match(i->nameToken(), "%var% [ %var% ]")) // Array index variable read.
if (i->isArray() && Token::Match(i->nameToken(), "%var% [ %var% ]")) // Array index variable read. variables.read(i->nameToken()->tokAt(2)->varId());
variables.read(i->nameToken()->tokAt(2)->varId());
if (defValTok && defValTok->str() == "=") { if (defValTok && defValTok->str() == "=") {
if (defValTok->next() && defValTok->next()->str() == "{") { if (defValTok->next() && defValTok->next()->str() == "{") {
for (const Token* tok = defValTok; tok && tok != defValTok->linkAt(1); tok = tok->next()) for (const Token* tok = defValTok; tok && tok != defValTok->linkAt(1); tok = tok->next())
if (Token::Match(tok, "%var%")) // Variables used to initialize the array read. if (Token::Match(tok, "%var%")) // Variables used to initialize the array read.
variables.read(tok->varId()); variables.read(tok->varId());
} else } else
doAssignment(variables, i->nameToken(), false, scope); doAssignment(variables, i->nameToken(), false, scope);
} else if (Token::Match(defValTok, "( %var% )")) // Variables used to initialize the variable read. } else if (Token::Match(defValTok, "( %var% )")) // Variables used to initialize the variable read.
variables.readAll(defValTok->next()->varId()); // ReadAll? variables.readAll(defValTok->next()->varId()); // ReadAll?
}
} }
// Check variable usage // Check variable usage

View File

@ -107,7 +107,8 @@ private:
TEST_CASE(localvararray2); // ticket #3438 TEST_CASE(localvararray2); // ticket #3438
TEST_CASE(localvarstring1); TEST_CASE(localvarstring1);
TEST_CASE(localvarstring2); // ticket #2929 TEST_CASE(localvarstring2); // ticket #2929
TEST_CASE(localvarconst); TEST_CASE(localvarconst1);
TEST_CASE(localvarconst2);
// Don't give false positives for variables in structs/unions // Don't give false positives for variables in structs/unions
TEST_CASE(localvarStruct1); TEST_CASE(localvarStruct1);
@ -2971,13 +2972,21 @@ private:
"[test.cpp:3]: (style) Unused variable: i\n", errout.str()); "[test.cpp:3]: (style) Unused variable: i\n", errout.str());
} }
void localvarconst() { void localvarconst1() {
functionVariableUsage("void foo() {\n" functionVariableUsage("void foo() {\n"
" const bool b = true;\n" " const bool b = true;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'b' is assigned a value that is never used\n", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'b' is assigned a value that is never used\n", errout.str());
} }
void localvarconst2() {
functionVariableUsage("void foo() {\n"
" const int N = 10;\n"
" struct X { int x[N]; };\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
// ticket #3104 - false positive when variable is read with "if (NOT var)" // ticket #3104 - false positive when variable is read with "if (NOT var)"
void localvarIfNOT() { void localvarIfNOT() {
functionVariableUsage("void f() {\n" functionVariableUsage("void f() {\n"