Fixed #7152 (False positive for redundantAssignment after calling a lambda function)
This commit is contained in:
parent
86a1b84b0c
commit
aa58f41e6d
|
@ -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();
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue