diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index dd6abfaee..32582c6b0 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -92,6 +92,8 @@ #include #include +#include +#include #include #include #include @@ -1829,6 +1831,22 @@ static bool valueFlowForward(Token * const startToken, return false; } + // Forward known values in the else branch + if(Token::simpleMatch(end, "} else {")) { + std::list knownValues; + std::copy_if(values.begin(), values.end(), std::back_inserter(knownValues), std::mem_fn(&ValueFlow::Value::isKnown)); + valueFlowForward(end->tokAt(2), + end->linkAt(2), + var, + varid, + knownValues, + constValue, + subFunction, + tokenlist, + errorLogger, + settings); + } + // Remove conditional values std::list::iterator it; for (it = values.begin(); it != values.end();) { diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 3c62b53d5..8bca20f52 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -2462,6 +2462,15 @@ private: check("void f() { if(1) {} }"); ASSERT_EQUALS("", errout.str()); + + check("void f(int i) {\n" + " bool b = false;\n" + " if (i == 0) b = true;\n" + " else if (!b && i == 1) {}\n" + " if (b)\n" + " {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (style) Condition '!b' is always true\n", errout.str()); } void checkInvalidTestForOverflow() { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 5e7055866..7b23bc7e9 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -80,6 +80,7 @@ private: TEST_CASE(valueFlowAfterCondition); TEST_CASE(valueFlowForwardCompoundAssign); TEST_CASE(valueFlowForwardCorrelatedVariables); + TEST_CASE(valueFlowForwardModifiedVariables); TEST_CASE(valueFlowForwardFunction); TEST_CASE(valueFlowForwardTernary); TEST_CASE(valueFlowForwardLambda); @@ -107,6 +108,24 @@ private: TEST_CASE(valueFlowContainerSize); } + bool testValueOfXKnown(const char code[], unsigned int linenr, int value) { + // Tokenize.. + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + + for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { + if (tok->str() == "x" && tok->linenr() == linenr) { + for(const ValueFlow::Value& val:tok->values()) { + if(val.isKnown() && val.intvalue == value) + return true; + } + } + } + + return false; + } + bool testValueOfX(const char code[], unsigned int linenr, int value) { // Tokenize.. Tokenizer tokenizer(&settings, this); @@ -2135,6 +2154,27 @@ private: ASSERT_EQUALS(false, testValueOfX(code, 4U, 0)); } + void valueFlowForwardModifiedVariables() { + const char *code; + + code = "void f(bool b) {\n" + " int x = 0;\n" + " if (b) x = 1;\n" + " else b = x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, 0)); + + code = "void f(int i) {\n" + " int x = 0;\n" + " if (i == 0) \n" + " x = 1;\n" + " else if (!x && i == 1) \n" + " int b = x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 5U, 0)); + ASSERT_EQUALS(true, testValueOfXKnown(code, 6U, 0)); + } + void valueFlowForwardFunction() { const char *code;