diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 75b40e13f..167f6de48 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -128,6 +128,29 @@ static bool conditionIsFalse(const Token *condition, unsigned int varid, const V 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 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. * Example: ((x!=NULL) && (*x == 123)) @@ -558,6 +581,24 @@ static bool valueFlowForward(Token * const startToken, if (Token::Match(tok2, "sizeof|typeof|typeid (")) 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::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.. else if (Token::Match(tok2, "%var% (") && Token::simpleMatch(tok2->linkAt(1), ") {")) { // Should scope be skipped because variable value is checked? diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index bafa427d9..352b56546 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -778,6 +778,17 @@ private: "}"; 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 || code = "void f(int x) {\n" " a = (x != 3 ||\n"