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; 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) static void valueFlowAfterMove(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
{ {
if (!tokenlist->isCPP() || settings->standards.cpp < Standards::CPP11) if (!tokenlist->isCPP() || settings->standards.cpp < Standards::CPP11)
@ -1757,15 +1763,18 @@ static void valueFlowAfterMove(TokenList *tokenlist, SymbolDatabase* symboldatab
ValueFlow::Value::MoveKind moveKind; ValueFlow::Value::MoveKind moveKind;
if (!isStdMoveOrStdForwarded(tok, &moveKind, &varTok)) if (!isStdMoveOrStdForwarded(tok, &moveKind, &varTok))
continue; continue;
const unsigned int varId = varTok->varId();
// x is not MOVED after assignment if code is: x = ... std::move(x) .. ; // x is not MOVED after assignment if code is: x = ... std::move(x) .. ;
const Token *parent = tok->astParent(); 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(); 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; continue;
if (parent && parent->astOperand1()->str() == varTok->str()) if (parent && parent->astOperand1()->varId() == varId)
continue; continue;
const unsigned int varid = varTok->varId();
const Variable *var = varTok->variable(); const Variable *var = varTok->variable();
if (!var) if (!var)
continue; continue;
@ -1778,7 +1787,7 @@ static void valueFlowAfterMove(TokenList *tokenlist, SymbolDatabase* symboldatab
std::list<ValueFlow::Value> values; std::list<ValueFlow::Value> values;
values.push_back(value); 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(moveAndAssign1);
TEST_CASE(moveAndAssign2); TEST_CASE(moveAndAssign2);
TEST_CASE(moveAssignMoveAssign); TEST_CASE(moveAssignMoveAssign);
TEST_CASE(moveAndReset1);
TEST_CASE(moveAndReset2);
TEST_CASE(moveResetMoveReset);
TEST_CASE(moveAndFunctionParameter); TEST_CASE(moveAndFunctionParameter);
TEST_CASE(moveAndFunctionParameterReference); TEST_CASE(moveAndFunctionParameterReference);
TEST_CASE(moveAndFunctionParameterConstReference); TEST_CASE(moveAndFunctionParameterConstReference);
@ -6189,6 +6192,50 @@ private:
"[test.cpp:8]: (warning) Access of moved variable a.\n", errout.str()); "[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() { void moveAndFunctionParameter() {
check("void g(A a);\n" check("void g(A a);\n"
"void f() {\n" "void f() {\n"