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;
if (var->typeEndToken()->isStandardType())
continue;
if (var->scope()->hasInlineOrLambdaFunction())
continue;
checkStructVariable(var);
}
}
@ -921,7 +919,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
}
// 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?
if (!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;
}
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
{
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(), ") {"))
return true;
// Lambda function
if (s->type == Scope::eLambda)
if (s->type == Scope::eLambda && !hasEmptyCaptureList(s->bodyStart))
return true;
if (s->hasInlineOrLambdaFunction())
return true;

View File

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

View File

@ -1737,7 +1737,7 @@ private:
TEST_CASE(customAllocation);
TEST_CASE(lambdaInForLoop); // #9793
TEST_CASE(lambdaInScope); // #9793
}
void err() {
@ -2228,8 +2228,8 @@ private:
ASSERT_EQUALS("[test.c:7]: (error) Memory leak: abc.a\n", errout.str());
}
void lambdaInForLoop() { // #9793
check(
void lambdaInScope() {
check( // #9793
"struct S { int * p{nullptr}; };\n"
"int main()\n"
"{\n"
@ -2242,6 +2242,35 @@ private:
" return 0;\n"
"}", true);
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"
"}");
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());
}