Fixed #3583 (False positive Variable X is assigned a value that is never used)
This commit is contained in:
parent
9431fb1b7e
commit
bbfae8e3ae
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue