Fixed #7965 (valueFlowForward: Improved handling of correlated variables)
This commit is contained in:
parent
713f607168
commit
02a1b7cd2d
|
@ -154,17 +154,20 @@ static ProgramMemory getProgramMemory(const Token *tok, unsigned int varid, cons
|
||||||
if (Token::Match(tok2, "[;{}] %varid% = %var% ;", varid)) {
|
if (Token::Match(tok2, "[;{}] %varid% = %var% ;", varid)) {
|
||||||
const Token *vartok = tok2->tokAt(3);
|
const Token *vartok = tok2->tokAt(3);
|
||||||
programMemory.setValue(vartok->varId(), value);
|
programMemory.setValue(vartok->varId(), value);
|
||||||
}
|
} else if (Token::Match(tok2, "[;{}] %var% =") ||
|
||||||
if (Token::Match(tok2, "[;{}] %var% =")) {
|
Token::Match(tok2, "[;{}] const| %type% %var% (")) {
|
||||||
const Token *vartok = tok2->next();
|
const Token *vartok = tok2->next();
|
||||||
|
while (vartok->next()->isName())
|
||||||
|
vartok = vartok->next();
|
||||||
if (!programMemory.hasValue(vartok->varId())) {
|
if (!programMemory.hasValue(vartok->varId())) {
|
||||||
MathLib::bigint result = 0;
|
MathLib::bigint result = 0;
|
||||||
bool error = false;
|
bool error = false;
|
||||||
execute(tok2->tokAt(2)->astOperand2(), &programMemory, &result, &error);
|
execute(vartok->next()->astOperand2(), &programMemory, &result, &error);
|
||||||
if (!error)
|
if (!error)
|
||||||
programMemory.setIntValue(vartok->varId(), result);
|
programMemory.setIntValue(vartok->varId(), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok2->str() == "{") {
|
if (tok2->str() == "{") {
|
||||||
if (indentlevel <= 0)
|
if (indentlevel <= 0)
|
||||||
break;
|
break;
|
||||||
|
@ -1296,6 +1299,9 @@ static bool valueFlowForward(Token * const startToken,
|
||||||
bool returnStatement = false; // current statement is a return, stop analysis at the ";"
|
bool returnStatement = false; // current statement is a return, stop analysis at the ";"
|
||||||
bool read = false; // is variable value read?
|
bool read = false; // is variable value read?
|
||||||
|
|
||||||
|
if (values.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
|
for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
|
||||||
if (indentlevel >= 0 && tok2->str() == "{")
|
if (indentlevel >= 0 && tok2->str() == "{")
|
||||||
++indentlevel;
|
++indentlevel;
|
||||||
|
@ -1414,17 +1420,32 @@ static bool valueFlowForward(Token * const startToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token * const condTok = tok2->next()->astOperand2();
|
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?
|
// Should scope be skipped because variable value is checked?
|
||||||
std::list<ValueFlow::Value> truevalues;
|
std::list<ValueFlow::Value> truevalues;
|
||||||
|
std::list<ValueFlow::Value> falsevalues;
|
||||||
for (std::list<ValueFlow::Value>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
for (std::list<ValueFlow::Value>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
||||||
if (condAlwaysTrue)
|
if (condAlwaysTrue) {
|
||||||
truevalues.push_back(*it);
|
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);
|
truevalues.push_back(*it);
|
||||||
else if (!subFunction && !conditionIsFalse(condTok, getProgramMemory(tok2, varid, *it)))
|
else if (!subFunction && !conditionIsFalse(condTok, programMemory))
|
||||||
truevalues.push_back(*it);
|
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) {
|
if (truevalues.size() != values.size() || condAlwaysTrue) {
|
||||||
// '{'
|
// '{'
|
||||||
|
@ -1458,6 +1479,30 @@ static bool valueFlowForward(Token * const startToken,
|
||||||
removeValues(values, truevalues);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@ private:
|
||||||
TEST_CASE(valueFlowAfterAssign);
|
TEST_CASE(valueFlowAfterAssign);
|
||||||
TEST_CASE(valueFlowAfterCondition);
|
TEST_CASE(valueFlowAfterCondition);
|
||||||
TEST_CASE(valueFlowForwardCompoundAssign);
|
TEST_CASE(valueFlowForwardCompoundAssign);
|
||||||
|
TEST_CASE(valueFlowForwardCorrelatedVariables);
|
||||||
|
|
||||||
TEST_CASE(valueFlowSwitchVariable);
|
TEST_CASE(valueFlowSwitchVariable);
|
||||||
|
|
||||||
|
@ -1771,6 +1772,18 @@ private:
|
||||||
ASSERT_EQUALS(true, testValueOfX(code, 4U, 123.45 + 67, 0.01));
|
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() {
|
void valueFlowBitAnd() {
|
||||||
const char *code;
|
const char *code;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue