Improve Fix #6180 (Do not warn about move if it is part of a reassignment of the variable)

This commit is contained in:
Frank Zingsheim 2016-12-11 22:32:57 +01:00 committed by Daniel Marjamäki
parent f8cfa72159
commit f4ab45f13b
2 changed files with 61 additions and 5 deletions

View File

@ -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<ValueFlow::Value> 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);
}
}
}

View File

@ -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"