Fix #11719 Handle lambdas in global scope (#5065)

* Fix #11719 Handle lambdas in global scope

* Capture list
This commit is contained in:
chrchr-github 2023-05-17 14:37:56 +02:00 committed by GitHub
parent 1999bc68bf
commit 518b6a27ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 8 deletions

View File

@ -141,6 +141,16 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
return endInitList.top().second == scope; return endInitList.top().second == scope;
}; };
auto addLambda = [this, &scope](const Token* tok, const Token* lambdaEndToken) -> const Token* {
const Token* lambdaStartToken = lambdaEndToken->link();
const Token* argStart = lambdaStartToken->astParent();
const Token* funcStart = Token::simpleMatch(argStart, "[") ? argStart : argStart->astParent();
const Function* function = addGlobalFunction(scope, tok, argStart, funcStart);
if (!function)
mTokenizer.syntaxError(tok);
return lambdaStartToken;
};
// Store current access in each scope (depends on evaluation progress) // Store current access in each scope (depends on evaluation progress)
std::map<const Scope*, AccessControl> access; std::map<const Scope*, AccessControl> access;
@ -674,6 +684,8 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
tok = declEnd; tok = declEnd;
continue; continue;
} }
} else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
tok = addLambda(tok, lambdaEndToken);
} }
} else if (scope->isExecutable()) { } else if (scope->isExecutable()) {
if (tok->isKeyword() && Token::Match(tok, "else|try|do {")) { if (tok->isKeyword() && Token::Match(tok, "else|try|do {")) {
@ -712,13 +724,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
endInitList.emplace(tok->next()->link(), scope); endInitList.emplace(tok->next()->link(), scope);
tok = tok->next(); tok = tok->next();
} else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) { } else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
const Token *lambdaStartToken = lambdaEndToken->link(); tok = addLambda(tok, lambdaEndToken);
const Token * argStart = lambdaStartToken->astParent();
const Token * funcStart = Token::simpleMatch(argStart, "[") ? argStart : argStart->astParent();
const Function * function = addGlobalFunction(scope, tok, argStart, funcStart);
if (!function)
mTokenizer.syntaxError(tok);
tok = lambdaStartToken;
} else if (tok->str() == "{") { } else if (tok->str() == "{") {
if (inInitList()) { if (inInitList()) {
endInitList.emplace(tok->link(), scope); endInitList.emplace(tok->link(), scope);

View File

@ -467,6 +467,7 @@ private:
TEST_CASE(lambda); // #5867 TEST_CASE(lambda); // #5867
TEST_CASE(lambda2); // #7473 TEST_CASE(lambda2); // #7473
TEST_CASE(lambda3); TEST_CASE(lambda3);
TEST_CASE(lambda4);
TEST_CASE(circularDependencies); // #6298 TEST_CASE(circularDependencies); // #6298
@ -7686,7 +7687,6 @@ private:
ASSERT_EQUALS(Scope::eLambda, scope->type); ASSERT_EQUALS(Scope::eLambda, scope->type);
} }
void lambda3() { void lambda3() {
GET_SYMBOL_DB("void func() {\n" GET_SYMBOL_DB("void func() {\n"
" auto f = []() mutable {}\n" " auto f = []() mutable {}\n"
@ -7701,6 +7701,28 @@ private:
ASSERT_EQUALS(Scope::eLambda, scope->type); ASSERT_EQUALS(Scope::eLambda, scope->type);
} }
void lambda4() { // #11719
GET_SYMBOL_DB("struct S { int* p; };\n"
"auto g = []() {\n"
" S s;\n"
" s.p = new int;\n"
"};\n");
ASSERT(db && db->scopeList.size() == 3);
std::list<Scope>::const_iterator scope = db->scopeList.cbegin();
ASSERT_EQUALS(Scope::eGlobal, scope->type);
++scope;
ASSERT_EQUALS(Scope::eStruct, scope->type);
++scope;
ASSERT_EQUALS(Scope::eLambda, scope->type);
ASSERT_EQUALS(1, scope->varlist.size());
const Variable& s = scope->varlist.front();
ASSERT_EQUALS(s.name(), "s");
ASSERT(s.type());
--scope;
ASSERT_EQUALS(s.type()->classScope, &*scope);
}
// #6298 "stack overflow in Scope::findFunctionInBase (endless recursion)" // #6298 "stack overflow in Scope::findFunctionInBase (endless recursion)"
void circularDependencies() { void circularDependencies() {
check("template<template<class> class E,class D> class C : E<D> {\n" check("template<template<class> class E,class D> class C : E<D> {\n"