Improve support of using a lambda as a deleter (#1246)

* Improve support of using a lambda as a deleter

* Use simple match
This commit is contained in:
Paul Fultz II 2018-05-21 01:22:18 -05:00 committed by Daniel Marjamäki
parent 42ed5a6b98
commit 406aa6cf1c
2 changed files with 61 additions and 4 deletions

View File

@ -600,16 +600,35 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
endDeleterToken = typeEndTok->linkAt(2);
}
if (deleterToken) {
// Skip the decaying plus in expressions like +[](T*){}
if (deleterToken->str() == "+") {
deleterToken = deleterToken->next();
}
// Check if its a pointer to a function
const Token * dtok = Token::findmatch(deleterToken, "& %name%", endDeleterToken);
if (dtok) {
af = _settings->library.dealloc(dtok->tokAt(1));
} else {
const Token * tscopeStart = nullptr;
const Token * tscopeEnd = nullptr;
// If the deleter is a lambda, check if it calls the dealloc function
if (deleterToken->str() == "[" &&
Token::simpleMatch(deleterToken->link(), "] (") &&
// TODO: Check for mutable keyword
Token::simpleMatch(deleterToken->link()->linkAt(1), ") {")) {
tscopeStart = deleterToken->link()->linkAt(1)->tokAt(1);
tscopeEnd = tscopeStart->link();
// If the deleter is a class, check if class calls the dealloc function
dtok = Token::findmatch(deleterToken, "%type%", endDeleterToken);
if (dtok && dtok->type()) {
const Scope * tscope = dtok->type()->classScope;
for (const Token *tok2 = tscope->bodyStart; tok2 != tscope->bodyEnd; tok2 = tok2->next()) {
} else if ((dtok = Token::findmatch(deleterToken, "%type%", endDeleterToken)) && dtok->type()) {
const Scope * tscope = dtok->type()->classScope;
if(tscope) {
tscopeStart = tscope->bodyStart;
tscopeEnd = tscope->bodyEnd;
}
}
if(tscopeStart && tscopeEnd) {
for (const Token *tok2 = tscopeStart; tok2 != tscopeEnd; tok2 = tok2->next()) {
af = _settings->library.dealloc(tok2);
if (af)
break;

View File

@ -1255,6 +1255,44 @@ private:
" std::unique_ptr<int, decltype(&destroy)> xp(x, &destroy());\n"
"}\n", true);
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" FILE*f=fopen(fname,a);\n"
" std::shared_ptr<FILE> fp{f, [](FILE* x) { fclose(x); }};\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" FILE*f=fopen(fname,a);\n"
" std::shared_ptr<FILE> fp{f, +[](FILE* x) { fclose(x); }};\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" FILE*f=fopen(fname,a);\n"
" std::shared_ptr<FILE> fp{f, [](FILE* x) { free(f); }};\n"
"}", true);
ASSERT_EQUALS("[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);
ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str());
check("class C;\n"
"void f() {\n"
" C* c = new C{};\n"
" std::shared_ptr<C> a{c, [](C*) {}};\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("class C;\n"
"void f() {\n"
" C* c = new C{};\n"
" std::shared_ptr<C> a{c, [](C* x) { delete x; }};\n"
"}", true);
ASSERT_EQUALS("", errout.str());
}
void smartPointerRelease() {
check("void f() {\n"