Fix #8433 FN unused variable not detected when there is lambda (#5060)

* Fix #8433 FN unused variable not detected when there is lambda

* Format

* Fix tests

* Check lambda return

* Add test

* Undo, add test

* simpleMatch()

* Rename test
This commit is contained in:
chrchr-github 2023-05-22 07:39:57 +02:00 committed by GitHub
parent e621f721fc
commit 8eabf5c211
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 11 deletions

View File

@ -720,8 +720,6 @@ void CheckMemoryLeakStructMember::check()
continue; continue;
if (var->typeEndToken()->isStandardType()) if (var->typeEndToken()->isStandardType())
continue; continue;
if (var->scope()->hasInlineOrLambdaFunction())
continue;
checkStructVariable(var); checkStructVariable(var);
} }
} }
@ -921,7 +919,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
} }
// Returning from function.. // Returning from function..
else if (tok3->str() == "return") { else if ((tok3->scope()->type != Scope::ScopeType::eLambda || tok3->scope() == variable->scope()) && tok3->str() == "return") {
// Returning from function without deallocating struct member? // Returning from function without deallocating struct member?
if (!Token::Match(tok3, "return %varid% ;", structid) && if (!Token::Match(tok3, "return %varid% ;", structid) &&
!Token::Match(tok3, "return & %varid%", structid) && !Token::Match(tok3, "return & %varid%", structid) &&

View File

@ -5149,6 +5149,15 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty
return nullptr; return nullptr;
} }
static bool hasEmptyCaptureList(const Token* tok) {
if (!Token::simpleMatch(tok, "{"))
return false;
const Token* listTok = tok->astParent();
if (Token::simpleMatch(listTok, "("))
listTok = listTok->astParent();
return Token::simpleMatch(listTok, "[ ]");
}
bool Scope::hasInlineOrLambdaFunction() const bool Scope::hasInlineOrLambdaFunction() const
{ {
return std::any_of(nestedList.begin(), nestedList.end(), [&](const Scope* s) { return std::any_of(nestedList.begin(), nestedList.end(), [&](const Scope* s) {
@ -5156,7 +5165,7 @@ bool Scope::hasInlineOrLambdaFunction() const
if (s->type == Scope::eUnconditional && Token::simpleMatch(s->bodyStart->previous(), ") {")) if (s->type == Scope::eUnconditional && Token::simpleMatch(s->bodyStart->previous(), ") {"))
return true; return true;
// Lambda function // Lambda function
if (s->type == Scope::eLambda) if (s->type == Scope::eLambda && !hasEmptyCaptureList(s->bodyStart))
return true; return true;
if (s->hasInlineOrLambdaFunction()) if (s->hasInlineOrLambdaFunction())
return true; return true;

View File

@ -2131,15 +2131,13 @@ private:
" FILE*f=fopen(fname,a);\n" " FILE*f=fopen(fname,a);\n"
" std::shared_ptr<FILE> fp{f, [](FILE* x) { free(f); }};\n" " std::shared_ptr<FILE> fp{f, [](FILE* x) { free(f); }};\n"
"}", true); "}", true);
TODO_ASSERT_EQUALS( ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str());
"[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", "", errout.str());
check("void f() {\n" check("void f() {\n"
" FILE*f=fopen(fname,a);\n" " FILE*f=fopen(fname,a);\n"
" std::shared_ptr<FILE> fp{f, [](FILE* x) {}};\n" " std::shared_ptr<FILE> fp{f, [](FILE* x) {}};\n"
"}", true); "}", true);
TODO_ASSERT_EQUALS( ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str());
"[test.cpp:2] -> [test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", "", errout.str());
check("class C;\n" check("class C;\n"
"void f() {\n" "void f() {\n"

View File

@ -1737,7 +1737,7 @@ private:
TEST_CASE(customAllocation); TEST_CASE(customAllocation);
TEST_CASE(lambdaInForLoop); // #9793 TEST_CASE(lambdaInScope); // #9793
} }
void err() { void err() {
@ -2228,8 +2228,8 @@ private:
ASSERT_EQUALS("[test.c:7]: (error) Memory leak: abc.a\n", errout.str()); ASSERT_EQUALS("[test.c:7]: (error) Memory leak: abc.a\n", errout.str());
} }
void lambdaInForLoop() { // #9793 void lambdaInScope() {
check( check( // #9793
"struct S { int * p{nullptr}; };\n" "struct S { int * p{nullptr}; };\n"
"int main()\n" "int main()\n"
"{\n" "{\n"
@ -2242,6 +2242,35 @@ private:
" return 0;\n" " return 0;\n"
"}", true); "}", true);
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check(
"struct S { int* p; };\n"
"void f() {\n"
" auto g = []() {\n"
" S s;\n"
" s.p = new int;\n"
" };\n"
"}\n", true);
ASSERT_EQUALS("[test.cpp:6]: (error) Memory leak: s.p\n", errout.str());
check(
"struct S { int* p; };\n"
"void f() {\n"
" S s;\n"
" s.p = new int;\n"
" auto g = [&]() {\n"
" delete s.p;\n"
" };\n"
" g();\n"
"}\n"
"void h() {\n"
" S s;\n"
" s.p = new int;\n"
" [&]() {\n"
" delete s.p;\n"
" }();\n"
"}\n", true);
ASSERT_EQUALS("", errout.str());
} }
}; };

View File

@ -6328,6 +6328,13 @@ private:
" });\n" " });\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
functionVariableUsage("int f() {\n" // #8433
" float a;\n"
" auto lambda = []() {};\n"
" return 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Unused variable: a\n", errout.str());
} }