diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 540ea7a41..aadfab8a7 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -236,7 +236,73 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok) return 0; } -void TemplateSimplifier::removeTemplates(Token *tok) +bool TemplateSimplifier::removeTemplate(Token *tok) +{ + if (!Token::simpleMatch(tok, "template <")) + return false; + + int indentlevel = 0; + unsigned int countgt = 0; // Counter for ">" + for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { + + if (tok2->str() == "(") { + tok2 = tok2->link(); + } else if (tok2->str() == ")") { // garbage code! (#3504) + Token::eraseTokens(tok,tok2); + tok->deleteThis(); + return false; + } + + else if (tok2->str() == "{") { + tok2 = tok2->link()->next(); + Token::eraseTokens(tok, tok2); + if (tok2 && tok2->str() == ";" && tok2->next()) + tok->deleteNext(); + tok->deleteThis(); + return true; + } else if (tok2->str() == "}") { // garbage code! (#3449) + Token::eraseTokens(tok,tok2); + tok->deleteThis(); + return false; + } + + // Count ">" + if (tok2->str() == ">") + countgt++; + + // don't remove constructor + if (tok2->str() == "explicit" || + (countgt == 1 && Token::Match(tok2->previous(), "> %type% (") && Token::simpleMatch(tok2->next()->link(), ") {"))) { + Token::eraseTokens(tok, tok2); + tok->deleteThis(); + return true; + } + + if (tok2->str() == ";") { + tok2 = tok2->next(); + Token::eraseTokens(tok, tok2); + tok->deleteThis(); + return true; + } + + if (tok2->str() == "<") + ++indentlevel; + + else if (indentlevel >= 2 && tok2->str() == ">") + --indentlevel; + + else if (Token::Match(tok2, "> class|struct %var% [,)]")) { + tok2 = tok2->next(); + Token::eraseTokens(tok, tok2); + tok->deleteThis(); + return true; + } + } + + return false; +} + +void TemplateSimplifier::removeAllTemplates(Token *tok) { bool goback = false; for (; tok; tok = tok->next()) { @@ -244,70 +310,9 @@ void TemplateSimplifier::removeTemplates(Token *tok) tok = tok->previous(); goback = false; } - if (!Token::simpleMatch(tok, "template <")) - continue; - int indentlevel = 0; - unsigned int countgt = 0; // Counter for ">" - for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { - - if (tok2->str() == "(") { - tok2 = tok2->link(); - } else if (tok2->str() == ")") { // garbage code! (#3504) - Token::eraseTokens(tok,tok2); - tok->deleteThis(); - break; - } - - else if (tok2->str() == "{") { - tok2 = tok2->link()->next(); - Token::eraseTokens(tok, tok2); - if (tok2 && tok2->str() == ";" && tok2->next()) - tok->deleteNext(); - tok->deleteThis(); - goback = true; - break; - } else if (tok2->str() == "}") { // garbage code! (#3449) - Token::eraseTokens(tok,tok2); - tok->deleteThis(); - break; - } - - // Count ">" - if (tok2->str() == ">") - countgt++; - - // don't remove constructor - if (tok2->str() == "explicit" || - (countgt == 1 && Token::Match(tok2->previous(), "> %type% (") && Token::simpleMatch(tok2->next()->link(), ") {"))) { - Token::eraseTokens(tok, tok2); - tok->deleteThis(); - goback = true; - break; - } - - if (tok2->str() == ";") { - tok2 = tok2->next(); - Token::eraseTokens(tok, tok2); - tok->deleteThis(); - goback = true; - break; - } - - if (tok2->str() == "<") - ++indentlevel; - - else if (indentlevel >= 2 && tok2->str() == ">") - --indentlevel; - - else if (Token::Match(tok2, "> class|struct %var% [,)]")) { - tok2 = tok2->next(); - Token::eraseTokens(tok, tok2); - tok->deleteThis(); - goback = true; - break; - } - } + if (tok->str() == "template") + goback = removeTemplate(tok); } } @@ -955,7 +960,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens) } -void TemplateSimplifier::simplifyTemplateInstantions( +bool TemplateSimplifier::simplifyTemplateInstantions( TokenList& tokenlist, ErrorLogger& errorlogger, const Settings *_settings, @@ -976,7 +981,7 @@ void TemplateSimplifier::simplifyTemplateInstantions( // bail out if the end of the file was reached if (!tok) - return; + return false; // get the position of the template name int namepos = TemplateSimplifier::simplifyTemplatesGetTemplateNamePosition(tok); @@ -986,7 +991,7 @@ void TemplateSimplifier::simplifyTemplateInstantions( std::list callstack(1, tok); errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "simplifyTemplates: bailing out", false)); } - return; + return false; } // name of template function/class.. @@ -998,6 +1003,8 @@ void TemplateSimplifier::simplifyTemplateInstantions( std::string::size_type amountOftemplateInstantiations = templateInstantiations.size(); unsigned int recursiveCount = 0; + bool instantiated = false; + for (std::list::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) { if (amountOftemplateInstantiations != templateInstantiations.size()) { amountOftemplateInstantiations = templateInstantiations.size(); @@ -1065,6 +1072,7 @@ void TemplateSimplifier::simplifyTemplateInstantions( if (expandedtemplates.find(newName) == expandedtemplates.end()) { expandedtemplates.insert(newName); TemplateSimplifier::simplifyTemplatesExpandTemplate(tokenlist, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantion,templateInstantiations); + instantiated = true; } // Replace all these template usages.. @@ -1112,6 +1120,9 @@ void TemplateSimplifier::simplifyTemplateInstantions( removeTokens.pop_back(); } } + + // Template has been instantiated .. then remove the template declaration + return instantiated; } @@ -1129,10 +1140,8 @@ void TemplateSimplifier::simplifyTemplates( // this info is used by checks std::list templates(TemplateSimplifier::simplifyTemplatesGetTemplateDeclarations(tokenlist.front(), _codeWithTemplates)); - if (templates.empty()) { - TemplateSimplifier::removeTemplates(tokenlist.front()); + if (templates.empty()) return; - } // There are templates.. // Remove "typename" unless used in template arguments.. @@ -1151,11 +1160,9 @@ void TemplateSimplifier::simplifyTemplates( // Locate possible instantiations of templates.. std::list templateInstantiations(TemplateSimplifier::simplifyTemplatesGetTemplateInstantiations(tokenlist.front())); - // No template instantiations? Then remove all templates. - if (templateInstantiations.empty()) { - TemplateSimplifier::removeTemplates(tokenlist.front()); + // No template instantiations? Then return. + if (templateInstantiations.empty()) return; - } // Template arguments with default values TemplateSimplifier::simplifyTemplatesUseDefaultArgumentValues(templates, templateInstantiations); @@ -1165,14 +1172,24 @@ void TemplateSimplifier::simplifyTemplates( //while (!done) { //done = true; + std::list templates2; for (std::list::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) { - TemplateSimplifier::simplifyTemplateInstantions( - tokenlist, - errorlogger, - _settings, - *iter1, templateInstantiations, expandedtemplates); + bool instantiated = TemplateSimplifier::simplifyTemplateInstantions(tokenlist, + errorlogger, + _settings, + *iter1, + templateInstantiations, + expandedtemplates); + if (instantiated) + templates2.push_back(*iter1); + } + + for (std::list::iterator it = templates2.begin(); it != templates2.end(); ++it) { + std::list::iterator it1 = std::find(templates.begin(), templates.end(), *it); + if (it1 != templates.end()) { + templates.erase(it1); + removeTemplate(*it); + } } } - - TemplateSimplifier::removeTemplates(tokenlist.front()); } diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index f834c4aaa..0c4e3c238 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -64,11 +64,6 @@ public: */ static unsigned int templateParameters(const Token *tok); - /** - * Remove "template < ..." they can cause false positives because they are not expanded - */ - static void removeTemplates(Token *tok); - /** * Expand specialized templates : "template<>.." * @return names of expanded templates @@ -131,8 +126,9 @@ public: * @param tok token where the template declaration begins * @param templateInstantiations a list of template usages (not necessarily just for this template) * @param expandedtemplates all templates that has been expanded so far. The full names are stored. + * @return true if the template was instantiated */ - static void simplifyTemplateInstantions( + static bool simplifyTemplateInstantions( TokenList& tokenlist, ErrorLogger& errorlogger, const Settings *_settings, @@ -160,6 +156,19 @@ public: * false if no modifications are done. */ static bool simplifyCalculations(Token *_tokens); + +private: + + /** + * Remove all "template < ..." they can cause false positives because they are not expanded + */ + static void removeAllTemplates(Token *tok); + + /** + * Remove a specific "template < ..." template class/function + */ + static bool removeTemplate(Token *tok); + }; /// @} diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index c2dc1d284..8bee71a15 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -1649,7 +1649,8 @@ private: "template Fred::Fred() { }\n" "Fred fred;"; - const std::string expected("Fred fred ; " + const std::string expected("template < classname T > Fred < T > :: Fred ( ) { } " // <- TODO: this should be removed + "Fred fred ; " "class Fred { } " "Fred :: Fred ( ) { }"); @@ -1679,7 +1680,7 @@ private: "\n" "};\n"; - const std::string expected(";"); + const std::string expected("template < class T > class ABC { public: } ;"); ASSERT_EQUALS(expected, tok(code)); } @@ -1695,18 +1696,19 @@ private: " return 0;\n" "}\n"; - const std::string wanted("int main ( ) { " + const std::string wanted("template < typename T > class ABC { public: } ; " + "int main ( ) { " "std :: vector < int > v ; " "v . push_back ( 4 ) ; " "return 0 ; " "}"); - const std::string current("int main ( ) { " + const std::string current("template < typename T > class ABC { public: } ; " + "int main ( ) { " "ABC < int > :: type v ; " "v . push_back ( 4 ) ; " "return 0 ; " - "}" - ); + "}"); TODO_ASSERT_EQUALS(wanted, current, tok(code)); } @@ -1722,7 +1724,12 @@ private: " }\n" "};\n"; - const std::string expected(";"); + const std::string expected("template < typename T > class ABC { " + "public: void f ( ) { " + "ABC < int > :: type v ; " + "v . push_back ( 4 ) ; " + "} " + "} ;"); ASSERT_EQUALS(expected, tok(code)); } @@ -1747,9 +1754,12 @@ private: "\n" "template inline B h() { return B(); }\n"; - ASSERT_EQUALS("", tok(code)); + ASSERT_EQUALS("template < typename T > class A ; " + "template < typename T > class B ; " + "template < typename T > class A { void f ( ) { B < T > a ; a = B < T > :: g ( ) ; T b ; b = 0 ; } } ; " + "template < typename T > B < T > h ( ) { return B < T > ( ) ; }", tok(code)); - ASSERT_EQUALS("class A { } ;", tok("class A{ template int foo(T d);};")); + ASSERT_EQUALS("class A { template < typename T > int foo ( T d ) ; } ;", tok("class A{ template int foo(T d);};")); } void template9() { @@ -1767,7 +1777,9 @@ private: "} ;\n"; // The expected result.. - std::string expected("void f ( ) { A a ; } class A { } class A { }"); + std::string expected("void f ( ) { A a ; } " + "template < typename T > class B { void g ( ) { A b ; b = A :: h ( ) ; } } ; " + "class A { } class A { }"); ASSERT_EQUALS(expected, tok(code)); } @@ -1977,7 +1989,8 @@ private: "A a;\n"; // The expected result.. - const std::string expected("A a ; " + const std::string expected("template < class T > A < T > :: ~ A ( ) { } " // <- TODO: this should be removed + "A a ; " "class A { public: ~ A ( ) ; } " "A :: ~ A ( ) { }"); ASSERT_EQUALS(expected, tok(code)); @@ -2014,18 +2027,6 @@ private: ASSERT_EQUALS(expected, tok(code)); } - { - const char code[] = "template struct Fred { };\n" - "template Fred::Fred() { }\n" - "Fred fred;"; - - const std::string expected("Fred fred ; " - "struct Fred { } " - "Fred :: Fred ( ) { }"); - - ASSERT_EQUALS(expected, tok(code)); - } - { const char code[] = "template struct Fred { };\n" "Fred fred1;\n" @@ -2091,7 +2092,8 @@ private: "\n" "bitset<1> z;"; - const char actual[] = "bitset<1> z ; " + const char actual[] = "template < int n > struct B { int a [ n ] ; } ; " + "bitset<1> z ; " "class bitset<1> : B < ( ) > { }"; const char expected[] = "bitset<1> z ; " @@ -2112,13 +2114,13 @@ private: "\n" "C<2> a;\n"; // TODO: expand A also - ASSERT_EQUALS("C<2> a ; class C<2> : public A < char [ 2 ] > { }", tok(code)); + ASSERT_EQUALS("template < class T > class A { public: T x ; } ; C<2> a ; class C<2> : public A < char [ 2 ] > { }", tok(code)); } void template27() { // #3350 - template inside macro call const char code[] = "X(template class Fred);"; - ASSERT_EQUALS("X ( class Fred ) ;", tok(code)); + ASSERT_EQUALS("X ( template < class T > class Fred ) ;", tok(code)); } void template28() { @@ -2133,13 +2135,13 @@ private: const char code[] = "template struct A;\n" "struct B { template struct C };\n" "{};"; - ASSERT_EQUALS("struct B { } ; { } ;", tok(code)); + ASSERT_EQUALS("template < typename T > struct A ; struct B { template < typename T > struct C } ; { } ;", tok(code)); } void template30() { // #3529 - template < template < .. const char code[] = "template class A, class B> void f(){}"; - ASSERT_EQUALS("", tok(code)); + ASSERT_EQUALS("template < template < class > class A , class B > void f ( ) { }", tok(code)); } void template_unhandled() { @@ -2264,7 +2266,7 @@ private: "{ }"; // The expected result.. - const std::string expected(""); + const std::string expected("template < class T > void foo ( T :: t * ) { }"); ASSERT_EQUALS(expected, tok(code)); } @@ -2284,13 +2286,13 @@ private: const char code[] = "class Fred {\n" " template explicit Fred(T t) { }\n" "}"; - ASSERT_EQUALS("class Fred { explicit Fred ( T t ) { } }", tok(code)); + ASSERT_EQUALS("class Fred { template < class T > explicit Fred ( T t ) { } }", tok(code)); // #3532 const char code2[] = "class Fred {\n" " template Fred(T t) { }\n" "}"; - ASSERT_EQUALS("class Fred { Fred ( T t ) { } }", tok(code2)); + ASSERT_EQUALS("class Fred { template < class T > Fred ( T t ) { } }", tok(code2)); } unsigned int templateParameters(const char code[]) { @@ -4465,7 +4467,7 @@ private: void simplifyTypedef39() { const char code[] = "typedef int A;\n" "template ::value;"; - const char expected[] = ""; + const char expected[] = "template < const int , int > :: value ;"; ASSERT_EQUALS(expected, tok(code, false)); checkSimplifyTypedef(code); @@ -4476,7 +4478,7 @@ private: const char code[] = "typedef int A;\n" "typedef int B;\n" "template class C { };"; - const char expected[] = ";"; + const char expected[] = "template < class A , class B > class C { } ;"; ASSERT_EQUALS(expected, tok(code, false)); checkSimplifyTypedef(code); @@ -4954,7 +4956,7 @@ private: " typedef void (SomeTemplateClass::*MessageDispatcherFunc)(SerialInputMessage&);\n" "};\n"; // The expected result.. - const std::string expected(";"); + const std::string expected("template < typename DISPATCHER > class SomeTemplateClass { } ;"); ASSERT_EQUALS(expected, tok(code)); // Check for output.. diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index b7b7b2b66..fe13a1456 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -5676,7 +5676,10 @@ private: "struct S\n" "{};\n" "S s;\n"; - TODO_ASSERT_EQUALS("S < int , ( int ) 0 > s ;", // wanted result + TODO_ASSERT_EQUALS("S s ; struct S { } ;", // wanted result + "template < class T , T t >\n" + "struct S\n" + "{ } ;\n" "S < int , ( T ) 0 > s ;", // current result tokenizeAndStringify(code)); }