ValueFlow: better handling of ? when condition result is known

This commit is contained in:
Daniel Marjamäki 2016-08-15 14:19:35 +02:00
parent 453b5577cd
commit 1f98af654a
3 changed files with 52 additions and 26 deletions

View File

@ -363,33 +363,42 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value)
} }
else if (parent->str() == "?" && tok->str() == ":" && tok == parent->astOperand2()) { else if (parent->str() == "?" && tok->str() == ":" && tok == parent->astOperand2()) {
// is condition only depending on 1 variable? // is condition always true/false?
std::stack<const Token*> tokens; if (parent->astOperand1()->values.size() == 1U && parent->astOperand1()->values.front().isKnown()) {
tokens.push(parent->astOperand1()); const ValueFlow::Value &condvalue = parent->astOperand1()->values.front();
unsigned int varId = 0; const bool cond(condvalue.tokvalue || condvalue.intvalue != 0);
while (!tokens.empty()) { const std::list<ValueFlow::Value> &values = cond ? tok->astOperand1()->values : tok->astOperand2()->values;
const Token *t = tokens.top(); if (std::find(values.begin(), values.end(), value) != values.end())
tokens.pop(); setTokenValue(parent, value);
if (!t) } else {
continue; // is condition only depending on 1 variable?
tokens.push(t->astOperand1()); std::stack<const Token*> tokens;
tokens.push(t->astOperand2()); tokens.push(parent->astOperand1());
if (t->varId()) { unsigned int varId = 0;
if (varId > 0 || value.varId != 0U) while (!tokens.empty()) {
return; const Token *t = tokens.top();
varId = t->varId(); tokens.pop();
} else if (t->str() == "(" && Token::Match(t->previous(), "%name%")) if (!t)
return; // function call continue;
tokens.push(t->astOperand1());
tokens.push(t->astOperand2());
if (t->varId()) {
if (varId > 0 || value.varId != 0U)
return;
varId = t->varId();
} else if (t->str() == "(" && Token::Match(t->previous(), "%name%"))
return; // function call
}
ValueFlow::Value v(value);
v.conditional = true;
v.changeKnownToPossible();
if (varId)
v.varId = varId;
setTokenValue(parent, v);
} }
ValueFlow::Value v(value);
v.conditional = true;
v.changeKnownToPossible();
if (varId)
v.varId = varId;
setTokenValue(parent, v);
} }
// Calculations.. // Calculations..

View File

@ -36,6 +36,18 @@ namespace ValueFlow {
explicit Value(long long val = 0) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(0), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {} explicit Value(long long val = 0) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(0), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {}
Value(const Token *c, long long val) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(c), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {} Value(const Token *c, long long val) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(c), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {}
bool operator==(const Value &rhs) const {
return intvalue == rhs.intvalue &&
tokvalue == rhs.tokvalue &&
varvalue == rhs.varvalue &&
condition == rhs.condition &&
varId == rhs.varId &&
conditional == rhs.conditional &&
inconclusive == rhs.inconclusive &&
defaultArg == rhs.defaultArg &&
valueKind == rhs.valueKind;
}
/** int value */ /** int value */
long long intvalue; long long intvalue;

View File

@ -327,6 +327,11 @@ private:
ASSERT_EQUALS(2, values.front().intvalue); ASSERT_EQUALS(2, values.front().intvalue);
ASSERT_EQUALS(3, values.back().intvalue); ASSERT_EQUALS(3, values.back().intvalue);
code = "x = (2<5) ? 2 : 3;\n";
values = tokenValues(code, "?");
ASSERT_EQUALS(1U, values.size());
ASSERT_EQUALS(2, values.front().intvalue);
// ! // !
code = "void f(int x) {\n" code = "void f(int x) {\n"
" a = !x;\n" " a = !x;\n"