diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index d5edcb9d6..ff18bdb02 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -432,6 +432,45 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog } } +static void valueFlowAfterAssign(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) +{ + for (Token *tok = tokenlist->front(); tok; tok = tok->next()) { + // Assignment + if ((tok->str() != "=") || (tok->astParent())) + continue; + + // Rhs should be a variable + if (!tok->astOperand1() || !tok->astOperand1()->isName()) + continue; + unsigned int varid = tok->astOperand1()->varId(); + if (varid == 0U) + continue; + const Variable *var = tok->astOperand1()->variable(); + if (!var || !var->isLocal()) + continue; + + // Lhs values.. + if (!tok->astOperand2() || tok->astOperand2()->values.empty()) + continue; + std::list values = tok->astOperand2()->values; + + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) { + if (Token::Match(tok2, "[{}]")) + break; + if (Token::Match(tok2, "sizeof (")) + tok2 = tok2->linkAt(1); + if (tok2->varId() == varid) { + if (!Token::Match(tok2->previous(), "= %var% %cop%|;")) + break; + + std::list::const_iterator it; + for (it = values.begin(); it != values.end(); ++it) + setTokenValue(tok2, *it); + } + } + } +} + static void valueFlowForLoop(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) { for (Token *tok = tokenlist->front(); tok; tok = tok->next()) { @@ -582,5 +621,6 @@ void ValueFlow::setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const valueFlowNumber(tokenlist); valueFlowForLoop(tokenlist, errorLogger, settings); valueFlowBeforeCondition(tokenlist, errorLogger, settings); + valueFlowAfterAssign(tokenlist, errorLogger, settings); valueFlowSubFunction(tokenlist, errorLogger, settings); } diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 2c0fdac0c..ba8a841b1 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -1969,7 +1969,9 @@ private: " std::string s5(p);\n" " foo(std::string(p));\n" "}", true); - ASSERT_EQUALS("[test.cpp:3]: (error) Null pointer dereference\n" + ASSERT_EQUALS("[test.cpp:7]: (error) Null pointer dereference\n" + "[test.cpp:8]: (error) Null pointer dereference\n" + "[test.cpp:3]: (error) Null pointer dereference\n" "[test.cpp:4]: (error) Null pointer dereference\n" "[test.cpp:5]: (error) Null pointer dereference\n" "[test.cpp:6]: (error) Null pointer dereference\n" diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index c4857cd85..2988d92f1 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -51,6 +51,8 @@ private: TEST_CASE(valueFlowBeforeConditionSwitch); TEST_CASE(valueFlowBeforeConditionTernaryOp); + TEST_CASE(valueFlowAfterAssign); + TEST_CASE(valueFlowForLoop); TEST_CASE(valueFlowSubFunction); } @@ -454,6 +456,22 @@ private: ASSERT_EQUALS("[test.cpp:3]: (debug) ValueFlow bailout: variable x stopping on goto label\n", errout.str()); } + void valueFlowAfterAssign() { + const char *code; + + code = "void f() {\n" + " int x = 123;\n" + " a = x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 3U, 123)); + + code = "void f() {\n" + " int x = 123;\n" + " a = sizeof(x);\n" + "}"; + ASSERT_EQUALS(false, testValueOfX(code, 3U, 123)); + } + void valueFlowForLoop() { const char *code;