Fixed #7152 (False positive for redundantAssignment after calling a lambda function)

This commit is contained in:
Daniel Marjamäki 2018-10-08 21:07:21 +02:00
parent 86a1b84b0c
commit aa58f41e6d
2 changed files with 38 additions and 1 deletions

View File

@ -485,6 +485,7 @@ void CheckOther::checkRedundantAssignment()
if (!scope.isExecutable()) if (!scope.isExecutable())
continue; continue;
std::map<unsigned int, std::set<unsigned int>> usedByLambda; // map key: lambda function varId. set of varIds used by lambda.
std::map<unsigned int, const Token*> varAssignments; std::map<unsigned int, const Token*> varAssignments;
std::map<unsigned int, const Token*> memAssignments; std::map<unsigned int, const Token*> memAssignments;
std::map<unsigned int, std::set<unsigned int> > membervars; std::map<unsigned int, std::set<unsigned int> > membervars;
@ -510,6 +511,17 @@ void CheckOther::checkRedundantAssignment()
} else if (Token::Match(tok, "break|return|continue|throw|goto|asm")) { } else if (Token::Match(tok, "break|return|continue|throw|goto|asm")) {
varAssignments.clear(); varAssignments.clear();
memAssignments.clear(); memAssignments.clear();
} else if (Token::Match(tok, "%var% = [ & ] (")) {
const unsigned int lambdaId = tok->varId();
const Token *lambdaParams = tok->tokAt(5);
if (Token::simpleMatch(lambdaParams->link(), ") {")) {
const Token *lambdaBodyStart = lambdaParams->link()->next();
const Token * const lambdaBodyEnd = lambdaBodyStart->link();
for (const Token *tok2 = lambdaBodyStart; tok2 != lambdaBodyEnd; tok2 = tok2->next()) {
if (tok2->varId())
usedByLambda[lambdaId].insert(tok2->varId());
}
}
} else if (tok->tokType() == Token::eVariable && !Token::Match(tok, "%name% (")) { } else if (tok->tokType() == Token::eVariable && !Token::Match(tok, "%name% (")) {
const Token *eq = nullptr; const Token *eq = nullptr;
for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) { for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) {
@ -640,9 +652,19 @@ void CheckOther::checkRedundantAssignment()
} }
} else if (Token::Match(tok, "%name% (") && !mSettings->library.isFunctionConst(tok->str(), true)) { // Function call. Global variables might be used. Reset their status } else if (Token::Match(tok, "%name% (") && !mSettings->library.isFunctionConst(tok->str(), true)) { // Function call. Global variables might be used. Reset their status
const bool memfunc = Token::Match(tok, "memcpy|memmove|memset|strcpy|strncpy|sprintf|snprintf|strcat|strncat|wcscpy|wcsncpy|swprintf|wcscat|wcsncat"); const bool memfunc = Token::Match(tok, "memcpy|memmove|memset|strcpy|strncpy|sprintf|snprintf|strcat|strncat|wcscpy|wcsncpy|swprintf|wcscat|wcsncat");
if (tok->varId()) // operator() or function pointer if (tok->varId()) {
// operator(), function pointer
varAssignments.erase(tok->varId()); varAssignments.erase(tok->varId());
// lambda..
std::map<unsigned int, std::set<unsigned int>>::const_iterator lambda = usedByLambda.find(tok->varId());
if (lambda != usedByLambda.end()) {
for (unsigned int varId : lambda->second) {
varAssignments.erase(varId);
}
}
}
if (memfunc && tok->strAt(-1) != "(" && tok->strAt(-1) != "=") { if (memfunc && tok->strAt(-1) != "(" && tok->strAt(-1) != "=") {
const Token* param1 = tok->tokAt(2); const Token* param1 = tok->tokAt(2);
writtenArgumentsEnd = param1->next(); writtenArgumentsEnd = param1->next();

View File

@ -160,6 +160,7 @@ private:
TEST_CASE(redundantVarAssignment); TEST_CASE(redundantVarAssignment);
TEST_CASE(redundantVarAssignment_7133); TEST_CASE(redundantVarAssignment_7133);
TEST_CASE(redundantVarAssignment_stackoverflow); TEST_CASE(redundantVarAssignment_stackoverflow);
TEST_CASE(redundantVarAssignment_lambda);
TEST_CASE(redundantMemWrite); TEST_CASE(redundantMemWrite);
TEST_CASE(varFuncNullUB); TEST_CASE(varFuncNullUB);
@ -5976,6 +5977,20 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void redundantVarAssignment_lambda() {
// #7152
check("int foo() {\n"
" int x = 0, y = 0;\n"
" auto f = [&]() { if (x < 5) ++y; };\n"
" x = 2;\n"
" f();\n"
" x = 6;\n"
" f();\n"
" return y;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void redundantMemWrite() { void redundantMemWrite() {
// Simple tests // Simple tests
check("void f() {\n" check("void f() {\n"