diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index d007b858e15..07a28e397c3 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -173,6 +173,30 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() const bool doProgress = (mSettings.reportProgress != -1); + std::map> forwardDecls; + + const std::function findForwardDeclScope = [&](const Token *tok, Scope *startScope) { + if (tok->str() == "::") + return findForwardDeclScope(tok->next(), &scopeList.front()); + + if (Token::Match(tok, "%name% :: %name%")) { + auto it = std::find_if(startScope->nestedList.cbegin(), startScope->nestedList.cend(), [&](const Scope *scope) { + return scope->className == tok->str(); + }); + + if (it == startScope->nestedList.cend()) + return static_cast(nullptr); + + return findForwardDeclScope(tok->tokAt(2), *it); + } + + auto it = forwardDecls.find(startScope); + if (it == forwardDecls.cend()) + return static_cast(nullptr); + + return it->second.count(tok->str()) > 0 ? startScope : nullptr; + }; + // find all scopes for (const Token *tok = mTokenizer.tokens(); tok; tok = tok ? tok->next() : nullptr) { // #5593 suggested to add here: @@ -291,7 +315,11 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() scope = new_scope; tok = tok2; } else { - scopeList.emplace_back(*this, tok, scope); + + const Scope *forwardDeclScope = findForwardDeclScope(tok->next(), scope); + const Scope *nestedIn = forwardDeclScope ? forwardDeclScope : scope; + + scopeList.emplace_back(*this, tok, nestedIn); new_scope = &scopeList.back(); if (tok->str() == "class") @@ -303,7 +331,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() if (new_scope->isClassOrStructOrUnion() || new_scope->type == ScopeType::eEnum) { Type* new_type = findType(name, scope); if (!new_type) { - typeList.emplace_back(new_scope->classDef, new_scope, scope); + typeList.emplace_back(new_scope->classDef, new_scope, nestedIn); new_type = &typeList.back(); scope->definedTypesMap[new_type->name()] = new_type; } else @@ -386,6 +414,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() typeList.emplace_back(tok, nullptr, scope); Type* new_type = &typeList.back(); scope->definedTypesMap[new_type->name()] = new_type; + forwardDecls[scope].insert(tok->strAt(1)); } tok = tok->tokAt(2); } diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 147f53b257f..790f92565bb 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -319,6 +319,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(namespaces2); TEST_CASE(namespaces3); // #3854 - unknown macro TEST_CASE(namespaces4); + TEST_CASE(namespaces5); // #13967 TEST_CASE(needInitialization); TEST_CASE(tryCatch1); @@ -3209,6 +3210,19 @@ class TestSymbolDatabase : public TestFixture { ASSERT_EQUALS(2U, fredAType->classDef->linenr()); } + void namespaces5() { // #13967 + GET_SYMBOL_DB("namespace test {\n" + " template \n" + " struct Test { int x[S]; };\n" + " const Test<64> test;\n" + "}\n"); + const Variable *x = db->getVariableFromVarId(2U); + ASSERT_EQUALS("x", x->name()); + const Scope *scope = x->scope(); + ASSERT(scope->nestedIn); + ASSERT_EQUALS("test", scope->nestedIn->className); + } + void needInitialization() { { GET_SYMBOL_DB_DBG("template \n" // #10259