ValueFlow: Improved analysis after condition when ! operator is used

This commit is contained in:
Daniel Marjamäki 2014-06-16 16:39:41 +02:00
parent b501708b6f
commit 847bb44bdd
2 changed files with 51 additions and 16 deletions

View File

@ -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);

View File

@ -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() {