ValueFlow: Improved analysis after condition when ! operator is used
This commit is contained in:
parent
b501708b6f
commit
847bb44bdd
|
@ -753,35 +753,61 @@ static void valueFlowAfterAssign(TokenList *tokenlist, ErrorLogger *errorLogger,
|
||||||
static void valueFlowAfterCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
static void valueFlowAfterCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||||
// Comparison
|
|
||||||
if (!tok->isComparisonOp() || !Token::Match(tok,"==|!=|>=|<="))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!tok->astOperand1() || !tok->astOperand2())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const Token *vartok, *numtok;
|
const Token *vartok, *numtok;
|
||||||
if (tok->astOperand1()->isName()) {
|
|
||||||
|
// Comparison
|
||||||
|
if (Token::Match(tok,"==|!=|>=|<=")) {
|
||||||
|
if (!tok->astOperand1() || !tok->astOperand2())
|
||||||
|
continue;
|
||||||
|
if (tok->astOperand1()->isName()) {
|
||||||
|
vartok = tok->astOperand1();
|
||||||
|
numtok = tok->astOperand2();
|
||||||
|
} else {
|
||||||
|
vartok = tok->astOperand2();
|
||||||
|
numtok = tok->astOperand1();
|
||||||
|
}
|
||||||
|
if (!vartok->isName() || !numtok->isNumber())
|
||||||
|
continue;
|
||||||
|
} else if (tok->str() == "!") {
|
||||||
vartok = tok->astOperand1();
|
vartok = tok->astOperand1();
|
||||||
numtok = tok->astOperand2();
|
numtok = nullptr;
|
||||||
|
if (!vartok || !vartok->isName())
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
vartok = tok->astOperand2();
|
|
||||||
numtok = tok->astOperand1();
|
|
||||||
}
|
|
||||||
if (!vartok->isName() || !numtok->isNumber())
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
const unsigned int varid = vartok->varId();
|
const unsigned int varid = vartok->varId();
|
||||||
if (varid == 0U)
|
if (varid == 0U)
|
||||||
continue;
|
continue;
|
||||||
const Variable *var = vartok->variable();
|
const Variable *var = vartok->variable();
|
||||||
if (!var || !(var->isLocal() || var->isArgument()))
|
if (!var || !(var->isLocal() || var->isArgument()))
|
||||||
continue;
|
continue;
|
||||||
std::list<ValueFlow::Value> values = numtok->values;
|
std::list<ValueFlow::Value> values;
|
||||||
|
values.push_back(ValueFlow::Value(tok, numtok ? MathLib::toLongNumber(numtok->str()) : 0LL));
|
||||||
|
|
||||||
const Token *top = tok->astTop();
|
const Token *top = tok->astTop();
|
||||||
if (top && Token::simpleMatch(top->previous(), "if (")) {
|
if (top && Token::simpleMatch(top->previous(), "if (")) {
|
||||||
|
// does condition reassign variable?
|
||||||
|
std::stack<const Token *> tokens;
|
||||||
|
tokens.push(top);
|
||||||
|
while (!tokens.empty()) {
|
||||||
|
const Token *tok2 = tokens.top();
|
||||||
|
tokens.pop();
|
||||||
|
if (!tok2)
|
||||||
|
continue;
|
||||||
|
tokens.push(tok2->astOperand1());
|
||||||
|
tokens.push(tok2->astOperand2());
|
||||||
|
if (tok2->str() == "=" && Token::Match(tok2->astOperand1(), "%varid%", varid))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!tokens.empty()) {
|
||||||
|
if (settings->debugwarnings)
|
||||||
|
bailout(tokenlist, errorLogger, tok, "assignment in condition");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Token *startToken = nullptr;
|
Token *startToken = nullptr;
|
||||||
if (Token::Match(tok, "==|>=|<=") && Token::simpleMatch(top->link(), ") {"))
|
if (Token::Match(tok, "==|>=|<=|!") && Token::simpleMatch(top->link(), ") {"))
|
||||||
startToken = top->link()->next();
|
startToken = top->link()->next();
|
||||||
else if (tok->str() == "!=" && Token::simpleMatch(top->link()->linkAt(1), "} else {"))
|
else if (tok->str() == "!=" && Token::simpleMatch(top->link()->linkAt(1), "} else {"))
|
||||||
startToken = top->link()->linkAt(1)->tokAt(2);
|
startToken = top->link()->linkAt(1)->tokAt(2);
|
||||||
|
|
|
@ -488,7 +488,8 @@ private:
|
||||||
" if (abc) {}\n"
|
" if (abc) {}\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: assignment of abc\n"
|
ASSERT_EQUALS("[test.cpp:2]: (debug) ValueFlow bailout: assignment of abc\n"
|
||||||
"[test.cpp:8]: (debug) ValueFlow bailout: variable abc stopping on goto label\n",
|
"[test.cpp:8]: (debug) ValueFlow bailout: variable abc stopping on goto label\n"
|
||||||
|
"[test.cpp:3]: (debug) ValueFlow bailout: variable abc. noreturn conditional scope.\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,6 +751,14 @@ private:
|
||||||
" else a = x;\n"
|
" else a = x;\n"
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS(true, testValueOfX(code, 3U, 123));
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 123));
|
||||||
|
|
||||||
|
// !
|
||||||
|
code = "void f(int x) {\n"
|
||||||
|
" if (!x) { a = x; }\n"
|
||||||
|
" else a = x;\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowBitAnd() {
|
void valueFlowBitAnd() {
|
||||||
|
|
Loading…
Reference in New Issue