From fdbcf818e6561007fa4937d3a228ccfa960e6aa7 Mon Sep 17 00:00:00 2001 From: Oleksandr Labetskyi Date: Thu, 8 Feb 2024 17:54:30 +0200 Subject: [PATCH 1/7] First draft --- lib/symboldatabase.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index a454d5c0951..e081acad620 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -720,6 +720,27 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() else if (scope->type == Scope::eCatch) scope->checkVariable(tok->tokAt(2), AccessControl::Throw, mSettings); // check for variable declaration and add it to new scope if found tok = scopeStartTok; + } else if (Token::Match(tok, "%name% (")) { + const Token *funcStart = nullptr; + const Token *argStart = nullptr; + const Token *declEnd = nullptr; + if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) { + bool newFunc = true; // Is this function already in the database? + auto range = scope->functionMap.equal_range(tok->str()); + for (std::multimap::const_iterator it = range.first; it != range.second; ++it) { + if (it->second->argsMatch(scope, it->second->argDef, argStart, emptyString, 0)) { + newFunc = false; + break; + } + } + // save function prototype in database + if (newFunc) + addGlobalFunctionDecl(scope, tok, argStart, funcStart); + + tok = declEnd; + continue; + } + } else if (Token::Match(tok, "%var% {")) { endInitList.emplace(tok->next()->link(), scope); tok = tok->next(); From e45701abc7d5216efb3a4f006c611b040709fa78 Mon Sep 17 00:00:00 2001 From: Oleksandr Labetskyi Date: Thu, 8 Feb 2024 18:26:11 +0200 Subject: [PATCH 2/7] Small change --- lib/symboldatabase.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index e081acad620..61a3c5e264e 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -725,20 +725,22 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() const Token *argStart = nullptr; const Token *declEnd = nullptr; if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) { - bool newFunc = true; // Is this function already in the database? - auto range = scope->functionMap.equal_range(tok->str()); - for (std::multimap::const_iterator it = range.first; it != range.second; ++it) { - if (it->second->argsMatch(scope, it->second->argDef, argStart, emptyString, 0)) { - newFunc = false; - break; + if (declEnd && declEnd->str() == ";") { + bool newFunc = true; // Is this function already in the database? + auto range = scope->functionMap.equal_range(tok->str()); + for (std::multimap::const_iterator it = range.first; it != range.second; ++it) { + if (it->second->argsMatch(scope, it->second->argDef, argStart, emptyString, 0)) { + newFunc = false; + break; + } } + // save function prototype in database + if (newFunc) { + addGlobalFunctionDecl(scope, tok, argStart, funcStart); + } + tok = declEnd; + continue; } - // save function prototype in database - if (newFunc) - addGlobalFunctionDecl(scope, tok, argStart, funcStart); - - tok = declEnd; - continue; } } else if (Token::Match(tok, "%var% {")) { From c62b2d094a8ac56c0c6b7a3ff014c9f4951ae0f6 Mon Sep 17 00:00:00 2001 From: Oleksandr Labetskyi Date: Fri, 9 Feb 2024 10:09:37 +0200 Subject: [PATCH 3/7] Another small fix --- lib/symboldatabase.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 61a3c5e264e..bf98f424949 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -736,7 +736,9 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() } // save function prototype in database if (newFunc) { - addGlobalFunctionDecl(scope, tok, argStart, funcStart); + Function function(tok, scope, funcStart, argStart); + if(function.isExtern()) + scope->addFunction(std::move(function)); } tok = declEnd; continue; @@ -5915,6 +5917,8 @@ const Function* SymbolDatabase::findFunction(const Token* const tok) const // find the scope this function is in const Scope *currScope = tok->scope(); while (currScope && currScope->isExecutable()) { + if (const Function* f = currScope->findFunction(tok)) + return f; if (currScope->functionOf) currScope = currScope->functionOf; else From 3e673938371d1efba51f43849ef7a54587e0d398 Mon Sep 17 00:00:00 2001 From: Oleksandr Labetskyi Date: Fri, 9 Feb 2024 11:56:13 +0200 Subject: [PATCH 4/7] Fix --- lib/symboldatabase.cpp | 57 ++++++++++++++++++++++-------------------- test/testunusedvar.cpp | 2 +- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index bf98f424949..b202e5395ce 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -720,31 +720,6 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() else if (scope->type == Scope::eCatch) scope->checkVariable(tok->tokAt(2), AccessControl::Throw, mSettings); // check for variable declaration and add it to new scope if found tok = scopeStartTok; - } else if (Token::Match(tok, "%name% (")) { - const Token *funcStart = nullptr; - const Token *argStart = nullptr; - const Token *declEnd = nullptr; - if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) { - if (declEnd && declEnd->str() == ";") { - bool newFunc = true; // Is this function already in the database? - auto range = scope->functionMap.equal_range(tok->str()); - for (std::multimap::const_iterator it = range.first; it != range.second; ++it) { - if (it->second->argsMatch(scope, it->second->argDef, argStart, emptyString, 0)) { - newFunc = false; - break; - } - } - // save function prototype in database - if (newFunc) { - Function function(tok, scope, funcStart, argStart); - if(function.isExtern()) - scope->addFunction(std::move(function)); - } - tok = declEnd; - continue; - } - } - } else if (Token::Match(tok, "%var% {")) { endInitList.emplace(tok->next()->link(), scope); tok = tok->next(); @@ -762,6 +737,32 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() } else { tok = tok->link(); } + } else if (Token::Match(tok, "%name% (")) { + if (tok->next() && Token::Match(tok->next()->link(), ") ;")) { + const Token *funcStart = nullptr; + const Token *argStart = nullptr; + const Token *declEnd = nullptr; + if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) { + if (declEnd && declEnd->str() == ";") { + bool newFunc = true; // Is this function already in the database? + auto range = scope->functionMap.equal_range(tok->str()); + for (std::multimap::const_iterator it = range.first; it != range.second; ++it) { + if (it->second->argsMatch(scope, it->second->argDef, argStart, emptyString, 0)) { + newFunc = false; + break; + } + } + // save function prototype in database + if (newFunc) { + Function function(tok, scope, funcStart, argStart); + if (function.isExtern()) + scope->addFunction(std::move(function)); + } + tok = declEnd; + continue; + } + } + } } // syntax error? if (!scope) @@ -5917,8 +5918,10 @@ const Function* SymbolDatabase::findFunction(const Token* const tok) const // find the scope this function is in const Scope *currScope = tok->scope(); while (currScope && currScope->isExecutable()) { - if (const Function* f = currScope->findFunction(tok)) - return f; + if (const Function* f = currScope->findFunction(tok)) { + if (f->isExtern()) + return f; + } if (currScope->functionOf) currScope = currScope->functionOf; else diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 3a8bbeed294..5cdda345544 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -6957,7 +6957,7 @@ class TestUnusedVar : public TestFixture { " int x = 0;\n" " std::for_each(ints.begin(), ints.end(), [&x](int i){ x += i; });\n" "}"); - TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'x' is assigned a value that is never used.\n", "", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'x' is assigned a value that is never used.\n", errout.str()); } void namespaces() { // #7557 From 73e6517b54cdc6399331a028e9c6ec4b6595014f Mon Sep 17 00:00:00 2001 From: Oleksandr Labetskyi Date: Fri, 9 Feb 2024 13:10:50 +0200 Subject: [PATCH 5/7] Add test --- lib/symboldatabase.cpp | 7 ++++--- test/testsymboldatabase.cpp | 14 ++++++++++++++ test/testunusedvar.cpp | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index b202e5395ce..21df3f8cc63 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -738,7 +738,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() tok = tok->link(); } } else if (Token::Match(tok, "%name% (")) { - if (tok->next() && Token::Match(tok->next()->link(), ") ;")) { + if (tok->next() && Token::simpleMatch(tok->next()->link(), ") ;")) { const Token *funcStart = nullptr; const Token *argStart = nullptr; const Token *declEnd = nullptr; @@ -755,10 +755,11 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() // save function prototype in database if (newFunc) { Function function(tok, scope, funcStart, argStart); - if (function.isExtern()) + if (function.isExtern()) { scope->addFunction(std::move(function)); + tok = declEnd; + } } - tok = declEnd; continue; } } diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index f4a313171fe..3310101dd98 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -269,6 +269,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(memberFunctionOfUnknownClassMacro2); TEST_CASE(memberFunctionOfUnknownClassMacro3); TEST_CASE(functionLinkage); + TEST_CASE(externalFunctionsInsideAFunction); // #12420 TEST_CASE(classWithFriend); @@ -2298,6 +2299,19 @@ class TestSymbolDatabase : public TestFixture { ASSERT(f && f->function() && !f->function()->isExtern() && f->function()->retDef->str() == "void"); } + void externalFunctionsInsideAFunction() { + GET_SYMBOL_DB("void foo( void )\n" + "{\n" + " extern void bar( void );\n" + " bar();\n" + "}\n"); + + ASSERT(db && errout.str().empty()); + + const Token *f = Token::findsimplematch(tokenizer.tokens(), "bar"); + ASSERT(f && f->function() && f->function()->isExtern() && f->function()->retDef->str() == "void"); + } + void classWithFriend() { GET_SYMBOL_DB("class Foo {}; class Bar1 { friend class Foo; }; class Bar2 { friend Foo; };"); // 3 scopes: Global, 3 classes diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 5cdda345544..3a8bbeed294 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -6957,7 +6957,7 @@ class TestUnusedVar : public TestFixture { " int x = 0;\n" " std::for_each(ints.begin(), ints.end(), [&x](int i){ x += i; });\n" "}"); - ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'x' is assigned a value that is never used.\n", errout.str()); + TODO_ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'x' is assigned a value that is never used.\n", "", errout.str()); } void namespaces() { // #7557 From 0d1a400366383320cf61d37b8605c876f96b7b67 Mon Sep 17 00:00:00 2001 From: Oleksandr Labetskyi Date: Mon, 12 Feb 2024 12:49:35 +0200 Subject: [PATCH 6/7] Test fix --- lib/symboldatabase.cpp | 2 +- test/testsymboldatabase.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 21df3f8cc63..bdafc33e88e 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -738,7 +738,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() tok = tok->link(); } } else if (Token::Match(tok, "%name% (")) { - if (tok->next() && Token::simpleMatch(tok->next()->link(), ") ;")) { + if (Token::simpleMatch(tok->linkAt(1), ") ;")) { const Token *funcStart = nullptr; const Token *argStart = nullptr; const Token *declEnd = nullptr; diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 3310101dd98..533d44b5120 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -2309,7 +2309,10 @@ class TestSymbolDatabase : public TestFixture { ASSERT(db && errout.str().empty()); const Token *f = Token::findsimplematch(tokenizer.tokens(), "bar"); - ASSERT(f && f->function() && f->function()->isExtern() && f->function()->retDef->str() == "void"); + ASSERT(f && f->function() && f->function()->isExtern() && f == f->function()->tokenDef && f->function()->retDef->str() == "void"); + + const Token *call = Token::findsimplematch(f->next(), "bar"); + ASSERT(call && call->function() && call->function()->isExtern() && call->function() == f->function()); } void classWithFriend() { From e16011163f939dec46afce54e3159c9096a63dc2 Mon Sep 17 00:00:00 2001 From: Oleksandr Labetskyi Date: Mon, 12 Feb 2024 12:57:30 +0200 Subject: [PATCH 7/7] Another small nit --- test/testsymboldatabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 533d44b5120..3b7b0818619 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -2312,7 +2312,7 @@ class TestSymbolDatabase : public TestFixture { ASSERT(f && f->function() && f->function()->isExtern() && f == f->function()->tokenDef && f->function()->retDef->str() == "void"); const Token *call = Token::findsimplematch(f->next(), "bar"); - ASSERT(call && call->function() && call->function()->isExtern() && call->function() == f->function()); + ASSERT(call && call->function() == f->function()); } void classWithFriend() {