diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 3b854eb36..b6a51ec79 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1736,6 +1736,12 @@ static bool isStdMoveOrStdForwarded(Token * tok, ValueFlow::Value::MoveKind * mo return true; } +static bool isOpenParenthesisMemberFunctionCallOfVarId(const Token * openParenthesisToken, unsigned int varId) +{ + return Token::Match(openParenthesisToken->tokAt(-3),"%varid% . %name% (", varId) && + openParenthesisToken->tokAt(-2)->originalName() == emptyString; +} + static void valueFlowAfterMove(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings) { if (!tokenlist->isCPP() || settings->standards.cpp < Standards::CPP11) @@ -1757,15 +1763,18 @@ static void valueFlowAfterMove(TokenList *tokenlist, SymbolDatabase* symboldatab ValueFlow::Value::MoveKind moveKind; if (!isStdMoveOrStdForwarded(tok, &moveKind, &varTok)) continue; + const unsigned int varId = varTok->varId(); // x is not MOVED after assignment if code is: x = ... std::move(x) .. ; const Token *parent = tok->astParent(); - while (parent && parent->str() != "=" && parent->str() != "return") + while (parent && parent->str() != "=" && parent->str() != "return" && + !(parent->str() == "(" && isOpenParenthesisMemberFunctionCallOfVarId(parent, varId))) parent = parent->astParent(); - if (parent && parent->str() == "return") // MOVED in return statement + if (parent && + (parent->str() == "return" || // MOVED in return statement + parent->str() == "(")) // MOVED in self assignment, isOpenParenthesisMemberFunctionCallOfVarId == true continue; - if (parent && parent->astOperand1()->str() == varTok->str()) + if (parent && parent->astOperand1()->varId() == varId) continue; - const unsigned int varid = varTok->varId(); const Variable *var = varTok->variable(); if (!var) continue; @@ -1778,7 +1787,7 @@ static void valueFlowAfterMove(TokenList *tokenlist, SymbolDatabase* symboldatab std::list values; values.push_back(value); - valueFlowForward(varTok->next(), endOfVarScope, var, varid, values, false, tokenlist, errorLogger, settings); + valueFlowForward(varTok->next(), endOfVarScope, var, varId, values, false, tokenlist, errorLogger, settings); } } } diff --git a/test/testother.cpp b/test/testother.cpp index 4f7bc9b48..8257f8676 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -179,6 +179,9 @@ private: TEST_CASE(moveAndAssign1); TEST_CASE(moveAndAssign2); TEST_CASE(moveAssignMoveAssign); + TEST_CASE(moveAndReset1); + TEST_CASE(moveAndReset2); + TEST_CASE(moveResetMoveReset); TEST_CASE(moveAndFunctionParameter); TEST_CASE(moveAndFunctionParameterReference); TEST_CASE(moveAndFunctionParameterConstReference); @@ -6189,6 +6192,50 @@ private: "[test.cpp:8]: (warning) Access of moved variable a.\n", errout.str()); } + void moveAndReset1() { + check("A g(A a);\n" + "void f() {\n" + " A a;\n" + " a.reset(g(std::move(a)));\n" + " a.reset(g(std::move(a)));\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void moveAndReset2() { + check("A g(A a);\n" + "void f() {\n" + " A a;\n" + " A b;\n" + " A c;\n" + " b.reset(g(std::move(a)));\n" + " c.reset(g(std::move(a)));\n" + "}"); + ASSERT_EQUALS("[test.cpp:7]: (warning) Access of moved variable a.\n", errout.str()); + } + + void moveResetMoveReset() { + check("void h(A a);\n" + "void f() {" + " A a;\n" + " g(std::move(a));\n" + " h(a);\n" + " a.reset(b);\n" + " h(a);\n" + " g(std::move(a));\n" + " h(a);\n" + " a.reset(b);\n" + " h(a);\n" + "}"); + ASSERT_EQUALS("[test.cpp:4]: (warning) Access of moved variable a.\n" + "[test.cpp:5]: (warning, inconclusive) Access of moved variable a.\n" + "[test.cpp:6]: (warning, inconclusive) Access of moved variable a.\n" + "[test.cpp:7]: (warning, inconclusive) Access of moved variable a.\n" + "[test.cpp:8]: (warning) Access of moved variable a.\n" + "[test.cpp:9]: (warning, inconclusive) Access of moved variable a.\n" + "[test.cpp:10]: (warning, inconclusive) Access of moved variable a.\n", errout.str()); + } + void moveAndFunctionParameter() { check("void g(A a);\n" "void f() {\n"