From cddaa6d6712e91147534f7a8a1b4cb8bf08d957f Mon Sep 17 00:00:00 2001 From: Ken-Patrick Lehrmann Date: Mon, 29 Mar 2021 12:16:02 +0200 Subject: [PATCH] 10221: Fix setVarId in template code (#3187) The computation of the classname was not expecting templates. Simply skipping the template part seems to fix the issue. --- lib/tokenize.cpp | 13 +++++++++---- test/testvarid.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 43b17ed95..b92675486 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4175,7 +4175,7 @@ void Tokenizer::setVarIdPass2() while (tok->str() == "}" && !scopeInfo.empty() && tok == scopeInfo.back().bodyEnd) scopeInfo.pop_back(); - if (!Token::Match(tok, "namespace|class|struct %name% {|:|::")) + if (!Token::Match(tok, "namespace|class|struct %name% {|:|::|<")) continue; const std::string &scopeName(getScopeName(scopeInfo)); @@ -4184,9 +4184,14 @@ void Tokenizer::setVarIdPass2() std::list classnameTokens; classnameTokens.push_back(tok->next()); const Token* tokStart = tok->tokAt(2); - while (Token::Match(tokStart, ":: %name%")) { - classnameTokens.push_back(tokStart->next()); - tokStart = tokStart->tokAt(2); + while (Token::Match(tokStart, ":: %name%") || tokStart->str() == "<") { + if (tokStart->str() == "<") { + // skip the template part + tokStart = tokStart->findClosingBracket()->next(); + } else { + classnameTokens.push_back(tokStart->next()); + tokStart = tokStart->tokAt(2); + } } std::string classname; diff --git a/test/testvarid.cpp b/test/testvarid.cpp index db04e2c04..492050329 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -195,6 +195,7 @@ private: TEST_CASE(varidclass19); // initializer list TEST_CASE(varidclass20); // #7578: int (*p)[2] TEST_CASE(varid_classnameshaddowsvariablename); // #3990 + TEST_CASE(varid_classnametemplate); // #10221 TEST_CASE(varidenum1); TEST_CASE(varidenum2); @@ -3211,6 +3212,37 @@ private: } + void varid_classnametemplate() { + const char code[] = "template \n" + "struct BBB {\n" + " struct inner;\n" + "};\n" + "\n" + "template \n" + "struct BBB::inner {\n" + " inner(int x);\n" + " int x;\n" + "};\n" + "\n" + "template \n" + "BBB::inner::inner(int x): x(x) {}\n"; + const char expected[] = "1: template < typename T >\n" + "2: struct BBB {\n" + "3: struct inner ;\n" + "4: } ;\n" + "5:\n" + "6: template < typename T >\n" + "7: struct BBB < T > :: inner {\n" + "8: inner ( int x@1 ) ;\n" + "9: int x@2 ;\n" + "10: } ;\n" + "11:\n" + "12: template < typename T >\n" + "13: BBB < T > :: inner :: inner ( int x@3 ) : x@2 ( x@3 ) { }\n"; + ASSERT_EQUALS(expected, tokenize(code)); + + } + void varidnamespace1() { const char code[] = "namespace A {\n" " char buf[20];\n"