diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 77662060b..84c75fd14 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -770,7 +770,6 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const break; } - // bailout when for_each is used if (Token::Match(tok, "%name% (") && Token::simpleMatch(tok->linkAt(1), ") {") && !Token::Match(tok, "if|for|while|switch")) { // does the name contain "for_each" or "foreach"? @@ -861,9 +860,6 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const } } - else if (Token::Match(tok->tokAt(-2), "while|if") && tok->strAt(1) == "=" && tok->varId() && tok->varId() == tok->tokAt(2)->varId()) { - variables.use(tok->tokAt(2)->varId(), tok); - } // assignment else if (Token::Match(tok, "*| ++|--| %name% ++|--| %assign%") || Token::Match(tok, "*| ( const| %type% *| ) %name% %assign%")) { @@ -893,6 +889,17 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const const unsigned int varid1 = tok->varId(); const Token * const start = tok; + // assignment in while head.. + bool inwhile = false; + { + const Token *parent = tok->astParent(); + while (parent) { + if (Token::simpleMatch(parent->previous(), "while (")) + inwhile = true; + parent = parent->astParent(); + } + } + tok = doAssignment(variables, tok, dereference, scope); if (tok && tok->isAssignmentOp() && tok->str() != "=") { @@ -914,7 +921,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const variables.read(varid1, tok); } else { Variables::VariableUsage *var = variables.find(varid1); - if (var && start->strAt(-1) == ",") { + if (var && (inwhile || start->strAt(-1) == ",")) { variables.use(varid1, tok); } else if (var && var->_type == Variables::reference) { variables.writeAliases(varid1, tok); diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 974ba22d5..8b0377f0e 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -144,7 +144,6 @@ private: TEST_CASE(localvarFor); // for ( ; var; ) TEST_CASE(localvarForEach); // #4155 - BOOST_FOREACH, hlist_for_each, etc TEST_CASE(localvarShift1); // 1 >> var - TEST_CASE(localvarShift2); // x = x >> 1 TEST_CASE(localvarShift3); // x << y TEST_CASE(localvarCast); TEST_CASE(localvarClass); @@ -156,6 +155,7 @@ private: TEST_CASE(localvarNULL); // #4203 - Setting NULL value is not redundant - it is safe TEST_CASE(localvarUnusedGoto); // #4447, #4558 goto TEST_CASE(localvarRangeBasedFor); // #7075 + TEST_CASE(localvarAssignInWhile); TEST_CASE(localvarCpp11Initialization); @@ -3238,15 +3238,6 @@ private: ASSERT_EQUALS("", errout.str()); } - void localvarShift2() { - functionVariableUsage("int foo()\n" - "{\n" - " int var = 1;\n" - " while (var = var >> 1) { }\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - void localvarShift3() { // #3509 functionVariableUsage("int foo()\n" "{\n" @@ -3859,6 +3850,22 @@ private: ASSERT_EQUALS("", errout.str()); } + void localvarAssignInWhile() { + functionVariableUsage("void foo() {\n" + " int a = 0;\n" + " do {\n" + " dostuff(a);\n" + " } while((a + = x) < 30);\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + functionVariableUsage("int foo() {\n" + " int var = 1;\n" + " while (var = var >> 1) { }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + void chainedAssignment() { // #5466 functionVariableUsage("void NotUsed(double* pdD, int n) {\n"