diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index e9aa3ddfff8..41043566423 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -485,10 +485,10 @@ static void setScopeInfo(const Token *tok, std::list *scopeInfo) } } -std::list TemplateSimplifier::getTemplateDeclarations(bool &codeWithTemplates, bool forward) +bool TemplateSimplifier::getTemplateDeclarations() { + bool codeWithTemplates = false; std::list scopeInfo; - std::list declarations; for (Token *tok = mTokenList.front(); tok; tok = tok->next()) { if (Token::Match(tok, "}|namespace|class|struct|union")) { setScopeInfo(tok, &scopeInfo); @@ -509,27 +509,23 @@ std::list TemplateSimplifier::getTemplateDecla tok2 = tok2->link(); else if (tok2->str() == ")") break; - // Just a declaration => ignore this + // Declaration => add to mTemplateForwardDeclarations else if (tok2->str() == ";") { - if (forward) { - const int namepos = getTemplateNamePosition(parmEnd, forward); - if (namepos > 0) - declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos)); - } + const int namepos = getTemplateNamePosition(parmEnd, true); + if (namepos > 0) + mTemplateForwardDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos)); break; } - // Implementation => add to "templates" + // Implementation => add to mTemplateDeclarations else if (tok2->str() == "{") { - if (!forward) { - const int namepos = getTemplateNamePosition(parmEnd, forward); - if (namepos > 0) - declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos)); - } + const int namepos = getTemplateNamePosition(parmEnd, false); + if (namepos > 0) + mTemplateDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos)); break; } } } - return declarations; + return codeWithTemplates; } @@ -961,15 +957,33 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok, bool forward) void TemplateSimplifier::addNamespace(const TokenAndName &templateDeclaration, const Token *tok) { + // find start of qualification + const Token * tokStart = tok; + int offset = 0; + while (Token::Match(tokStart->tokAt(-2), "%name% ::")) { + tokStart = tokStart->tokAt(-2); + offset -= 2; + } + // decide if namespace needs to be inserted in or appended to token list + const bool insert = tokStart != tok; + std::string::size_type start = 0; std::string::size_type end = 0; while ((end = templateDeclaration.scope.find(" ", start)) != std::string::npos) { std::string token = templateDeclaration.scope.substr(start, end - start); - mTokenList.addtoken(token, tok->linenr(), tok->fileIndex()); + if (insert) + mTokenList.back()->tokAt(offset)->insertToken(token, ""); + else + mTokenList.addtoken(token, tok->linenr(), tok->fileIndex()); start = end + 1; } - mTokenList.addtoken(templateDeclaration.scope.substr(start), tok->linenr(), tok->fileIndex()); - mTokenList.addtoken("::", tok->linenr(), tok->fileIndex()); + if (insert) { + mTokenList.back()->tokAt(offset)->insertToken(templateDeclaration.scope.substr(start), ""); + mTokenList.back()->tokAt(offset)->insertToken("::", ""); + } else { + mTokenList.addtoken(templateDeclaration.scope.substr(start), tok->linenr(), tok->fileIndex()); + mTokenList.addtoken("::", tok->linenr(), tok->fileIndex()); + } } bool TemplateSimplifier::alreadyHasNamespace(const TokenAndName &templateDeclaration, const Token *tok) const @@ -1961,12 +1975,8 @@ void TemplateSimplifier::replaceTemplateUsage( void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues() { - // get all forward declarations - bool dummy; - std::list forwardTemplateDeclarations = getTemplateDeclarations(dummy, true); - // try to locate a matching declaration for each forward declaration - for (const auto & forwardDecl : forwardTemplateDeclarations) { + for (const auto & forwardDecl : mTemplateForwardDeclarations) { std::vector params1; getTemplateParametersInDeclaration(forwardDecl.token, params1); @@ -1995,29 +2005,8 @@ void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues() void TemplateSimplifier::simplifyTemplates( const std::time_t maxtime, - bool &codeWithTemplates -) + bool &codeWithTemplates) { - std::set expandedtemplates; - - if (getTemplateDeclarations(codeWithTemplates).empty()) - return; - - // There are templates.. - // Remove "typename" unless used in template arguments.. - for (Token *tok = mTokenList.front(); tok; tok = tok->next()) { - if (tok->str() == "typename") - tok->deleteThis(); - - if (Token::simpleMatch(tok, "template <")) { - while (tok && tok->str() != ">") - tok = tok->next(); - if (!tok) - break; - } - } - - // expand templates // TODO: 2 is not the ideal number of loops. // We should loop until the number of declarations is 0 but we can't // do that until we instantiate unintstantiated templates with their symbolic types. @@ -2027,12 +2016,36 @@ void TemplateSimplifier::simplifyTemplates( // is fixed. for (int i = 0; i < 2; ++i) { if (i) { - expandedtemplates.clear(); + mTemplateDeclarations.clear(); + mTemplateForwardDeclarations.clear(); mTemplateInstantiations.clear(); mInstantiatedTemplates.clear(); } - mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates); + bool hasTemplates = getTemplateDeclarations(); + + if (i == 0) { + codeWithTemplates = hasTemplates; + if (hasTemplates) { + // There are templates.. + // Remove "typename" unless used in template arguments.. + for (Token *tok = mTokenList.front(); tok; tok = tok->next()) { + if (tok->str() == "typename") + tok->deleteThis(); + + if (Token::simpleMatch(tok, "template <")) { + while (tok && tok->str() != ">") + tok = tok->next(); + if (!tok) + break; + } + } + } + } + + // Make sure there is something to simplify. + if (mTemplateDeclarations.empty()) + return; // Copy default argument values from forward declaration to declaration fixForwardDeclaredDefaultArgumentValues(); @@ -2045,6 +2058,8 @@ void TemplateSimplifier::simplifyTemplates( simplifyTemplateAliases(); + std::set expandedtemplates; + for (std::list::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) { // get specializations.. std::list specializations; diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index b586a846b8b..4a04d4e27b8 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -123,11 +123,9 @@ class CPPCHECKLIB TemplateSimplifier { private: /** * Get template declarations - * @param codeWithTemplates set to true if code has templates - * @param forward declaration or forward declaration - * @return list of template declarations + * @return true if code has templates. */ - std::list getTemplateDeclarations(bool &codeWithTemplates, bool forward = false); + bool getTemplateDeclarations(); /** * Get template instantiations @@ -264,6 +262,7 @@ class CPPCHECKLIB TemplateSimplifier { ErrorLogger *mErrorLogger; std::list mTemplateDeclarations; + std::list mTemplateForwardDeclarations; std::list mTemplateInstantiations; std::list mInstantiatedTemplates; std::list mMemberFunctionsToDelete; diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index 93937c873ab..cb9084ed908 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -130,6 +130,7 @@ class TestSimplifyTemplate : public TestFixture { TEST_CASE(template_namespace_8); TEST_CASE(template_namespace_9); TEST_CASE(template_namespace_10); + TEST_CASE(template_namespace_11); // #7145 // Test TemplateSimplifier::templateParameters TEST_CASE(templateParameters); @@ -1974,6 +1975,34 @@ class TestSimplifyTemplate : public TestFixture { "} ;", tok(code)); } + void template_namespace_11() {// #7145 + const char code[] = "namespace MyNamespace {\n" + "class TestClass {\n" + "public:\n" + " TestClass() {\n" + " SomeFunction();\n" + " TemplatedMethod< int >();\n" + " }\n" + " void SomeFunction() { }\n" + "private:\n" + " template< typename T > void TemplatedMethod();\n" + "};\n" + "template< typename T > void TestClass::TemplatedMethod() { }\n" + "}"; + ASSERT_EQUALS("namespace MyNamespace { " + "class TestClass { " + "public: " + "TestClass ( ) { " + "SomeFunction ( ) ; " + "TemplatedMethod ( ) ; " + "} " + "void SomeFunction ( ) { } " + "private: " + "template < typename T > void TemplatedMethod ( ) ; " + "} ; " + "} void MyNamespace :: TestClass :: TemplatedMethod ( ) { }", tok(code)); + } + unsigned int templateParameters(const char code[]) { Tokenizer tokenizer(&settings, this);