Skip to content

Commit 63b5854

Browse files
IOBYTEdanmar
authored andcommitted
Fixed cppcheck-opensource#4386 (False positive: ctor not detected)
1 parent b99d3f0 commit 63b5854

3 files changed

Lines changed: 55 additions & 4 deletions

File tree

lib/symboldatabase.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
5454
// find all scopes
5555
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
5656
// Locate next class
57-
if (Token::Match(tok, "class|struct|union|namespace ::| %var% {|:|::")) {
57+
if (Token::Match(tok, "class|struct|union|namespace ::| %var% {|:|::") &&
58+
tok->strAt(-1) != "friend") {
5859
const Token *tok2 = tok->tokAt(2);
5960

6061
if (tok->strAt(1) == "::")
@@ -429,10 +430,25 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
429430
}
430431

431432
// friend class declaration?
432-
else if (Token::Match(tok, "friend class| %any% ;")) {
433+
else if (Token::Match(tok, "friend class| ::| %any% ;|::")) {
433434
Scope::FriendInfo friendInfo;
434435

435-
friendInfo.name = tok->strAt(1) == "class" ? tok->strAt(2) : tok->strAt(1);
436+
// save the name start
437+
friendInfo.nameStart = tok->strAt(1) == "class" ? tok->tokAt(2) : tok->tokAt(1);
438+
friendInfo.nameEnd = friendInfo.nameStart;
439+
440+
// skip leading "::"
441+
if (friendInfo.nameEnd->str() == "::")
442+
friendInfo.nameEnd = friendInfo.nameEnd->next();
443+
444+
// skip qualification "name ::"
445+
while (friendInfo.nameEnd && friendInfo.nameEnd->strAt(1) == "::")
446+
friendInfo.nameEnd = friendInfo.nameEnd->tokAt(2);
447+
448+
// save the name
449+
if (friendInfo.nameEnd)
450+
friendInfo.name = friendInfo.nameEnd->str();
451+
436452
// fill this in after parsing is complete
437453
friendInfo.scope = 0;
438454

@@ -641,7 +657,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
641657
for (std::list<Scope::FriendInfo>::iterator i = it->friendList.begin(); i != it->friendList.end(); ++i) {
642658
for (std::list<Scope>::iterator j = scopeList.begin(); j != scopeList.end(); ++j) {
643659
// check scope for match
644-
scope = const_cast<Scope*>(j->findQualifiedScope(i->name));
660+
scope = findScope(i->nameStart, it->nestedIn);
645661

646662
// found match?
647663
if (scope && scope->isClassOrStruct()) {
@@ -1574,6 +1590,24 @@ void SymbolDatabase::printOut(const char *title) const
15741590

15751591
std::cout << " )" << std::endl;
15761592

1593+
std::cout << " friendList[" << scope->friendList.size() << "] = (";
1594+
1595+
std::list<Scope::FriendInfo>::const_iterator fii;
1596+
1597+
count = scope->friendList.size();
1598+
for (fii = scope->friendList.begin(); fii != scope->friendList.end(); ++fii) {
1599+
if (fii->scope)
1600+
std::cout << fii->scope->type;
1601+
else
1602+
std::cout << " Unknown";
1603+
1604+
std::cout << " " << fii->name;
1605+
if (count-- > 1)
1606+
std::cout << ",";
1607+
}
1608+
1609+
std::cout << " )" << std::endl;
1610+
15771611
std::cout << " nestedIn: " << scope->nestedIn;
15781612
if (scope->nestedIn) {
15791613
std::cout << " " << scope->nestedIn->type << " "

lib/symboldatabase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ class CPPCHECKLIB Scope {
445445
};
446446

447447
struct FriendInfo {
448+
const Token *nameStart;
449+
const Token *nameEnd;
448450
std::string name;
449451
Scope *scope;
450452
};

test/testclass.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class TestClass : public TestFixture {
5050
TEST_CASE(noConstructor3);
5151
TEST_CASE(noConstructor4);
5252
TEST_CASE(noConstructor5);
53+
TEST_CASE(noConstructor6); // ticket #4386
5354

5455
TEST_CASE(operatorEq1);
5556
TEST_CASE(operatorEq2);
@@ -1881,6 +1882,20 @@ class TestClass : public TestFixture {
18811882
ASSERT_EQUALS("", errout.str());
18821883
}
18831884

1885+
void noConstructor6() {
1886+
// ticket #4386
1887+
checkNoConstructor("class Ccpucycles {\n"
1888+
" friend class foo::bar;\n"
1889+
" Ccpucycles() :\n"
1890+
" m_v(0), m_b(true)\n"
1891+
" {}\n"
1892+
"private:\n"
1893+
" cpucyclesT m_v;\n"
1894+
" bool m_b;\n"
1895+
"};\n");
1896+
ASSERT_EQUALS("", errout.str());
1897+
}
1898+
18841899
void checkNoMemset(const char code[]) {
18851900
// Clear the error log
18861901
errout.str("");

0 commit comments

Comments
 (0)