From 8c5013adda7a803aee5f938d864bbd93dec9d45f Mon Sep 17 00:00:00 2001 From: Frank Zingsheim Date: Sun, 7 Sep 2014 21:41:52 +0200 Subject: [PATCH] Fixed #6073 --- lib/tokenize.cpp | 76 ++++++++++++++++++++++++++++++------------- test/testclass.cpp | 21 ++++++++++++ test/testtokenize.cpp | 33 +++++++++++++++++++ 3 files changed, 107 insertions(+), 23 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 2de18f0fe..f76ba5607 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2359,6 +2359,37 @@ static void setVarIdStructMembers(Token **tok1, } +static const Token * findInitListEndToken(const Token *tok) +{ + if (!Token::Match(tok, ") :")) + return nullptr; + + tok = tok->tokAt(2); + + while (tok) { + if (tok && tok->str()=="::") + tok = tok->next(); + + while (tok && Token::Match(tok, "%type% ::")) + tok = tok->tokAt(2); + + if (Token::Match(tok, "%var% [({]")) { + tok = tok->linkAt(1); + if (!tok) + return nullptr; + tok = tok->next(); + } + if (tok && tok->str()==",") + tok = tok->next(); + else if (tok && tok->str()=="{") + return tok; // End of init list found + else + return nullptr; + } + + return nullptr; +} + static void setVarIdClassDeclaration(Token * const startToken, const std::map &variableId, const unsigned int scopeStartVarId, @@ -2381,14 +2412,15 @@ static void setVarIdClassDeclaration(Token * const startToken, // replace varids.. unsigned int indentlevel = 0; - bool initList = false; + const Token * initListEndToken = nullptr; for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) { if (tok->str() == "{") { - initList = false; + if (tok == initListEndToken) + initListEndToken = nullptr; ++indentlevel; } else if (tok->str() == "}") --indentlevel; - else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %var% (")) { + else if (initListEndToken && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %var% [({]")) { const std::map::const_iterator it = variableId.find(tok->str()); if (it != variableId.end()) { tok->varId(it->second); @@ -2411,7 +2443,7 @@ static void setVarIdClassDeclaration(Token * const startToken, } } } else if (indentlevel == 0 && tok->str() == ":") - initList = true; + initListEndToken = findInitListEndToken(tok->previous()); } } @@ -2444,18 +2476,6 @@ static void setVarIdClassFunction(const std::string &classname, } } -static bool isInitList(const Token *tok) -{ - if (!Token::Match(tok, ") : %var% (")) - return false; - - tok = tok->linkAt(3); - while (Token::Match(tok, ") , %var% (")) - tok = tok->linkAt(3); - - return Token::simpleMatch(tok, ") {"); -} - void Tokenizer::setVarId() { // Clear all variable ids @@ -2486,14 +2506,22 @@ void Tokenizer::setVarId() executableScope.push(false); std::stack scopestartvarid; // varid when scope starts scopestartvarid.push(0); - bool initlist = false; + const Token * initListEndToken = nullptr; for (Token *tok = list.front(); tok; tok = tok->next()) { // scope info to handle shadow variables.. - if (!initlist && tok->str() == "(" && - (Token::simpleMatch(tok->link(), ") {") || Token::Match(tok->link(), ") %type% {") || isInitList(tok->link()))) { + bool newScope = false; + if (!initListEndToken && tok->str() == "(") { + if (Token::simpleMatch(tok->link(), ") {") || Token::Match(tok->link(), ") %type% {")) + newScope = true; + else { + initListEndToken = findInitListEndToken(tok->link()); + if (initListEndToken) + newScope = true; + } + } + if (newScope) { scopeInfo.push(variableId); - initlist = Token::simpleMatch(tok->link(), ") :"); // function declarations } else if (!executableScope.top() && tok->str() == "(" && Token::Match(tok->link(), ") const| ;")) { @@ -2503,22 +2531,24 @@ void Tokenizer::setVarId() scopeInfo.pop(); } else if (tok->str() == "{") { - initlist = false; // parse anonymous unions as part of the current scope if (!(tok->strAt(-1) == "union" && Token::simpleMatch(tok->link(), "} ;"))) { scopestartvarid.push(_varId); - if (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%")) { + if (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%") || + tok == initListEndToken) { executableScope.push(true); } else { executableScope.push(tok->strAt(-1) == "else"); scopeInfo.push(variableId); } } + if (tok == initListEndToken) + initListEndToken= nullptr; } else if (tok->str() == "}") { // parse anonymous unions as part of the current scope if (!(Token::simpleMatch(tok, "} ;") && tok->link() && Token::simpleMatch(tok->link()->previous(), "union {"))) { // Set variable ids in class declaration.. - if (!isC() && !executableScope.top() && tok->link()) { + if (!initListEndToken && !isC() && !executableScope.top() && tok->link()) { setVarIdClassDeclaration(tok->link(), variableId, scopestartvarid.top(), diff --git a/test/testclass.cpp b/test/testclass.cpp index ff3355171..7538a87e7 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -5821,6 +5821,27 @@ private: " }\n" "};"); ASSERT_EQUALS("", errout.str()); + + checkSelfInitialization("struct Foo : Bar {\n" + " int i;\n" + " Foo(int i)\n" + " : Bar(""), i(i) {}\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + checkSelfInitialization("struct Foo : std::Bar {\n" // #6073 + " int i;\n" + " Foo(int i)\n" + " : std::Bar(""), i(i) {}\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + checkSelfInitialization("struct Foo : std::Bar {\n" // #6073 + " int i;\n" + " Foo(int i)\n" + " : std::Bar(""), i{i} {}\n" + "};"); + ASSERT_EQUALS("", errout.str()); } void checkPureVirtualFunctionCall(const char code[], const Settings *s = 0, bool inconclusive = true) { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 775a92d33..0d9c82a86 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -337,6 +337,7 @@ private: TEST_CASE(varidclass14); TEST_CASE(varidclass15); // initializer list TEST_CASE(varidclass16); // #4577 + TEST_CASE(varidclass17); // #6073 TEST_CASE(varid_classnameshaddowsvariablename); // #3990 TEST_CASE(varidnamespace1); @@ -4954,6 +4955,21 @@ private: ASSERT_EQUALS("\n\n##file 0\n" "1: class CPPCHECKLIB Scope { } ;\n", tokenizeDebugListing("class CPPCHECKLIB Scope { };")); + + // #6073 + ASSERT_EQUALS("\n\n##file 0\n" + "1: class A : public B , public C :: D {\n" + "2: int i@1 ;\n" + "3: A ( int i@2 ) : B { i@2 } , C :: D { i@2 } , i@1 { i@2 } {\n" + "4: int j@3 { i@2 } ;\n" + "5: }\n" + "6: } ;\n", + tokenizeDebugListing("class A: public B, public C::D {\n" + " int i;\n" + " A(int i): B{i}, C::D{i}, i{i} {\n" + " int j{i};\n" + " }\n" + "};")); } void varid_inheritedMembers() { @@ -5429,6 +5445,23 @@ private: ASSERT_EQUALS(expected, tokenizeDebugListing(code)); } + void varidclass17() { + const char code[] = "class A: public B, public C::D {\n" + " int i;\n" + " A(int i): B(i), C::D(i), i(i) {\n" + " int j(i);\n" + " }\n" + "};"; + const char expected[] = "\n\n##file 0\n" + "1: class A : public B , public C :: D {\n" + "2: int i@1 ;\n" + "3: A ( int i@2 ) : B ( i@2 ) , C :: D ( i@2 ) , i@1 ( i@2 ) {\n" + "4: int j@3 ; j@3 = i@2 ;\n" + "5: }\n" + "6: } ;\n"; + ASSERT_EQUALS(expected, tokenizeDebugListing(code)); + } + void varid_classnameshaddowsvariablename() { const char code[] = "class Data;\n" "void strange_declarated(const Data& Data);\n"