Fixed #7006 (False positive Mismatching assignment and comparison (variable is changed in loop))
This commit is contained in:
parent
00a47546f8
commit
b9b0964dab
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue