Fixed #5947 (valueFlowForward: forward conditions not handled properly)

This commit is contained in:
Daniel Marjamäki 2014-06-25 16:00:56 +02:00
parent d19b6f181d
commit 5af96c2dd8
2 changed files with 52 additions and 0 deletions

View File

@ -128,6 +128,29 @@ static bool conditionIsFalse(const Token *condition, unsigned int varid, const V
return !error && result == 0; return !error && result == 0;
} }
/**
* Is condition always true when variable has given value?
* \param condition top ast token in condition
* \param varid variable id for variable
* \param value value of variable
*/
static bool conditionIsTrue(const Token *condition, unsigned int varid, const ValueFlow::Value &value)
{
if (!condition)
return false;
if (condition->str() == "||") {
bool result1 = conditionIsTrue(condition->astOperand1(), varid, value);
bool result2 = result1 ? true : conditionIsTrue(condition->astOperand2(), varid, value);
return result2;
}
std::map<unsigned int, MathLib::bigint> programMemory;
programMemory[varid] = value.intvalue;
MathLib::bigint result = 0;
bool error = false;
execute(condition, &programMemory, &result, &error);
return !error && result == 1;
}
/** /**
* Should value be skipped because it's hidden inside && || or ?: expression. * Should value be skipped because it's hidden inside && || or ?: expression.
* Example: ((x!=NULL) && (*x == 123)) * Example: ((x!=NULL) && (*x == 123))
@ -558,6 +581,24 @@ static bool valueFlowForward(Token * const startToken,
if (Token::Match(tok2, "sizeof|typeof|typeid (")) if (Token::Match(tok2, "sizeof|typeof|typeid ("))
tok2 = tok2->linkAt(1); tok2 = tok2->linkAt(1);
else if (Token::simpleMatch(tok2, "else {")) {
// Should scope be skipped because variable value is checked?
bool skipelse = false;
const Token *condition = tok2->linkAt(-1);
condition = condition ? condition->linkAt(-1) : nullptr;
condition = condition ? condition->astOperand2() : nullptr;
for (std::list<ValueFlow::Value>::iterator it = values.begin(); it != values.end(); ++it) {
if (conditionIsTrue(condition, varid, *it)) {
skipelse = true;
break;
}
}
if (skipelse) {
tok2 = tok2->linkAt(1);
continue;
}
}
// conditional block of code that assigns variable.. // conditional block of code that assigns variable..
else if (Token::Match(tok2, "%var% (") && Token::simpleMatch(tok2->linkAt(1), ") {")) { else if (Token::Match(tok2, "%var% (") && Token::simpleMatch(tok2->linkAt(1), ") {")) {
// Should scope be skipped because variable value is checked? // Should scope be skipped because variable value is checked?

View File

@ -778,6 +778,17 @@ private:
"}"; "}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 3)); ASSERT_EQUALS(true, testValueOfX(code, 3U, 3));
// conditional code after if/else/while
code = "void f(int x) {\n"
" if (x == 2) {}\n"
" if (x > 0)\n"
" a = x;\n"
" else\n"
" b = x;\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code, 4U, 2));
ASSERT_EQUALS(false, testValueOfX(code, 6U, 2));
// In condition, after && and || // In condition, after && and ||
code = "void f(int x) {\n" code = "void f(int x) {\n"
" a = (x != 3 ||\n" " a = (x != 3 ||\n"