diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 08f7d8f42..5d0940190 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -1625,7 +1625,8 @@ static bool isUnchanged(const Token *startToken, const Token *endToken, const st struct FwdAnalysis::Result FwdAnalysis::checkRecursive(const Token *expr, const Token *startToken, const Token *endToken, const std::set &exprVarIds, bool local, bool inInnerClass) { // Parse the given tokens - for (const Token *tok = startToken; tok != endToken; tok = tok->next()) { + + for (const Token* tok = startToken; precedes(tok, endToken); tok = tok->next()) { if (Token::simpleMatch(tok, "try {")) { // TODO: handle try return Result(Result::Type::BAILOUT); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index dee9f30cf..5fe9f9b81 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1841,6 +1841,16 @@ static void valueFlowGlobalStaticVar(TokenList *tokenList, const Settings *setti } } +static void valueFlowForward(Token* startToken, + const Token* endToken, + const Token* exprTok, + std::list values, + const bool constValue, + const bool subFunction, + TokenList* const tokenlist, + ErrorLogger* const errorLogger, + const Settings* settings); + static void valueFlowReverse(TokenList *tokenlist, Token *tok, const Token * const varToken, @@ -1865,8 +1875,30 @@ static void valueFlowReverse(TokenList *tokenlist, } if (tok2->varId() == varid) { + if (tok2->hasKnownValue()) + break; // bailout: assignment if (Token::Match(tok2->previous(), "!!* %name% =")) { + Token* assignTok = const_cast(tok2->next()->astOperand2()); + if (!assignTok->hasKnownValue()) { + std::list values = {val}; + setTokenValue(assignTok, val, settings); + if (val2.condition) { + setTokenValue(assignTok, val2, settings); + values.push_back(val2); + } + const Token* startForwardToken = nextAfterAstRightmostLeaf(tok2->next()); + const Token* endForwardToken = tok->scope() ? tok->scope()->bodyEnd : tok; + valueFlowForward(const_cast(startForwardToken), + endForwardToken, + assignTok, + values, + false, + false, + tokenlist, + errorLogger, + settings); + } if (settings->debugwarnings) bailout(tokenlist, errorLogger, tok2, "assignment of " + tok2->str()); break; @@ -2062,6 +2094,17 @@ static void valueFlowReverse(TokenList *tokenlist, } } +static bool isConditionKnown(const Token* tok, bool then) +{ + const char* op = "||"; + if (then) + op = "&&"; + const Token* parent = tok->astParent(); + while (parent && parent->str() == op) + parent = parent->astParent(); + return (parent && parent->str() == "("); +} + static void valueFlowBeforeCondition(TokenList *tokenlist, SymbolDatabase *symboldatabase, ErrorLogger *errorLogger, const Settings *settings) { for (const Scope * scope : symboldatabase->functionScopes) { @@ -4311,17 +4354,6 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat } } -static bool isConditionKnown(const Token* tok, bool then) -{ - const char * op = "||"; - if (then) - op = "&&"; - const Token* parent = tok->astParent(); - while (parent && parent->str() == op) - parent = parent->astParent(); - return (parent && parent->str() == "("); -} - static void valueFlowSetConditionToKnown(const Token* tok, std::list& values, bool then) { if (values.empty()) diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index f9596ee42..0ef8c8be0 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -79,6 +79,7 @@ private: TEST_CASE(valueFlowBeforeConditionSizeof); TEST_CASE(valueFlowBeforeConditionSwitch); TEST_CASE(valueFlowBeforeConditionTernaryOp); + TEST_CASE(valueFlowBeforeConditionForward); TEST_CASE(valueFlowAfterAssign); TEST_CASE(valueFlowAfterCondition); @@ -1410,6 +1411,25 @@ private: errout.str()); } + void valueFlowBeforeConditionForward() + { + const char* code; + + code = "void f(int a) {\n" + " int x = a;\n" + " if (a == 123) {}\n" + " int b = x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 123)); + + code = "void f(int a) {\n" + " int x = a;\n" + " if (a != 123) {}\n" + " int b = x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 123)); + } + void valueFlowAfterAssign() { const char *code;