diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 90748fccc..2788663b6 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -271,3 +271,36 @@ bool isWithoutSideEffects(bool cpp, const Token* tok) return true; } +bool isVariableChanged(const Token *start, const Token *end, const unsigned int varid) +{ + for (const Token *tok = start; tok != end; tok = tok->next()) { + if (tok->varId() == varid) { + if (Token::Match(tok, "%name% =|++|--")) + return true; + + if (Token::Match(tok->previous(), "++|-- %name%")) + return true; + + if (Token::Match(tok->tokAt(-2), "[(,] & %var% [,)]")) + return true; // TODO: check if function parameter is const + + if (Token::Match(tok->previous(), "[(,] %var% [,)]")) { + const Token *parent = tok->astParent(); + while (parent && parent->str() == ",") + parent = parent->astParent(); + if (parent && parent->str() == "(") { + if (parent->astOperand1() && parent->astOperand1()->isName() && !parent->astOperand1()->function()) + return true; + // TODO: check if function parameter is non-const reference etc.. + } + } + + const Token *parent = tok->astParent(); + while (Token::Match(parent, ".|::")) + parent = parent->astParent(); + if (parent && parent->tokType() == Token::eIncDecOp) + return true; + } + } + return false; +} diff --git a/lib/astutils.h b/lib/astutils.h index b841cb9d8..ff9406a10 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -64,4 +64,7 @@ bool isConstExpression(const Token *tok, const std::set &constFunct bool isWithoutSideEffects(bool cpp, const Token* tok); +/** Is variable changed in block of code? */ +bool isVariableChanged(const Token *start, const Token *end, const unsigned int varid); + #endif // astutilsH diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp index 12fd8f86f..a0684b5f7 100644 --- a/lib/checkcondition.cpp +++ b/lib/checkcondition.cpp @@ -142,6 +142,13 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok, if (Token::Match(tok2, "if|while (")) { if (!islocal && tok2->str() == "while") continue; + if (tok2->str() == "while") { + // is variable changed in loop? + const Token *bodyStart = tok2->linkAt(1)->next(); + const Token *bodyEnd = bodyStart ? bodyStart->link() : nullptr; + if (!bodyEnd || bodyEnd->str() != "}" || isVariableChanged(bodyStart, bodyEnd, varid)) + continue; + } // parse condition const Token * const end = tok2->next()->link(); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index a6e3a06f1..7b02ac2b8 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -17,6 +17,7 @@ */ #include "valueflow.h" +#include "astutils.h" #include "errorlogger.h" #include "mathlib.h" #include "settings.h" @@ -321,40 +322,6 @@ static bool isReturn(const Token *tok) return false; } -static bool isVariableChanged(const Token *start, const Token *end, const unsigned int varid) -{ - for (const Token *tok = start; tok != end; tok = tok->next()) { - if (tok->varId() == varid) { - if (Token::Match(tok, "%name% =|++|--")) - return true; - - if (Token::Match(tok->previous(), "++|-- %name%")) - return true; - - if (Token::Match(tok->tokAt(-2), "[(,] & %var% [,)]")) - return true; // TODO: check if function parameter is const - - if (Token::Match(tok->previous(), "[(,] %var% [,)]")) { - const Token *parent = tok->astParent(); - while (parent && parent->str() == ",") - parent = parent->astParent(); - if (parent && parent->str() == "(") { - if (parent->astOperand1() && parent->astOperand1()->isName() && !parent->astOperand1()->function()) - return true; - // TODO: check if function parameter is non-const reference etc.. - } - } - - const Token *parent = tok->astParent(); - while (Token::Match(parent, ".|::")) - parent = parent->astParent(); - if (parent && parent->tokType() == Token::eIncDecOp) - return true; - } - } - return false; -} - /** Add token value. Return true if value is added. */ static bool addValue(Token *tok, const ValueFlow::Value &value) { diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 3a36e5b65..61e1c11ee 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -178,6 +178,15 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + check("void f(int x) {\n" + " int a = 100;\n" + " while (x) {\n" + " int y = 16 | a;\n" + " while (y != 0) y--;\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + // calling function check("void f(int x) {\n" " int y = x & 7;\n"