Fixed #7965 (valueFlowForward: Improved handling of correlated variables)

This commit is contained in:
Daniel Marjamäki 2017-08-27 19:50:44 +02:00
parent 713f607168
commit 02a1b7cd2d
2 changed files with 65 additions and 7 deletions

View File

@ -154,17 +154,20 @@ static ProgramMemory getProgramMemory(const Token *tok, unsigned int varid, cons
if (Token::Match(tok2, "[;{}] %varid% = %var% ;", varid)) {
const Token *vartok = tok2->tokAt(3);
programMemory.setValue(vartok->varId(), value);
}
if (Token::Match(tok2, "[;{}] %var% =")) {
} else if (Token::Match(tok2, "[;{}] %var% =") ||
Token::Match(tok2, "[;{}] const| %type% %var% (")) {
const Token *vartok = tok2->next();
while (vartok->next()->isName())
vartok = vartok->next();
if (!programMemory.hasValue(vartok->varId())) {
MathLib::bigint result = 0;
bool error = false;
execute(tok2->tokAt(2)->astOperand2(), &programMemory, &result, &error);
execute(vartok->next()->astOperand2(), &programMemory, &result, &error);
if (!error)
programMemory.setIntValue(vartok->varId(), result);
}
}
if (tok2->str() == "{") {
if (indentlevel <= 0)
break;
@ -1296,6 +1299,9 @@ static bool valueFlowForward(Token * const startToken,
bool returnStatement = false; // current statement is a return, stop analysis at the ";"
bool read = false; // is variable value read?
if (values.empty())
return true;
for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
if (indentlevel >= 0 && tok2->str() == "{")
++indentlevel;
@ -1414,17 +1420,32 @@ static bool valueFlowForward(Token * const startToken,
}
const Token * const condTok = tok2->next()->astOperand2();
const bool condAlwaysTrue = (condTok && condTok->values().size() == 1U && condTok->values().front().isKnown() && condTok->values().front().intvalue != 0);
const bool condAlwaysTrue = (condTok && condTok->hasKnownIntValue() && condTok->values().front().intvalue != 0);
const bool condAlwaysFalse = (condTok && condTok->hasKnownIntValue() && condTok->values().front().intvalue == 0);
// Should scope be skipped because variable value is checked?
std::list<ValueFlow::Value> truevalues;
std::list<ValueFlow::Value> falsevalues;
for (std::list<ValueFlow::Value>::const_iterator it = values.begin(); it != values.end(); ++it) {
if (condAlwaysTrue)
if (condAlwaysTrue) {
truevalues.push_back(*it);
else if (subFunction && conditionIsTrue(condTok, getProgramMemory(tok2, varid, *it)))
continue;
}
if (condAlwaysFalse) {
falsevalues.push_back(*it);
continue;
}
const ProgramMemory &programMemory = getProgramMemory(tok2, varid, *it);
if (subFunction && conditionIsTrue(condTok, programMemory))
truevalues.push_back(*it);
else if (!subFunction && !conditionIsFalse(condTok, getProgramMemory(tok2, varid, *it)))
else if (!subFunction && !conditionIsFalse(condTok, programMemory))
truevalues.push_back(*it);
if (condAlwaysFalse)
falsevalues.push_back(*it);
else if (conditionIsFalse(condTok, programMemory))
falsevalues.push_back(*it);
else if (!subFunction && !conditionIsTrue(condTok, programMemory))
falsevalues.push_back(*it);
}
if (truevalues.size() != values.size() || condAlwaysTrue) {
// '{'
@ -1458,6 +1479,30 @@ static bool valueFlowForward(Token * const startToken,
removeValues(values, truevalues);
}
if (Token::simpleMatch(tok2, "} else {")) {
Token * const startTokenElse = tok2->tokAt(2);
valueFlowForward(startTokenElse->next(),
startTokenElse->link(),
var,
varid,
falsevalues,
constValue,
subFunction,
tokenlist,
errorLogger,
settings);
// goto '}'
tok2 = startTokenElse->link();
if (isReturnScope(tok2)) {
if (condAlwaysFalse)
return false;
removeValues(values, falsevalues);
}
}
continue;
}

View File

@ -77,6 +77,7 @@ private:
TEST_CASE(valueFlowAfterAssign);
TEST_CASE(valueFlowAfterCondition);
TEST_CASE(valueFlowForwardCompoundAssign);
TEST_CASE(valueFlowForwardCorrelatedVariables);
TEST_CASE(valueFlowSwitchVariable);
@ -1771,6 +1772,18 @@ private:
ASSERT_EQUALS(true, testValueOfX(code, 4U, 123.45 + 67, 0.01));
}
void valueFlowForwardCorrelatedVariables() {
const char *code;
code = "void f(int x = 0) {\n"
" bool zero(x==0);\n"
" if (zero) a = x;\n" // <- x is 0
" else b = x;\n" // <- x is not 0
"}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
ASSERT_EQUALS(false, testValueOfX(code, 4U, 0));
}
void valueFlowBitAnd() {
const char *code;