diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 931d9f8e8..f62f57605 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -54,7 +54,8 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti // find all scopes for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { // Locate next class - if (Token::Match(tok, "class|struct|union|namespace ::| %var% {|:|::")) { + if (Token::Match(tok, "class|struct|union|namespace ::| %var% {|:|::") && + tok->strAt(-1) != "friend") { const Token *tok2 = tok->tokAt(2); if (tok->strAt(1) == "::") @@ -429,10 +430,25 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti } // friend class declaration? - else if (Token::Match(tok, "friend class| %any% ;")) { + else if (Token::Match(tok, "friend class| ::| %any% ;|::")) { Scope::FriendInfo friendInfo; - friendInfo.name = tok->strAt(1) == "class" ? tok->strAt(2) : tok->strAt(1); + // save the name start + friendInfo.nameStart = tok->strAt(1) == "class" ? tok->tokAt(2) : tok->tokAt(1); + friendInfo.nameEnd = friendInfo.nameStart; + + // skip leading "::" + if (friendInfo.nameEnd->str() == "::") + friendInfo.nameEnd = friendInfo.nameEnd->next(); + + // skip qualification "name ::" + while (friendInfo.nameEnd && friendInfo.nameEnd->strAt(1) == "::") + friendInfo.nameEnd = friendInfo.nameEnd->tokAt(2); + + // save the name + if (friendInfo.nameEnd) + friendInfo.name = friendInfo.nameEnd->str(); + // fill this in after parsing is complete friendInfo.scope = 0; @@ -641,7 +657,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti for (std::list::iterator i = it->friendList.begin(); i != it->friendList.end(); ++i) { for (std::list::iterator j = scopeList.begin(); j != scopeList.end(); ++j) { // check scope for match - scope = const_cast(j->findQualifiedScope(i->name)); + scope = findScope(i->nameStart, it->nestedIn); // found match? if (scope && scope->isClassOrStruct()) { @@ -1574,6 +1590,24 @@ void SymbolDatabase::printOut(const char *title) const std::cout << " )" << std::endl; + std::cout << " friendList[" << scope->friendList.size() << "] = ("; + + std::list::const_iterator fii; + + count = scope->friendList.size(); + for (fii = scope->friendList.begin(); fii != scope->friendList.end(); ++fii) { + if (fii->scope) + std::cout << fii->scope->type; + else + std::cout << " Unknown"; + + std::cout << " " << fii->name; + if (count-- > 1) + std::cout << ","; + } + + std::cout << " )" << std::endl; + std::cout << " nestedIn: " << scope->nestedIn; if (scope->nestedIn) { std::cout << " " << scope->nestedIn->type << " " diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index e0a7d71d9..367b9df5a 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -445,6 +445,8 @@ public: }; struct FriendInfo { + const Token *nameStart; + const Token *nameEnd; std::string name; Scope *scope; }; diff --git a/test/testclass.cpp b/test/testclass.cpp index fff217092..538dde683 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -50,6 +50,7 @@ private: TEST_CASE(noConstructor3); TEST_CASE(noConstructor4); TEST_CASE(noConstructor5); + TEST_CASE(noConstructor6); // ticket #4386 TEST_CASE(operatorEq1); TEST_CASE(operatorEq2); @@ -1881,6 +1882,20 @@ private: ASSERT_EQUALS("", errout.str()); } + void noConstructor6() { + // ticket #4386 + checkNoConstructor("class Ccpucycles {\n" + " friend class foo::bar;\n" + " Ccpucycles() :\n" + " m_v(0), m_b(true)\n" + " {}\n" + "private:\n" + " cpucyclesT m_v;\n" + " bool m_b;\n" + "};\n"); + ASSERT_EQUALS("", errout.str()); + } + void checkNoMemset(const char code[]) { // Clear the error log errout.str("");