diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index fb3cafd69..0d04af68c 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -1056,8 +1056,9 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa void TemplateSimplifier::simplifyTemplateAliases() { - std::list::iterator it1, it2; + std::list::iterator it1, it2, it3; for (it1 = mTemplateInstantiations.begin(); it1 != mTemplateInstantiations.end();) { + it3 = it1; TokenAndName &templateAlias = *it1; ++it1; Token *startToken = templateAlias.token; @@ -1065,13 +1066,15 @@ void TemplateSimplifier::simplifyTemplateAliases() continue; while (Token::Match(startToken->tokAt(-2), "%name% :: %name%")) startToken = startToken->tokAt(-2); - if (!Token::Match(startToken->tokAt(-4), "> using %name% = %name% ::|<")) + if (!(Token::Match(startToken->tokAt(-4), "> using %name% = %name% ::|<") || + Token::Match(startToken->tokAt(-5), "> using %name% = typename %name% ::|<"))) continue; - const std::string aliasName(startToken->strAt(-2)); + const bool hasTypename(startToken->strAt(-1) == "typename"); + const std::string aliasName(startToken->strAt(hasTypename ? -3 : -2)); const Token * const aliasToken1 = startToken; // Get start token for alias - startToken = startToken->tokAt(-5); + startToken = startToken->tokAt(hasTypename ? -6 : -5); while (Token::Match(startToken, "%name%|<|>|>>|,")) startToken = startToken->previous(); // handle case where 'template' is first token @@ -1158,6 +1161,8 @@ void TemplateSimplifier::simplifyTemplateAliases() } endToken = endToken1->next(); + while (endToken->str() != ";") + endToken = endToken->next(); // Remove alias usage code (parameters) Token::eraseTokens(tok2->previous(), args.back().second); @@ -1180,7 +1185,7 @@ void TemplateSimplifier::simplifyTemplateAliases() } // find declaration - const std::list::iterator it3 = std::find_if(mTemplateDeclarations.begin(), + const std::list::iterator it4 = std::find_if(mTemplateDeclarations.begin(), mTemplateDeclarations.end(), FindToken(startToken ? startToken->next() : mTokenList.front())); @@ -1192,9 +1197,10 @@ void TemplateSimplifier::simplifyTemplateAliases() } // remove declaration - if (it3 != mTemplateDeclarations.end()) - mTemplateDeclarations.erase(it3); - } + if (it4 != mTemplateDeclarations.end()) + mTemplateDeclarations.erase(it4); + } else + mTemplateInstantiations.erase(it3); } } @@ -2417,7 +2423,8 @@ std::string TemplateSimplifier::getNewName( { std::string typeForNewName; unsigned int indentlevel = 0; - for (Token *tok3 = tok2->tokAt(2); tok3 && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) { + const Token * endToken = tok2->next()->findClosingBracket(); + for (Token *tok3 = tok2->tokAt(2); tok3 != endToken && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) { // #2648 - unhandled parentheses => bail out // #2721 - unhandled [ => bail out if (Token::Match(tok3, "(|[")) { @@ -2686,10 +2693,11 @@ void TemplateSimplifier::replaceTemplateUsage( // match parameters Token * tok2 = nameTok->tokAt(2); + const Token * endToken = nameTok->next()->findClosingBracket(); unsigned int typeCountInInstantiation = tok2->str() == ">" ? 0U : 1U; const Token *typetok = (!mTypesUsedInTemplateInstantiation.empty()) ? mTypesUsedInTemplateInstantiation[0].token : nullptr; unsigned int indentlevel2 = 0; // indentlevel for tokgt - while (tok2 && (indentlevel2 > 0 || tok2->str() != ">")) { + while (tok2 != endToken && (indentlevel2 > 0 || tok2->str() != ">")) { if (tok2->str() == "<" && templateParameters(tok2) > 0) ++indentlevel2; else if (indentlevel2 > 0 && Token::Match(tok2, "> [,>]")) diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index 4d98107ca..d906e4e79 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -145,6 +145,7 @@ private: TEST_CASE(template105); // #9076 TEST_CASE(template106); TEST_CASE(template107); // #8663 + TEST_CASE(template108); // #9109 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) @@ -2448,6 +2449,88 @@ private: ASSERT_EQUALS(exp, tok(code)); } + void template108() { // #9109 + { + const char code[] = "template struct a;\n" + "template struct b {};\n" + "template struct c;\n" + "template struct e {\n" + " using f = a::g>>;\n" + " bool h = f::h;\n" + "};\n" + "struct i {\n" + " e j();\n" + "};\n"; + const char exp[] = "template < typename > struct a ; " + "struct b::g> ; " + "template < typename > struct c ; " + "struct e ; " + "struct i { e j ( ) ; " + "} ; " + "struct e { bool h ; " + "h = a < b::g> > :: h ; " + "} ; " + "struct b::g> { } ;"; + ASSERT_EQUALS(exp, tok(code)); + } + { + const char code[] = "namespace {\n" + "template struct a;\n" + "template struct b {};\n" + "}\n" + "namespace {\n" + "template struct c;\n" + "template struct e {\n" + " using f = a::g>>;\n" + " bool h = f::h;\n" + "};\n" + "template using j = typename e::g;\n" + "}"; + const char exp[] = "namespace { " + "template < typename > struct a ; " + "template < typename > struct b { } ; " + "} " + "namespace { " + "template < typename > struct c ; " + "template < typename d > struct e { " + "using f = a < b < c < d > :: g > > ; " + "bool h ; h = f :: h ; " + "} ; " + "template < typename i > using j = typename e < i > :: g ; " + "}"; + ASSERT_EQUALS(exp, tok(code)); + } + { + const char code[] = "namespace {\n" + "template struct a;\n" + "template struct b {};\n" + "}\n" + "namespace {\n" + "template struct c;\n" + "template struct e {\n" + " using f = a::g>>;\n" + " bool h = f::h;\n" + "};\n" + "template using j = typename e::g;\n" + "}\n" + "j foo;"; + const char exp[] = "namespace { " + "template < typename > struct a ; " + "struct b::g> ; " + "} " + "namespace { " + "template < typename > struct c ; " + "struct e ; " + "} " + "e foo ; " + "struct e { " + "bool h ; h = a < b::g> > :: h ; " + "} ; " + "struct b::g> { } ;"; + 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" diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 786b9ecc3..311b16b1a 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -7647,6 +7647,21 @@ private: } void checkTemplates() { + // #9109 + ASSERT_NO_THROW(tokenizeAndStringify( + "namespace {\n" + "template struct a;\n" + "template struct b {};\n" + "}\n" + "namespace {\n" + "template struct c;\n" + "template struct e {\n" + " using f = a< b::g> >;\n" + " bool h = f::h;\n" + "};\n" + "template using j = typename e::g;\n" + "}\n")) + ASSERT_NO_THROW(tokenizeAndStringify( "template struct a {\n" " void c();\n" @@ -7666,7 +7681,6 @@ private: "};\n")) } - void noCrash1() { ASSERT_NO_THROW(tokenizeAndStringify( "struct A {\n"