diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 472c125c0..90c1e3b7b 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -774,8 +774,16 @@ void TemplateSimplifier::expandTemplate( std::list &templateInstantiations) { bool inTemplateDefinition=false; + const Token *endOfTemplateDefinition = nullptr; std::vector localTypeParametersInDeclaration; for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) { + if (inTemplateDefinition) { + if (!endOfTemplateDefinition && tok3->str() == "{") + endOfTemplateDefinition = tok3->link(); + if (tok3 == endOfTemplateDefinition) + inTemplateDefinition = false; + } + if (tok3->str()=="template") { if (tok3->next() && tok3->next()->str()=="<") { TemplateParametersInDeclaration(tok3->tokAt(2), localTypeParametersInDeclaration); @@ -799,6 +807,11 @@ void TemplateSimplifier::expandTemplate( // member function implemented outside class definition else if (inTemplateDefinition && TemplateSimplifier::instantiateMatch(tok3, name, typeParametersInDeclaration.size(), ":: ~| %name% (")) { + const Token *tok4 = tok3->next()->findClosingBracket(); + while (tok4 && tok4->str() != "(") + tok4 = tok4->next(); + if (!Tokenizer::isFunctionHead(tok4, "{:", true)) + continue; tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex()); while (tok3 && tok3->str() != "::") tok3 = tok3->next(); diff --git a/lib/tokenize.h b/lib/tokenize.h index 82bc4204d..9ee23637d 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -504,8 +504,6 @@ public: */ const Token * isFunctionHead(const Token *tok, const std::string &endsWith) const; -private: - /** * is token pointing at function head? * @param tok A '(' or ')' token in a possible function head @@ -515,6 +513,8 @@ private: */ static const Token * isFunctionHead(const Token *tok, const std::string &endsWith, bool cpp); +private: + /** * simplify "while (0)" */ diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index b51f5486b..a69f66209 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -97,6 +97,7 @@ private: TEST_CASE(template57); // #7891 TEST_CASE(template58); // #6021 - use after free (deleted tokens in simplifyCalculations) TEST_CASE(template59); // #8051 - TemplateSimplifier::simplifyTemplateInstantiation failure + TEST_CASE(template60); // handling of methods outside template definition TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template) TEST_CASE(template_unhandled); TEST_CASE(template_default_parameter); @@ -1096,6 +1097,19 @@ private: ASSERT_EQUALS(exp, tok(code)); } + void template60() { // Extracted from Clang testfile + const char code[] = "template struct S { typedef int type; };\n" + "template void f() {}\n" + "template void h() { f::type(0)>(); }\n" + "\n" + "void j() { h(); }"; + const char exp[] = "template < typename T > void f ( ) { } " // <- TODO: This template is not expanded + "void j ( ) { h < int > ( ) ; } " + "void h < int > ( ) { f < S < int > :: type ( 0 ) > ( ) ; } " + "struct S < int > { } ;"; + ASSERT_EQUALS(exp, tok(code)); + } + void template_enum() { const char code1[] = "template \n" "struct Unconst {\n"