Fixed #7006 (False positive Mismatching assignment and comparison (variable is changed in loop))

This commit is contained in:
Daniel Marjamäki 2015-11-11 13:45:28 +01:00
parent 00a47546f8
commit b9b0964dab
5 changed files with 53 additions and 34 deletions

View File

@ -271,3 +271,36 @@ bool isWithoutSideEffects(bool cpp, const Token* tok)
return true; 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;
}

View File

@ -64,4 +64,7 @@ bool isConstExpression(const Token *tok, const std::set<std::string> &constFunct
bool isWithoutSideEffects(bool cpp, const Token* tok); 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 #endif // astutilsH

View File

@ -142,6 +142,13 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok,
if (Token::Match(tok2, "if|while (")) { if (Token::Match(tok2, "if|while (")) {
if (!islocal && tok2->str() == "while") if (!islocal && tok2->str() == "while")
continue; 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 // parse condition
const Token * const end = tok2->next()->link(); const Token * const end = tok2->next()->link();

View File

@ -17,6 +17,7 @@
*/ */
#include "valueflow.h" #include "valueflow.h"
#include "astutils.h"
#include "errorlogger.h" #include "errorlogger.h"
#include "mathlib.h" #include "mathlib.h"
#include "settings.h" #include "settings.h"
@ -321,40 +322,6 @@ static bool isReturn(const Token *tok)
return false; 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. */ /** Add token value. Return true if value is added. */
static bool addValue(Token *tok, const ValueFlow::Value &value) static bool addValue(Token *tok, const ValueFlow::Value &value)
{ {

View File

@ -178,6 +178,15 @@ private:
"}"); "}");
ASSERT_EQUALS("", errout.str()); 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 // calling function
check("void f(int x) {\n" check("void f(int x) {\n"
" int y = x & 7;\n" " int y = x & 7;\n"