Fixed #5947 (valueFlowForward: forward conditions not handled properly)
This commit is contained in:
parent
d19b6f181d
commit
5af96c2dd8
|
@ -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?
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue