From 2c69f2b226ed2469850f634569aa509b3ca09340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 26 Dec 2017 10:55:18 +0100 Subject: [PATCH] TemplateSimplifier: Improved handling of scopes --- lib/templatesimplifier.cpp | 299 +++++++++++++++++++++------------- lib/templatesimplifier.h | 41 +++-- test/testsimplifytemplate.cpp | 65 +++++++- 3 files changed, 270 insertions(+), 135 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 90c1e3b7b..69ee50f3c 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -31,38 +31,6 @@ #include #include -#ifdef GDB_HELPERS - -static void printlist(const std::list &list) -{ - for (std::list::const_iterator it = list.begin(); it != list.end(); ++it) { - const Token *token = *it; - std::cout << " "; - while (token && !Token::Match(token, "[{};]")) { - std::cout << " " << token->str(); - token = token->next(); - } - std::cout << std::endl; - } -} - -static void printvector(const std::vector &v) -{ - for (std::size_t i = 0; i < v.size(); i++) { - const Token *token = v[i]; - std::cout << " " << i << ":"; - while (token && !Token::Match(token, "[{};]")) { - std::cout << " " << token->str(); - token = token->next(); - } - std::cout << std::endl; - } -} - -#endif - -//--------------------------------------------------------------------------- - void TemplateSimplifier::cleanupAfterSimplify(Token *tokens) { bool goback = false; @@ -455,14 +423,54 @@ std::set TemplateSimplifier::expandSpecialized(Token *tokens) return expandedtemplates; } -std::list TemplateSimplifier::getTemplateDeclarations(Token *tokens, bool &codeWithTemplates) +/// TODO: This is copy pasted from Tokenizer. We should reuse this code. +namespace { + struct ScopeInfo2 { + ScopeInfo2(const std::string &name_, const Token *classEnd_) : name(name_), classEnd(classEnd_) {} + const std::string name; + const Token * const classEnd; + }; +} +static std::string getScopeName(const std::list &scopeInfo) { - std::list templates; - for (Token *tok = tokens; tok; tok = tok->next()) { - // TODO: handle namespaces. Right now we don't instantiate templates that are defined in namespaces. - if (Token::Match(tok, "namespace %type% {")) - tok = tok->linkAt(2); + std::string ret; + for (std::list::const_iterator it = scopeInfo.begin(); it != scopeInfo.end(); ++it) + ret += (ret.empty() ? "" : " :: ") + (it->name); + return ret; +} +static std::string getFullName(const std::list &scopeInfo, const std::string &name) +{ + const std::string &scopeName = getScopeName(scopeInfo); + return scopeName + (scopeName.empty() ? "" : " :: ") + name; +} +static void setScopeInfo(const Token *tok, std::list *scopeInfo) +{ + while (tok->str() == "}" && !scopeInfo->empty() && tok == scopeInfo->back().classEnd) + scopeInfo->pop_back(); + if (!Token::Match(tok, "namespace|class|struct %name% {|:|::")) + return; + tok = tok->next(); + std::string classname = tok->str(); + while (Token::Match(tok, "%name% :: %name%")) { + tok = tok->tokAt(2); + classname += " :: " + tok->str(); + } + tok = tok->next(); + if (tok && tok->str() == ":") { + // ... + } + if (tok && tok->str() == "{") { + scopeInfo->push_back(ScopeInfo2(classname,tok->link())); + } +} + +std::list TemplateSimplifier::getTemplateDeclarations(Token *tokens, bool &codeWithTemplates) +{ + std::list scopeInfo; + std::list declarations; + for (Token *tok = tokens; tok; tok = tok->next()) { + setScopeInfo(tok, &scopeInfo); if (Token::simpleMatch(tok, "template <")) { // Some syntax checks, see #6865 if (!tok->tokAt(2)) @@ -472,36 +480,35 @@ std::list TemplateSimplifier::getTemplateDeclarations(Token *tokens, bo syntaxError(tok->next()); codeWithTemplates = true; Token *parmEnd = tok->next()->findClosingBracket(); - int indentlevel = 0; for (const Token *tok2 = parmEnd; tok2; tok2 = tok2->next()) { if (tok2->str() == "(") - ++indentlevel; + tok2 = tok2->link(); else if (tok2->str() == ")") - --indentlevel; - - if (indentlevel) // In an argument list; move to the next token - continue; - + break; // Just a declaration => ignore this - if (tok2->str() == ";") + else if (tok2->str() == ";") break; // Implementation => add to "templates" - if (tok2->str() == "{") { - templates.push_back(tok); + else if (tok2->str() == "{") { + int namepos = getTemplateNamePosition(parmEnd); + if (namepos > 0) + declarations.push_back(TokenAndName(tok, getFullName(scopeInfo, parmEnd->strAt(namepos)))); break; } } } } - return templates; + return declarations; } -std::list TemplateSimplifier::getTemplateInstantiations(Token *tokens) +std::list TemplateSimplifier::getTemplateInstantiations(Token *tokens) { - std::list used; + std::list instantiations; + std::list scopeList; for (Token *tok = tokens; tok; tok = tok->next()) { + setScopeInfo(tok, &scopeList); // template definition.. skip it if (Token::simpleMatch(tok, "template <")) { tok = tok->next()->findClosingBracket(); @@ -513,36 +520,45 @@ std::list TemplateSimplifier::getTemplateInstantiations(Token *tokens) const Token *tok2 = Token::findmatch(tok, "{|;"); if (tok2 && tok2->str() == "{") tok = tok2->link(); - } else if (Token::Match(tok->previous(), "[({};=] %name% <") || - Token::Match(tok->previous(), "%type% %name% <") || - Token::Match(tok->tokAt(-2), "[,:] private|protected|public %name% <")) { + } else if (Token::Match(tok->previous(), "[({};=] %name% ::|<") || + Token::Match(tok->previous(), "%type% %name% ::|<") || + Token::Match(tok->tokAt(-2), "[,:] private|protected|public %name% ::|<")) { + + std::string scopeName = getScopeName(scopeList); + while (Token::Match(tok, "%name% :: %name%")) { + scopeName += (scopeName.empty() ? "" : " :: ") + tok->str(); + tok = tok->tokAt(2); + } + if (!Token::Match(tok, "%name% <")) + continue; // Add inner template instantiations first => go to the ">" // and then parse backwards, adding all seen instantiations const Token *tok2 = tok->next()->findClosingBracket(); // parse backwards and add template instantiations + // TODO for (; tok2 && tok2 != tok; tok2 = tok2->previous()) { if (Token::Match(tok2, ", %name% <") && TemplateSimplifier::templateParameters(tok2->tokAt(2))) { - used.push_back(tok2->next()); + instantiations.push_back(TokenAndName(tok2->next(),getFullName(scopeList, tok2->strAt(1)))); } } // Add outer template.. if (TemplateSimplifier::templateParameters(tok->next())) - used.push_back(tok); + instantiations.push_back(TokenAndName(tok, scopeName + (scopeName.empty()?"":" :: ") + tok->str())); } } - return used; + return instantiations; } -void TemplateSimplifier::useDefaultArgumentValues(const std::list &templates, - std::list * const templateInstantiations) +void TemplateSimplifier::useDefaultArgumentValues(const std::list &templates, + std::list * const templateInstantiations) { - for (std::list::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) { + for (std::list::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) { // template parameters with default value has syntax such as: // x = y // this list will contain all the '=' tokens for such arguments @@ -560,7 +576,7 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list &temp std::string classname; // Scan template declaration.. - for (Token *tok = *iter1; tok; tok = tok->next()) { + for (Token *tok = iter1->token; tok; tok = tok->next()) { if (Token::simpleMatch(tok, "template < >")) { // Ticket #5762: Skip specialization tokens tok = tok->tokAt(2); if (0 == templateParmDepth) @@ -605,8 +621,8 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list &temp continue; // iterate through all template instantiations - for (std::list::const_iterator iter2 = templateInstantiations->begin(); iter2 != templateInstantiations->end(); ++iter2) { - Token *tok = *iter2; + for (std::list::const_iterator iter2 = templateInstantiations->begin(); iter2 != templateInstantiations->end(); ++iter2) { + Token *tok = iter2->token; if (!Token::simpleMatch(tok, (classname + " <").c_str())) continue; @@ -659,9 +675,11 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list &temp if (Token::Match(tok2, "(|{|[")) tok2 = tok2->link(); else if (Token::Match(tok2, "%type% <") && templateParameters(tok2->next())) { - std::list::iterator ti = std::find(templateInstantiations->begin(), - templateInstantiations->end(), - tok2); + std::list::iterator ti; + for (ti = templateInstantiations->begin(); ti != templateInstantiations->end(); ++ti) { + if (ti->token == tok2) + break; + } if (ti != templateInstantiations->end()) templateInstantiations->erase(ti); ++indentlevel; @@ -683,10 +701,10 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list &temp } } -bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::string &name, const std::size_t numberOfArguments, const char patternAfter[]) +bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::size_t numberOfArguments, const char patternAfter[]) { - if (!Token::simpleMatch(instance, (name + " <").c_str())) - return false; +// if (!Token::simpleMatch(instance, (name + " <").c_str())) +// return false; if (numberOfArguments != TemplateSimplifier::templateParameters(instance->next())) return false; @@ -766,17 +784,18 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok) void TemplateSimplifier::expandTemplate( TokenList& tokenlist, - const Token *tok, - const std::string &name, + const Token *templateDeclarationToken, + const std::string &fullName, const std::vector &typeParametersInDeclaration, const std::string &newName, const std::vector &typesUsedInTemplateInstantiation, - std::list &templateInstantiations) + std::list &templateInstantiations) { - bool inTemplateDefinition=false; + std::list scopeInfo; + bool inTemplateDefinition = false; const Token *endOfTemplateDefinition = nullptr; - std::vector localTypeParametersInDeclaration; for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) { + setScopeInfo(const_cast(tok3), &scopeInfo); if (inTemplateDefinition) { if (!endOfTemplateDefinition && tok3->str() == "{") endOfTemplateDefinition = tok3->link(); @@ -786,31 +805,33 @@ void TemplateSimplifier::expandTemplate( if (tok3->str()=="template") { if (tok3->next() && tok3->next()->str()=="<") { + std::vector localTypeParametersInDeclaration; TemplateParametersInDeclaration(tok3->tokAt(2), localTypeParametersInDeclaration); if (localTypeParametersInDeclaration.size() != typeParametersInDeclaration.size()) inTemplateDefinition = false; // Partial specialization else inTemplateDefinition = true; - } else + } else { inTemplateDefinition = false; // Only template instantiation + } } - if (Token::Match(tok3, "{|(|[")) + if (Token::Match(tok3, "(|[")) tok3 = tok3->link(); - else if (Token::simpleMatch(tok3, "namespace {")) - tok3 = tok3->tokAt(2); // Start of template.. - if (tok3 == tok) { + if (tok3 == templateDeclarationToken) { tok3 = tok3->next(); } // member function implemented outside class definition else if (inTemplateDefinition && - TemplateSimplifier::instantiateMatch(tok3, name, typeParametersInDeclaration.size(), ":: ~| %name% (")) { + Token::Match(tok3, "%name% <") && + fullName == getFullName(scopeInfo, tok3->str()) && + TemplateSimplifier::instantiateMatch(tok3, typeParametersInDeclaration.size(), ":: ~| %name% (")) { const Token *tok4 = tok3->next()->findClosingBracket(); while (tok4 && tok4->str() != "(") tok4 = tok4->next(); - if (!Tokenizer::isFunctionHead(tok4, "{:", true)) + if (!Tokenizer::isFunctionHead(tok4, ":{", true)) continue; tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex()); while (tok3 && tok3->str() != "::") @@ -824,6 +845,9 @@ void TemplateSimplifier::expandTemplate( int indentlevel = 0; std::stack brackets; // holds "(", "[" and "{" tokens + // FIXME use full name matching somehow + const std::string lastName = (fullName.find(" ") != std::string::npos) ? fullName.substr(fullName.rfind(" ")+1) : fullName; + for (; tok3; tok3 = tok3->next()) { if (tok3->isName()) { // search for this token in the type vector @@ -852,7 +876,7 @@ void TemplateSimplifier::expandTemplate( } // replace name.. - if (Token::Match(tok3, (name + " !!<").c_str())) { + if (Token::Match(tok3, (lastName + " !!<").c_str())) { if (Token::Match(tok3->tokAt(-2), "> :: %name% ( )")) { ; // Ticket #7942: Replacing for out-of-line constructors generates invalid syntax } else { @@ -863,8 +887,26 @@ void TemplateSimplifier::expandTemplate( // copy tokenlist.addtoken(tok3, tok3->linenr(), tok3->fileIndex()); - if (Token::Match(tok3, "%type% <") && Token::Match(tok3->next()->findClosingBracket(), ">|>> !!&")) { - templateInstantiations.push_back(tokenlist.back()); + if (Token::Match(tok3, "%type% <") && Token::Match(tok3->next()->findClosingBracket(), ">|>>")) { + const Token *closingBracket = tok3->next()->findClosingBracket(); + if (Token::simpleMatch(closingBracket->next(), "&")) { + int num = 0; + const Token *par = tok3->next(); + while (num < typeParametersInDeclaration.size() && par != closingBracket) { + const std::string pattern("[<,] " + typeParametersInDeclaration[num]->str() + " [,>]"); + if (!Token::Match(par, pattern.c_str())) + break; + ++num; + par = par->tokAt(2); + } + if (num < typeParametersInDeclaration.size() || par != closingBracket) + continue; + } + + std::string name = tok3->str(); + for (const Token *prev = tok3->tokAt(-2); Token::Match(prev, "%name% ::"); prev = prev->tokAt(-2)) + name = prev->str() + " :: " + name; + templateInstantiations.push_back(TokenAndName(tokenlist.back(), getFullName(scopeInfo, name))); } // link() newly tokens manually @@ -888,6 +930,7 @@ void TemplateSimplifier::expandTemplate( // the "}" token should only be added if indentlevel is 1 but I add it always intentionally // if indentlevel ever becomes 0, cppcheck will write: // ### Error: Invalid number of character { + inTemplateDefinition = false; break; } --indentlevel; @@ -1239,9 +1282,9 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( TokenList& tokenlist, ErrorLogger* errorlogger, const Settings *_settings, - const Token *tok, + const TokenAndName &templateDeclaration, const std::time_t maxtime, - std::list &templateInstantiations, + std::list &templateInstantiations, std::set &expandedtemplates) { // this variable is not used at the moment. The intention was to @@ -1250,7 +1293,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( // Contains tokens such as "T" std::vector typeParametersInDeclaration; - tok = TemplateParametersInDeclaration(tok->tokAt(2), typeParametersInDeclaration); + const Token * const tok = TemplateParametersInDeclaration(templateDeclaration.token->tokAt(2), typeParametersInDeclaration); // bail out if the end of the file was reached if (!tok) @@ -1280,7 +1323,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( bool instantiated = false; - for (std::list::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) { + for (std::list::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) { if (numberOfTemplateInstantiations != templateInstantiations.size()) { numberOfTemplateInstantiations = templateInstantiations.size(); simplifyCalculations(tokenlist.front()); @@ -1290,7 +1333,11 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( break; } } - Token * const tok2 = *iter2; + + if (iter2->name != templateDeclaration.name) + continue; + + Token * const tok2 = iter2->token; if (errorlogger && !tokenlist.getFiles().empty()) errorlogger->reportProgress(tokenlist.getFiles()[0], "TemplateSimplifier::simplifyTemplateInstantiations()", tok2->progressValue()); #ifdef MAXTIME @@ -1300,11 +1347,13 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( (void)maxtime; #endif assert(tokenlist.validateToken(tok2)); // that assertion fails on examples from #6021 - if (tok2->str() != name) - continue; - if (Token::Match(tok2->previous(), "[;{}=]") && - !TemplateSimplifier::instantiateMatch(*iter2, name, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%")) + const Token *startToken = tok2; + while (Token::Match(startToken->tokAt(-2), "%name% :: %name%")) + startToken = startToken->tokAt(-2); + + if (Token::Match(startToken->previous(), "[;{}=]") && + !TemplateSimplifier::instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%")) continue; // New type.. @@ -1348,13 +1397,13 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( typeForNewName += tok3->str(); } } - std::string templateMatchPattern(name + " < " + typeForPatternMatch + " >"); + const std::string templateParametersMatchPattern("< " + typeForPatternMatch + " >"); if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantiation.size()) { if (printDebug && errorlogger) { std::list callstack(1, tok2); errorlogger->reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", - "Failed to instantiate template \"" + name + "\". The checking continues anyway.", false)); + "Failed to instantiate template \"" + iter2->name + "\". The checking continues anyway.", false)); } if (typeForNewName.empty()) continue; @@ -1362,16 +1411,16 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( } // New classname/funcname.. - const std::string newName(name + " < " + typeForNewName + " >"); + const std::string newName(templateDeclaration.name + " < " + typeForNewName + " >"); if (expandedtemplates.find(newName) == expandedtemplates.end()) { expandedtemplates.insert(newName); - TemplateSimplifier::expandTemplate(tokenlist, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantiation,templateInstantiations); + TemplateSimplifier::expandTemplate(tokenlist, tok, iter2->name, typeParametersInDeclaration, newName, typesUsedInTemplateInstantiation, templateInstantiations); instantiated = true; } // Replace all these template usages.. - replaceTemplateUsage(tok2, templateMatchPattern, newName, typesUsedInTemplateInstantiation, templateInstantiations); + replaceTemplateUsage(tok2, iter2->name, templateParametersMatchPattern, newName, typesUsedInTemplateInstantiation, templateInstantiations); } // Template has been instantiated .. then remove the template declaration @@ -1380,14 +1429,24 @@ bool TemplateSimplifier::simplifyTemplateInstantiations( void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken, - const std::string &templateMatchPattern, + const std::string &templateName, + const std::string &templateParametersMatchPattern, const std::string &newName, const std::vector &typesUsedInTemplateInstantiation, - std::list &templateInstantiations) + std::list &templateInstantiations) { + std::list scopeInfo; std::list< std::pair > removeTokens; for (Token *nameTok = instantiationToken; nameTok; nameTok = nameTok->next()) { - if (!Token::simpleMatch(nameTok, templateMatchPattern.c_str())) + setScopeInfo(nameTok, &scopeInfo); + if (!Token::Match(nameTok, "%name% <")) + continue; + if (!Token::simpleMatch(nameTok->next(), templateParametersMatchPattern.c_str())) + continue; + + // FIXME Proper name matching + const std::string lastName(templateName.find(" ") == std::string::npos ? templateName : templateName.substr(templateName.rfind(" ") + 1)); + if (lastName != nameTok->str()) continue; // match parameters @@ -1426,10 +1485,24 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken, // matching template usage => replace tokens.. // Foo < int > => Foo if (tok2->str() == ">" && typeCountInInstantiation == typesUsedInTemplateInstantiation.size()) { + Token * const nameTok1 = nameTok; + while (Token::Match(nameTok->tokAt(-2), "%name% :: %name%")) + nameTok = nameTok->tokAt(-2); nameTok->str(newName); - for (Token *tok = nameTok->next(); tok != tok2; tok = tok->next()) { - if (tok->isName()) - templateInstantiations.remove(tok); + for (std::list::iterator it = templateInstantiations.begin(); it != templateInstantiations.end(); ++it) { + if (it->token == nameTok1) + it->token = nameTok; + } + for (Token *tok = nameTok1->next(); tok != tok2; tok = tok->next()) { + if (tok->isName()) { + std::list::iterator ti; + for (ti = templateInstantiations.begin(); ti != templateInstantiations.end();) { + if (ti->token == tok) + templateInstantiations.erase(ti++); + else + ++ti; + } + } } removeTokens.push_back(std::pair(nameTok, tok2->next())); } @@ -1470,10 +1543,10 @@ void TemplateSimplifier::simplifyTemplates( } } - std::list templates(TemplateSimplifier::getTemplateDeclarations(tokenlist.front(), _codeWithTemplates)); + std::list templates(TemplateSimplifier::getTemplateDeclarations(tokenlist.front(), _codeWithTemplates)); // Locate possible instantiations of templates.. - std::list templateInstantiations(TemplateSimplifier::getTemplateInstantiations(tokenlist.front())); + std::list templateInstantiations(TemplateSimplifier::getTemplateInstantiations(tokenlist.front())); // No template instantiations? Then return. if (templateInstantiations.empty()) @@ -1487,8 +1560,8 @@ void TemplateSimplifier::simplifyTemplates( //while (!done) { //done = true; - std::list templates2; - for (std::list::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) { + std::list templates2; + for (std::list::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) { bool instantiated = TemplateSimplifier::simplifyTemplateInstantiations(tokenlist, errorlogger, _settings, @@ -1500,11 +1573,15 @@ void TemplateSimplifier::simplifyTemplates( templates2.push_back(*iter1); } - for (std::list::const_iterator it = templates2.begin(); it != templates2.end(); ++it) { - std::list::iterator it1 = std::find(templates.begin(), templates.end(), *it); + for (std::list::const_iterator it = templates2.begin(); it != templates2.end(); ++it) { + std::list::iterator it1; + for (it1 = templates.begin(); it1 != templates.end(); ++it1) { + if (it1->token == it->token) + break; + } if (it1 != templates.end()) { templates.erase(it1); - removeTemplate(*it); + removeTemplate(it->token); } } } diff --git a/lib/templatesimplifier.h b/lib/templatesimplifier.h index bf2be3f97..169f9502b 100644 --- a/lib/templatesimplifier.h +++ b/lib/templatesimplifier.h @@ -72,35 +72,43 @@ public: */ static std::set expandSpecialized(Token *tokens); + /** + * Token and its full scopename + */ + struct TokenAndName { + TokenAndName(Token *tok, const std::string &scopeName) : token(tok), name(scopeName) {} + Token *token; + std::string name; + }; + /** * Get template declarations * @return list of template declarations */ - static std::list getTemplateDeclarations(Token *tokens, bool &codeWithTemplates); + static std::list getTemplateDeclarations(Token *tokens, bool &codeWithTemplates); /** * Get template instantiations * @return list of template instantiations */ - static std::list getTemplateInstantiations(Token *tokens); + static std::list getTemplateInstantiations(Token *tokens); /** * simplify template instantiations (use default argument values) * @param templates list of template declarations * @param templateInstantiations list of template instantiations */ - static void useDefaultArgumentValues(const std::list &templates, - std::list *templateInstantiations); + static void useDefaultArgumentValues(const std::list &templates, + std::list *templateInstantiations); /** * Match template declaration/instantiation * @param instance template instantiation - * @param name name of template * @param numberOfArguments number of template arguments * @param patternAfter pattern that must match the tokens after the ">" * @return match => true */ - static bool instantiateMatch(const Token *instance, const std::string &name, const std::size_t numberOfArguments, const char patternAfter[]); + static bool instantiateMatch(const Token *instance, const std::size_t numberOfArguments, const char patternAfter[]); /** * Match template declaration/instantiation @@ -112,12 +120,12 @@ public: static void expandTemplate( TokenList& tokenlist, - const Token *tok, - const std::string &name, + const Token *templateDeclarationToken, + const std::string &fullName, const std::vector &typeParametersInDeclaration, const std::string &newName, const std::vector &typesUsedInTemplateInstantiation, - std::list &templateInstantiations); + std::list &templateInstantiations); /** * @brief TemplateParametersInDeclaration @@ -138,7 +146,7 @@ public: * @param tokenlist token list * @param errorlogger error logger * @param _settings settings - * @param tok token where the template declaration begins + * @param templateDeclaration template declaration * @param maxtime time when the simplification will stop * @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. @@ -148,24 +156,26 @@ public: TokenList& tokenlist, ErrorLogger* errorlogger, const Settings *_settings, - const Token *tok, + const TokenAndName &templateDeclaration, const std::time_t maxtime, - std::list &templateInstantiations, + std::list &templateInstantiations, std::set &expandedtemplates); /** * Replace all matching template usages 'Foo < int >' => 'Foo' * @param instantiationToken Template instantiation token - * @param templateMatchPattern Pattern compatible with Token::simpleMatch + * @param templateName full template name with scope info + * @param templateParametersMatchPattern template parameters, Token::simpleMatch compatible pattern * @param newName The new type name * @param typesUsedInTemplateInstantiation template instantiation parameters * @param templateInstantiations All seen instantiations */ static void replaceTemplateUsage(Token *const instantiationToken, - const std::string &templateMatchPattern, + const std::string &templateName, + const std::string &templateParametersMatchPattern, const std::string &newName, const std::vector &typesUsedInTemplateInstantiation, - std::list &templateInstantiations); + std::list &templateInstantiations); /** * Simplify templates @@ -200,7 +210,6 @@ public: static bool simplifyCalculations(Token *_tokens); private: - /** * Remove a specific "template < ..." template class/function */ diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index d7ff36aeb..5911fdc91 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -106,7 +106,10 @@ private: TEST_CASE(template_constructor); // #3152 - template constructor is removed TEST_CASE(syntax_error_templates_1); TEST_CASE(template_member_ptr); // Ticket #5786 - crash upon valid code - TEST_CASE(template_namespace); + TEST_CASE(template_namespace_1); + TEST_CASE(template_namespace_2); + TEST_CASE(template_namespace_3); + TEST_CASE(template_namespace_4); // Test TemplateSimplifier::templateParameters TEST_CASE(templateParameters); @@ -1392,7 +1395,7 @@ private: "};"); } - void template_namespace() { + void template_namespace_1() { // #6570 const char code[] = "namespace {\n" " template void Fred(T value) { }\n" @@ -1403,6 +1406,52 @@ private: "void Fred ( int value ) { }", tok(code)); } + void template_namespace_2() { + // #8283 + const char code[] = "namespace X {\n" + " template struct S { };\n" + "}\n" + "X::S s;"; + ASSERT_EQUALS("X::S s ; " + "struct X::S { } ;", tok(code)); + } + + void template_namespace_3() { + const char code[] = "namespace test16 {\n" + " template struct foo {\n" + " static void *bar();\n" + " };\n" + " void *test() { return foo::bar(); }\n" + "}"; + ASSERT_EQUALS("namespace test16 {" + " void * test ( ) {" + " return test16::foo :: bar ( ) ;" + " } " + "} " + "struct test16::foo {" + " static void * bar ( ) ; " + "} ;", tok(code)); + } + + void template_namespace_4() { + const char code[] = "namespace foo {\n" + " template class A { void dostuff() {} };\n" + " struct S : public A {\n" + " void f() {\n" + " A::dostuff();\n" + " }\n" + " };\n" + "}"; + ASSERT_EQUALS("namespace foo {" + " struct S : public foo::A {" + " void f ( ) {" + " foo::A :: dostuff ( ) ;" + " }" + " } ; " + "} " + "class foo::A { void dostuff ( ) { } } ;", tok(code)); + } + unsigned int templateParameters(const char code[]) { Tokenizer tokenizer(&settings, this); @@ -1491,29 +1540,29 @@ private: ASSERT_EQUALS("class A : public B { } ;", tok("template<> class A : public B {};")); } - unsigned int instantiateMatch(const char code[], const std::string& name, const std::size_t numberOfArguments, const char patternAfter[]) { + unsigned int instantiateMatch(const char code[], const std::size_t numberOfArguments, const char patternAfter[]) { Tokenizer tokenizer(&settings, this); std::istringstream istr(code); tokenizer.tokenize(istr, "test.cpp", ""); - return TemplateSimplifier::instantiateMatch(tokenizer.tokens(), name, numberOfArguments, patternAfter); + return TemplateSimplifier::instantiateMatch(tokenizer.tokens(), numberOfArguments, patternAfter); } void instantiateMatch() { // Ticket #8175 ASSERT_EQUALS(false, instantiateMatch("ConvertHelper < From, To > c ;", - "ConvertHelper", 2, ":: %name% (")); + 2, ":: %name% (")); ASSERT_EQUALS(true, instantiateMatch("ConvertHelper < From, To > :: Create ( ) ;", - "ConvertHelper", 2, ":: %name% (")); + 2, ":: %name% (")); ASSERT_EQUALS(false, instantiateMatch("integral_constant < bool, sizeof ( ConvertHelper < From, To > :: Create ( ) ) > ;", - "integral_constant", 2, ":: %name% (")); + 2, ":: %name% (")); ASSERT_EQUALS(false, instantiateMatch("integral_constant < bool, sizeof ( ns :: ConvertHelper < From, To > :: Create ( ) ) > ;", - "integral_constant", 2, ":: %name% (")); + 2, ":: %name% (")); } };