diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 064a110df..fed2be696 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -363,33 +363,42 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value) } else if (parent->str() == "?" && tok->str() == ":" && tok == parent->astOperand2()) { - // is condition only depending on 1 variable? - std::stack tokens; - tokens.push(parent->astOperand1()); - unsigned int varId = 0; - while (!tokens.empty()) { - const Token *t = tokens.top(); - tokens.pop(); - if (!t) - 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 + // is condition always true/false? + if (parent->astOperand1()->values.size() == 1U && parent->astOperand1()->values.front().isKnown()) { + const ValueFlow::Value &condvalue = parent->astOperand1()->values.front(); + const bool cond(condvalue.tokvalue || condvalue.intvalue != 0); + const std::list &values = cond ? tok->astOperand1()->values : tok->astOperand2()->values; + if (std::find(values.begin(), values.end(), value) != values.end()) + setTokenValue(parent, value); + } else { + // is condition only depending on 1 variable? + std::stack tokens; + tokens.push(parent->astOperand1()); + unsigned int varId = 0; + while (!tokens.empty()) { + const Token *t = tokens.top(); + tokens.pop(); + if (!t) + 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.. diff --git a/lib/valueflow.h b/lib/valueflow.h index 908c98b32..ecad5bb08 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -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) {} 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 */ long long intvalue; diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 9d85f9a37..6626573bc 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -327,6 +327,11 @@ private: ASSERT_EQUALS(2, values.front().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" " a = !x;\n"