Skip to content

Commit a495357

Browse files
authored
fix #10127 (debug: Executable scope 'x' with unknown function.) (cppcheck-opensource#3077)
1 parent c860de8 commit a495357

2 files changed

Lines changed: 60 additions & 3 deletions

File tree

lib/tokenize.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1996,6 +1996,36 @@ bool Tokenizer::isMemberFunction(const Token *openParen) const
19961996
isFunctionHead(openParen, "{|:");
19971997
}
19981998

1999+
static bool scopesMatch(const std::string &scope1, const std::string &scope2, const std::list<ScopeInfo3> &scopeList)
2000+
{
2001+
if (scope1.empty() || scope2.empty())
2002+
return false;
2003+
2004+
// check if scopes match
2005+
if (scope1 == scope2)
2006+
return true;
2007+
2008+
if (scopeList.size() < 2)
2009+
return false;
2010+
2011+
// check if scopes only differ by global qualification
2012+
if (scope1 == (":: " + scope2)) {
2013+
std::string::size_type end = scope2.find_first_of(' ');
2014+
if (end == std::string::npos)
2015+
end = scope2.size();
2016+
if ((++scopeList.begin())->name == scope2.substr(0, end))
2017+
return true;
2018+
} else if (scope2 == (":: " + scope1)) {
2019+
std::string::size_type end = scope1.find_first_of(' ');
2020+
if (end == std::string::npos)
2021+
end = scope1.size();
2022+
if ((++scopeList.begin())->name == scope1.substr(0, end))
2023+
return true;
2024+
}
2025+
2026+
return false;
2027+
}
2028+
19992029
bool Tokenizer::simplifyUsing()
20002030
{
20012031
bool substitute = false;
@@ -2159,7 +2189,7 @@ bool Tokenizer::simplifyUsing()
21592189
// remove the qualification
21602190
std::string fullScope = scope;
21612191
std::string removed;
2162-
while (tok1->strAt(-1) == "::") {
2192+
while (Token::Match(tok1->tokAt(-2), "%name% ::") && !tok1->tokAt(-2)->isKeyword()) {
21632193
removed = (tok1->strAt(-2) + " :: ") + removed;
21642194
if (fullScope == tok1->strAt(-2)) {
21652195
tok1->deletePrevious();
@@ -2180,6 +2210,12 @@ bool Tokenizer::simplifyUsing()
21802210
}
21812211
}
21822212

2213+
// remove global namespace if present
2214+
if (tok1->strAt(-1) == "::") {
2215+
removed.insert(0, ":: ");
2216+
tok1->deletePrevious();
2217+
}
2218+
21832219
Token * arrayStart = nullptr;
21842220

21852221
// parse the type
@@ -2297,7 +2333,7 @@ bool Tokenizer::simplifyUsing()
22972333
std::string::size_type idx = removed1.rfind(" ::");
22982334
if (idx != std::string::npos)
22992335
removed1.resize(idx);
2300-
if (removed1 == scope && !removed1.empty()) {
2336+
if (scopesMatch(removed1, scope, scopeList)) {
23012337
for (std::list<ScopeInfo3>::const_reverse_iterator it = scopeList.crbegin(); it != scopeList.crend(); ++it) {
23022338
if (it->recordTypes.find(start->str()) != it->recordTypes.end()) {
23032339
std::string::size_type spaceIdx = 0;

test/testsymboldatabase.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,8 @@ class TestSymbolDatabase: public TestFixture {
402402
TEST_CASE(findFunction35);
403403
TEST_CASE(findFunction36); // #10122
404404
TEST_CASE(findFunction37); // #10124
405-
TEST_CASE(findFunction38); // #10152
405+
TEST_CASE(findFunction38); // #10125
406+
TEST_CASE(findFunction39); // #10127
406407
TEST_CASE(findFunctionContainer);
407408
TEST_CASE(findFunctionExternC);
408409
TEST_CASE(findFunctionGlobalScope); // ::foo
@@ -6322,6 +6323,26 @@ class TestSymbolDatabase: public TestFixture {
63226323
ASSERT_EQUALS(6, functok->function()->tokenDef->linenr());
63236324
}
63246325

6326+
void findFunction39() { // #10127
6327+
GET_SYMBOL_DB("namespace external {\n"
6328+
" class V {\n"
6329+
" public:\n"
6330+
" using I = int;\n"
6331+
" };\n"
6332+
"}\n"
6333+
"class A {\n"
6334+
" void f(external::V::I);\n"
6335+
"};\n"
6336+
"using ::external::V;\n"
6337+
"void A::f(V::I) {}");
6338+
ASSERT_EQUALS("", errout.str());
6339+
const Token *functok = Token::findsimplematch(tokenizer.tokens(), "f ( int )");
6340+
ASSERT(functok);
6341+
ASSERT(functok->function());
6342+
ASSERT(functok->function()->name() == "f");
6343+
ASSERT_EQUALS(8, functok->function()->tokenDef->linenr());
6344+
}
6345+
63256346
void findFunctionContainer() {
63266347
{
63276348
GET_SYMBOL_DB("void dostuff(std::vector<int> v);\n"

0 commit comments

Comments
 (0)