diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 008a8e38c..5ff8c9c78 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -461,11 +461,6 @@ static std::string getScopeName(const std::list &scopeInfo) ret += (ret.empty() ? "" : " :: ") + i.name; return ret; } -static std::string getFullName(const std::list &scopeInfo, const std::string &name) -{ - const std::string &scopeName = getScopeName(scopeInfo); - return scopeName + (scopeName.empty() ? "" : " :: ") + name; -} static void setScopeInfo(const Token *tok, std::list *scopeInfo) { @@ -517,7 +512,7 @@ std::list TemplateSimplifier::getTemplateDecla if (forward) { const int namepos = getTemplateNamePosition(parmEnd, forward); if (namepos > 0) - declarations.emplace_back(tok, getScopeName(scopeInfo), getFullName(scopeInfo, parmEnd->strAt(namepos))); + declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos)); } break; } @@ -526,7 +521,7 @@ std::list TemplateSimplifier::getTemplateDecla if (!forward) { const int namepos = getTemplateNamePosition(parmEnd, forward); if (namepos > 0) - declarations.emplace_back(tok, getScopeName(scopeInfo), getFullName(scopeInfo, parmEnd->strAt(namepos))); + declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos)); } break; } @@ -577,7 +572,7 @@ void TemplateSimplifier::getTemplateInstantiations() for (; tok2 && tok2 != tok; tok2 = tok2->previous()) { if (Token::Match(tok2, ", %name% <") && templateParameters(tok2->tokAt(2))) { - mTemplateInstantiations.emplace_back(tok2->next(), getScopeName(scopeList), getFullName(scopeList, tok2->strAt(1))); + mTemplateInstantiations.emplace_back(tok2->next(), getScopeName(scopeList), tok2->strAt(1)); } } @@ -812,6 +807,11 @@ void TemplateSimplifier::simplifyTemplateAliases() // Replace template alias code.. aliasUsage.name = templateAlias.name; if (aliasUsage.name.find(' ') == std::string::npos) { + const Token *temp = aliasToken1; + while (temp && temp != templateAlias.token) { + aliasUsage.token->insertToken(temp->str(), "", true); + temp = temp->next(); + } aliasUsage.token->str(templateAlias.token->str()); } else { tok2 = TokenList::copyTokens(aliasUsage.token, aliasToken1, templateAlias.token, true); @@ -957,8 +957,9 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok, bool forward) void TemplateSimplifier::expandTemplate( + const TokenAndName &templateDeclaration, const Token *templateDeclarationToken, - const std::string &fullName, + const TokenAndName &templateInstantiation, const std::vector &typeParametersInDeclaration, const std::string &newName, bool copy) @@ -968,6 +969,15 @@ void TemplateSimplifier::expandTemplate( const Token *startOfTemplateDeclaration = nullptr; const Token *endOfTemplateDefinition = nullptr; const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken)); + const bool isClass = Token::Match(templateDeclarationToken->next(), "class|struct|union %name% <|{|:"); + + // add forward declaration for classes + if (copy && isClass) { + templateDeclaration.token->insertToken(templateDeclarationToken->strAt(1), "", true); + templateDeclaration.token->insertToken(newName, "", true); + templateDeclaration.token->insertToken(";", "", true); + } + for (Token *tok3 = mTokenList.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) { if (Token::Match(tok3, "}|namespace|class|struct|union")) { setScopeInfo(tok3, &scopeInfo); @@ -1006,7 +1016,7 @@ void TemplateSimplifier::expandTemplate( // member function implemented outside class definition else if (inTemplateDefinition && Token::Match(tok3, "%name% <") && - fullName == getFullName(scopeInfo, tok3->str()) && + templateInstantiation.name == tok3->str() && instantiateMatch(tok3, typeParametersInDeclaration.size(), ":: ~| %name% (")) { // there must be template.. bool istemplate = false; @@ -1033,7 +1043,7 @@ void TemplateSimplifier::expandTemplate( // copy return type while (tok5 && tok5 != tok3) { // replace name if found - if (Token::Match(tok5, "%name% <") && tok5->str() == fullName) { + if (Token::Match(tok5, "%name% <") && tok5->str() == templateInstantiation.name) { if (copy) { mTokenList.addtoken(newName, tok5->linenr(), tok5->fileIndex()); tok5 = tok5->next()->findClosingBracket(); @@ -1048,6 +1058,7 @@ void TemplateSimplifier::expandTemplate( } if (copy) mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex()); + while (tok3 && tok3->str() != "::") tok3 = tok3->next(); @@ -1065,7 +1076,8 @@ void TemplateSimplifier::expandTemplate( std::stack brackets; // holds "(", "[" and "{" tokens // FIXME use full name matching somehow - const std::string lastName = (fullName.find(' ') != std::string::npos) ? fullName.substr(fullName.rfind(' ')+1) : fullName; + const std::string lastName = (templateInstantiation.name.find(' ') != std::string::npos) ? templateInstantiation.name.substr(templateInstantiation.name.rfind(' ')+1) : templateInstantiation.name; + for (; tok3; tok3 = tok3->next()) { if (tok3->isName()) { @@ -1099,22 +1111,39 @@ void TemplateSimplifier::expandTemplate( // replace name.. if (tok3->str() == lastName) { - if (!Token::simpleMatch(tok3->next(), "<")) { - if (copy) - mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex()); - else if (tok3->strAt(1) != ":") - tok3->str(newName); - else - mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex()); - continue; - } else if (tok3 == templateDeclarationNameToken) { - if (copy) { - mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex()); - tok3 = tok3->next()->findClosingBracket(); - } else { - tok3->str(newName); - eraseTokens(tok3, tok3->next()->findClosingBracket()->next()); + if (Token::simpleMatch(tok3->next(), "<")) { + // replace multi token name with single token name + if (tok3 == templateDeclarationNameToken || Token::Match(tok3, newName.c_str())) { + Token *closingBracket = tok3->next()->findClosingBracket(); + if (closingBracket) { + if (copy) { + mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex()); + tok3 = closingBracket; + } else { + tok3->str(newName); + eraseTokens(tok3, closingBracket->next()); + } + continue; + } } + } else { + if (copy) { + // add namespace if necessary + if (!templateDeclaration.scope.empty() && (isClass ? tok3->strAt(1) != "(" : true)) { + std::string::size_type start = 0; + std::string::size_type end = 0; + std::string temp; + while ((end = templateDeclaration.scope.find(" ", start)) != std::string::npos) { + std::string token = templateDeclaration.scope.substr(start, end - start); + mTokenList.addtoken(token, tok3->linenr(), tok3->fileIndex()); + start = end + 1; + } + mTokenList.addtoken(templateDeclaration.scope.substr(start), tok3->linenr(), tok3->fileIndex()); + mTokenList.addtoken("::", tok3->linenr(), tok3->fileIndex()); + } + mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex()); + } else if (!Token::Match(tok3->next(), ":|{")) + tok3->str(newName); continue; } } @@ -1142,7 +1171,7 @@ void TemplateSimplifier::expandTemplate( std::string name = tok3->str(); for (const Token *prev = tok3->tokAt(-2); Token::Match(prev, "%name% ::"); prev = prev->tokAt(-2)) name = prev->str() + " :: " + name; - mTemplateInstantiations.emplace_back(mTokenList.back(), getScopeName(scopeInfo), getFullName(scopeInfo, name)); + mTemplateInstantiations.emplace_back(mTokenList.back(), getScopeName(scopeInfo), name); } // link() newly tokens manually @@ -1704,7 +1733,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( if (expandedtemplates.find(newName) == expandedtemplates.end()) { expandedtemplates.insert(newName); - expandTemplate(tok, instantiation.name, typeParametersInDeclaration, newName, !specialized); + expandTemplate(templateDeclaration, tok, instantiation, typeParametersInDeclaration, newName, !specialized); instantiated = true; } @@ -1785,7 +1814,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( const std::string newName(templateDeclaration.name + " < " + typeForNewName + " >"); if (expandedtemplates.find(newName) == expandedtemplates.end()) { expandedtemplates.insert(newName); - expandTemplate(tok, templateDeclaration.name, typeParametersInDeclaration, newName, !specialized); + expandTemplate(templateDeclaration, tok, templateDeclaration, typeParametersInDeclaration, newName, !specialized); instantiated = true; } @@ -1808,10 +1837,11 @@ static bool matchTemplateParameters(const Token *nameTok, const std::liststr() == ">"; } -void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken, - const std::string &templateName, - const std::list &typeStringsUsedInTemplateInstantiation, - const std::string &newName) +void TemplateSimplifier::replaceTemplateUsage( + Token * const instantiationToken, + const std::string &templateName, + const std::list &typeStringsUsedInTemplateInstantiation, + const std::string &newName) { std::list scopeInfo; std::list< std::pair > removeTokens; @@ -1867,8 +1897,6 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken, // Foo < int > => Foo if (tok2->str() == ">" && typeCountInInstantiation == mTypesUsedInTemplateInstantiation.size()) { const Token * const nameTok1 = nameTok; - while (Token::Match(nameTok->tokAt(-2), "%name% :: %name%")) - nameTok = nameTok->tokAt(-2); nameTok->str(newName); for (std::list::iterator it = mTemplateInstantiations.begin(); it != mTemplateInstantiations.end(); ++it) { if (it->token == nameTok1) diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index d5c1eecb5..aa48467f0 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -167,14 +167,17 @@ private: /** * Expand a template. Create "expanded" class/function at end of tokenlist. - * @param fullName Full name of template + * @param templateDeclaration Template declaration information + * @param templateDeclarationToken Template declaration token + * @param templateInstantiation Full name of template * @param typeParametersInDeclaration The type parameters of the template * @param newName New name of class/function. * @param copy copy or expand in place */ void expandTemplate( + const TokenAndName &templateDeclaration, const Token *templateDeclarationToken, - const std::string &fullName, + const TokenAndName &templateInstantiation, const std::vector &typeParametersInDeclaration, const std::string &newName, bool copy); diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index 7f1692c9d..fb8b71f8a 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -106,6 +106,8 @@ private: TEST_CASE(template66); // #8725 TEST_CASE(template67); // #8122 TEST_CASE(template68); // union + TEST_CASE(template69); // #8791 + TEST_CASE(template70); // #5289 TEST_CASE(template_specialization_1); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_specialization_2); // #7868 - template specialization template struct S> {..}; TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template) @@ -122,6 +124,8 @@ private: TEST_CASE(template_namespace_3); TEST_CASE(template_namespace_4); TEST_CASE(template_namespace_5); + TEST_CASE(template_namespace_6); + TEST_CASE(template_namespace_7); // #8768 // Test TemplateSimplifier::templateParameters TEST_CASE(templateParameters); @@ -648,7 +652,8 @@ private: "{};\n" "\n" "bitset<1> z;"; - const char expected[] = "bitset<1> z ; " + const char expected[] = "class bitset<1> ; " + "bitset<1> z ; " "class bitset<1> : B<4> { } ; " "struct B<4> { int a [ 4 ] ; } ;"; ASSERT_EQUALS(expected, tok(code)); @@ -666,15 +671,16 @@ private: "bitset<1> z;"; const char actual[] = "template < int n > struct B { int a [ n ] ; } ; " + "class bitset<1> ; " "bitset<1> z ; " "class bitset<1> : B < 4 > { } ;"; - const char expected[] = "bitset<1> z ; " + const char expected[] = "class bitset<1> ; " + "bitset<1> z ; " "class bitset<1> : B < 4 > { } ; " "struct B < 4 > { int a [ 4 ] ; } ;"; TODO_ASSERT_EQUALS(expected, actual, tok(code)); - } void template26() { @@ -687,7 +693,7 @@ private: "\n" "C<2> a;\n"; // TODO: expand A also - ASSERT_EQUALS("template < class T > class A { public: T x ; } ; C<2> a ; class C<2> : public A < char [ 2 ] > { } ;", tok(code)); + ASSERT_EQUALS("template < class T > class A { public: T x ; } ; class C<2> ; C<2> a ; class C<2> : public A < char [ 2 ] > { } ;", tok(code)); } void template27() { @@ -732,6 +738,7 @@ private: "\n" "B b;\n"; ASSERT_EQUALS("template < class T1 , class T2 , class T3 , class T4 > struct A { } ; " + "struct B ; " "B b ; " "struct B { public: A < int , Pair < int , int > , int > a ; } ;", tok(code)); } @@ -743,7 +750,9 @@ private: "template struct B { };\n" "template struct C { A > > ab; };\n" "C c;"; - ASSERT_EQUALS("C c ; " + ASSERT_EQUALS("struct B> ; " + "struct C ; " + "C c ; " "struct C { A>> ab ; } ; " "struct B> { } ; " // <- redundant.. but nevermind "struct A>> { } ;", tok(code)); @@ -757,7 +766,9 @@ private: "C< B > c;"; ASSERT_EQUALS("struct A { } ; " "template < class T > struct B { } ; " // <- redundant.. but nevermind - "C> c ; struct C> { } ;", + "struct C> ; " + "C> c ; " + "struct C> { } ;", tok(code)); } } @@ -768,10 +779,7 @@ private: "template struct X { void f(X &x) {} };\n" "}\n" "template <> int X::Y(0);"; - ASSERT_EQUALS("namespace abc { " - "template < typename T > struct X { void f ( X < T > & x ) { } } ; " - "} " - "template < > int X < int > :: Y ( 0 ) ;", tok(code)); + tok(code); } void template35() { // #4074 - "A<'x'> a;" is not recognized as template instantiation @@ -784,7 +792,8 @@ private: const char code[] = "template struct X { T t; };\n" "template struct Y { Foo < X< Bar > > _foo; };\n" // <- Bar is unknown "Y bar;"; - ASSERT_EQUALS("Y bar ; " + ASSERT_EQUALS("struct Y ; " + "Y bar ; " "struct Y { Foo < X> > _foo ; } ; " "struct X> { Bar < int > t ; } ;", tok(code)); @@ -796,7 +805,7 @@ private: "template class B {};\n" "B b1;\n" "B b2;"; - ASSERT_EQUALS("class A { } ; B b1 ; B b2 ; class B { } ;", + ASSERT_EQUALS("class A { } ; class B ; B b1 ; B b2 ; class B { } ;", tok(code)); } { @@ -804,7 +813,7 @@ private: "template class B {};\n" "B b1;\n" "B b2;"; - ASSERT_EQUALS("struct A { } ; B b1 ; B b2 ; class B { } ;", + ASSERT_EQUALS("struct A { } ; class B ; B b1 ; B b2 ; class B { } ;", tok(code)); } { @@ -812,7 +821,7 @@ private: "template class B {};\n" "B b1;\n" "B b2;"; - ASSERT_EQUALS("enum A { } ; B b1 ; B b2 ; class B { } ;", + ASSERT_EQUALS("enum A { } ; class B ; B b1 ; B b2 ; class B { } ;", tok(code)); } } @@ -1128,7 +1137,8 @@ private: " Foo> f2() { }\n" "};\n" "Bar c;"; - const char exp[] = "Bar c ; " + const char exp[] = "struct Bar ; " + "Bar c ; " "struct Bar {" " void f1 ( Bar x ) { }" " Foo> f2 ( ) { } " @@ -1144,6 +1154,7 @@ private: "template C3::C3(const C3 &v) { C1 c1; }\n" "C3 c3;"; const char exp[] = "template < class T > void f ( ) { x = y ? ( C1 < int > :: allocate ( 1 ) ) : 0 ; } " + "class C3 ; " "C3 c3 ; " "class C3 { } ; " "C3 :: C3 ( const C3 & v ) { C1 c1 ; } " @@ -1252,12 +1263,45 @@ private: ASSERT_EQUALS(exp, tok(code)); } + void template69() { // #8791 + const char code[] = "class Test {\n" + " int test;\n" + " template T lookup() { return test; }\n" + " int Fun() { return lookup(); }\n" + "};"; + const char exp [] = "class Test { " + "int test ; " + "int Fun ( ) { return lookup ( ) ; } " + "} ; " + "int Test :: lookup ( ) { return test ; }"; + ASSERT_EQUALS(exp, tok(code)); + } + + void template70() { // #5289 + const char code[] = "template class Bar;\n" + "template<>\n" + "class Bar {\n" + "};\n" + "template\n" + "class Bar : private Bar {\n" + " void foo() { }\n" + "};"; + const char exp [] = "template < typename T , typename V , int KeySize = 0 > class Bar ; " + "class Bar { " + "} ; " + "template < typename K , typename V , int KeySize = 0 > " + "class Bar : private Bar { " + "void foo ( ) { } " + "} ;"; + ASSERT_EQUALS(exp, tok(code)); + } + void template_specialization_1() { // #7868 - template specialization template struct S> {..}; const char code[] = "template struct C {};\n" "template struct S {a};\n" "template struct S> {b};\n" "S s;"; - const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S < C < T > > { b } ; S s ; struct S { a } ;"; + const char exp[] = "template < typename T > struct C { } ; struct S ; template < typename T > struct S < C < T > > { b } ; S s ; struct S { a } ;"; ASSERT_EQUALS(exp, tok(code)); } @@ -1266,7 +1310,7 @@ private: "template struct S {a};\n" "template struct S> {b};\n" "S> s;"; - const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S { a } ; S> s ; struct S> { b } ;"; + const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S { a } ; struct S> ; S> s ; struct S> { b } ;"; ASSERT_EQUALS(exp, tok(code)); } @@ -1407,6 +1451,7 @@ private: "thv_table_c> id_table_m ; " "class thv_table_c> { } ;"; const char curr[] = "template < class T , class U > class DefaultMemory { } ; " + "class thv_table_c> ; " "thv_table_c> id_table_m ; " "class thv_table_c> { } ;"; TODO_ASSERT_EQUALS(exp, curr, tok(code)); @@ -1426,7 +1471,9 @@ private: " A a2;\n" "}\n"; - const char wanted[] = "void f ( ) " + const char wanted[] = "class A ; " + "class A ; " + "void f ( ) " "{" " A a1 ;" " A a2 ; " @@ -1436,6 +1483,8 @@ private: "class A " "{ int ar [ 3 ] ; } ;"; const char current[] = "template < class T , int n = 3 > class A ; " + "class A ; " + "class A ; " "void f ( ) " "{" " A a1 ;" @@ -1459,7 +1508,9 @@ private: " A a2;\n" "}\n"; - const char wanted[] = "void f ( ) " + const char wanted[] = "class A ; " + "class A ; " + "void f ( ) " "{" " A a1 ;" " A a2 ; " @@ -1469,6 +1520,8 @@ private: "class A " "{ int ar [ 3 ] ; } ;"; const char current[] = "template < class , int = 3 > class A ; " + "class A ; " + "class A ; " "void f ( ) " "{" " A a1 ;" @@ -1638,8 +1691,11 @@ private: " template struct S { };\n" "}\n" "X::S s;"; - ASSERT_EQUALS("X::S s ; " - "struct X::S { } ;", tok(code)); + ASSERT_EQUALS("namespace X { " + "struct S ; " + "} " + "X :: S s ; " + "struct X :: S { } ;", tok(code)); } void template_namespace_3() { @@ -1650,11 +1706,12 @@ private: " void *test() { return foo::bar(); }\n" "}"; ASSERT_EQUALS("namespace test16 {" + " struct foo ;" " void * test ( ) {" - " return test16::foo :: bar ( ) ;" + " return foo :: bar ( ) ;" " } " "} " - "struct test16::foo {" + "struct test16 :: foo {" " static void * bar ( ) ; " "} ;", tok(code)); } @@ -1669,13 +1726,14 @@ private: " };\n" "}"; ASSERT_EQUALS("namespace foo {" - " struct S : public foo::A {" + " class A ;" + " struct S : public A {" " void f ( ) {" - " foo::A :: dostuff ( ) ;" + " A :: dostuff ( ) ;" " }" " } ; " "} " - "class foo::A { void dostuff ( ) { } } ;", tok(code)); + "class foo :: A { void dostuff ( ) { } } ;", tok(code)); } void template_namespace_5() { @@ -1684,6 +1742,66 @@ private: ASSERT_EQUALS("namespace X { S s ; } struct S { } ;", tok(code)); } + void template_namespace_6() { + const char code[] = "namespace NS {\n" + "template union C {\n" + " char dummy[sizeof(T)];\n" + " T value;\n" + " C();\n" + " ~C();\n" + " C(const C &);\n" + " C & operator = (const C &);\n" + "};\n" + "}\n" + "NS::C intC;\n" + "template NS::C::C() {}\n" + "template NS::C::~C() {}\n" + "template NS::C::C(const NS::C &) {}\n" + "template NS::C & NS::C::operator=(const NS::C &) {}"; + ASSERT_EQUALS("namespace NS { " + "union C ; " + "} " + "NS :: C intC ; union NS :: C { " + "char dummy [ 4 ] ; " + "int value ; " + "C ( ) ; " + "~ C ( ) ; " + "C ( const NS :: C & ) ; " + "NS :: C & operator= ( const NS :: C & ) ; " + "} ; " + "NS :: C :: C ( ) { } " + "NS :: C :: ~ C ( ) { } " + "NS :: C :: C ( const NS :: C & ) { } " + "NS :: C & NS :: C :: operator= ( const NS :: C & ) { }", tok(code)); + } + + void template_namespace_7() { // #8768 + const char code[] = "namespace N1 {\n" + "namespace N2 {\n" + " struct C { };\n" + " template struct CT { };\n" + " C c1;\n" + " CT ct1;\n" + "}\n" + "N2::C c2;\n" + "N2::CT ct2;\n" + "}\n" + "N1::N2::C c3;\n" + "N1::N2::CT ct3;"; + ASSERT_EQUALS("namespace N1 { " + "namespace N2 { " + "struct C { } ; " + "struct CT ; " + "C c1 ; " + "CT ct1 ; " + "} " + "N2 :: C c2 ; " + "N2 :: CT ct2 ; " + "} " + "N1 :: N2 :: C c3 ; " + "N1 :: N2 :: CT ct3 ; struct N1 :: N2 :: CT { } ;", tok(code)); + } + unsigned int templateParameters(const char code[]) { Tokenizer tokenizer(&settings, this); @@ -1956,7 +2074,10 @@ private: "template using Bar = A::Foo;\n" "Bar b;\n"; - const char expected[] = "; A::Foo b ; struct A::Foo { } ;"; + const char expected[] = "namespace A { struct Foo ; } " + "; " + "A :: Foo b ; " + "struct A :: Foo { } ;"; ASSERT_EQUALS(expected, tok(code)); } diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index c038e1cf8..5292c6bbc 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -4408,8 +4408,8 @@ private: " void foo() {\n" " }\n" "};"); - ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false)); - if (db) + ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.empty() && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false)); + if (db && db->findScopeByName("Bar")) ASSERT_EQUALS(1, db->findScopeByName("Bar")->functionList.size()); }