TemplateSimplifier: Better handling of scopes

This commit is contained in:
Daniel Marjamäki 2017-12-23 08:20:24 +01:00
parent 8851fd64a6
commit 326765c632
3 changed files with 227 additions and 135 deletions

View File

@ -31,38 +31,6 @@
#include <stack>
#include <utility>
#ifdef GDB_HELPERS
static void printlist(const std::list<Token *> &list)
{
for (std::list<Token *>::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<const Token *> &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<std::string> TemplateSimplifier::expandSpecialized(Token *tokens)
return expandedtemplates;
}
std::list<Token *> 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<ScopeInfo2> &scopeInfo)
{
std::list<Token *> 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<ScopeInfo2>::const_iterator it = scopeInfo.begin(); it != scopeInfo.end(); ++it)
ret += (ret.empty() ? "" : " :: ") + (it->name);
return ret;
}
static std::string getFullName(const std::list<ScopeInfo2> &scopeInfo, const std::string &name)
{
const std::string &scopeName = getScopeName(scopeInfo);
return scopeName + (scopeName.empty() ? "" : " :: ") + name;
}
static void setScopeInfo(const Token *tok, std::list<ScopeInfo2> *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::TokenAndName> TemplateSimplifier::getTemplateDeclarations(Token *tokens, bool &codeWithTemplates)
{
std::list<ScopeInfo2> scopeInfo;
std::list<TokenAndName> 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<Token *> 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<Token *> TemplateSimplifier::getTemplateInstantiations(Token *tokens)
std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateInstantiations(Token *tokens)
{
std::list<Token *> used;
std::list<TokenAndName> instantiations;
std::list<ScopeInfo2> 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<Token *> 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<Token *> &templates,
std::list<Token *> * const templateInstantiations)
void TemplateSimplifier::useDefaultArgumentValues(const std::list<TokenAndName> &templates,
std::list<TokenAndName> * const templateInstantiations)
{
for (std::list<Token *>::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) {
for (std::list<TokenAndName>::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<Token *> &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<Token *> &temp
continue;
// iterate through all template instantiations
for (std::list<Token *>::const_iterator iter2 = templateInstantiations->begin(); iter2 != templateInstantiations->end(); ++iter2) {
Token *tok = *iter2;
for (std::list<TokenAndName>::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<Token *> &temp
if (Token::Match(tok2, "(|{|["))
tok2 = tok2->link();
else if (Token::Match(tok2, "%type% <") && templateParameters(tok2->next())) {
std::list<Token*>::iterator ti = std::find(templateInstantiations->begin(),
templateInstantiations->end(),
tok2);
std::list<TokenAndName>::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<Token *> &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,39 +784,42 @@ 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<const Token *> &typeParametersInDeclaration,
const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<Token *> &templateInstantiations)
std::list<TemplateSimplifier::TokenAndName> &templateInstantiations)
{
bool inTemplateDefinition=false;
std::vector<const Token *> localTypeParametersInDeclaration;
std::list<ScopeInfo2> scopeInfo;
bool inTemplateDefinition = false;
for (const Token *tok3 = tokenlist.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
setScopeInfo(const_cast<Token *>(tok3), &scopeInfo);
if (tok3->str()=="template") {
if (tok3->next() && tok3->next()->str()=="<") {
std::vector<const Token *> 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% (")) {
tokenlist.addtoken(newName, tok3->linenr(), tok3->fileIndex());
while (tok3 && tok3->str() != "::")
tok3 = tok3->next();
@ -838,8 +859,9 @@ void TemplateSimplifier::expandTemplate(
}
}
// replace name..
if (Token::Match(tok3, (name + " !!<").c_str())) {
// FIXME replace name..
const std::string lastName = (fullName.find(" ") != std::string::npos) ? fullName.substr(fullName.rfind(" ")+1) : fullName;
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 {
@ -850,8 +872,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
@ -1226,9 +1266,9 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
TokenList& tokenlist,
ErrorLogger* errorlogger,
const Settings *_settings,
const Token *tok,
const TokenAndName templateDeclaration,
const std::time_t maxtime,
std::list<Token *> &templateInstantiations,
std::list<TokenAndName> &templateInstantiations,
std::set<std::string> &expandedtemplates)
{
// this variable is not used at the moment. The intention was to
@ -1237,7 +1277,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
// Contains tokens such as "T"
std::vector<const Token *> 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)
@ -1267,7 +1307,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
bool instantiated = false;
for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) {
for (std::list<TokenAndName>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) {
if (numberOfTemplateInstantiations != templateInstantiations.size()) {
numberOfTemplateInstantiations = templateInstantiations.size();
simplifyCalculations(tokenlist.front());
@ -1277,7 +1317,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
@ -1287,11 +1331,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..
@ -1335,13 +1381,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<const Token *> 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;
@ -1349,16 +1395,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
@ -1367,14 +1413,26 @@ 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<const Token *> &typesUsedInTemplateInstantiation,
std::list<Token *> &templateInstantiations)
std::list<TokenAndName> &templateInstantiations)
{
std::list<ScopeInfo2> scopeInfo;
std::list< std::pair<Token *, Token *> > 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;
std::string fullName(nameTok->str());
for (const Token *tok = nameTok->tokAt(-2); Token::Match(tok, "%name% ::"); tok = tok->tokAt(-2))
fullName = tok->str() + "::" + fullName;
fullName = getFullName(scopeInfo, fullName);
if (fullName != templateName)
continue;
// match parameters
@ -1413,10 +1471,20 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
// matching template usage => replace tokens..
// Foo < int > => Foo<int>
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 (Token *tok = nameTok1->next(); tok != tok2; tok = tok->next()) {
if (tok->isName()) {
std::list<TokenAndName>::iterator ti;
for (ti = templateInstantiations.begin(); ti != templateInstantiations.end();) {
if (ti->token == tok)
templateInstantiations.erase(ti++);
else
++ti;
}
}
}
removeTokens.push_back(std::pair<Token*,Token*>(nameTok, tok2->next()));
}
@ -1457,10 +1525,10 @@ void TemplateSimplifier::simplifyTemplates(
}
}
std::list<Token *> templates(TemplateSimplifier::getTemplateDeclarations(tokenlist.front(), _codeWithTemplates));
std::list<TokenAndName> templates(TemplateSimplifier::getTemplateDeclarations(tokenlist.front(), _codeWithTemplates));
// Locate possible instantiations of templates..
std::list<Token *> templateInstantiations(TemplateSimplifier::getTemplateInstantiations(tokenlist.front()));
std::list<TokenAndName> templateInstantiations(TemplateSimplifier::getTemplateInstantiations(tokenlist.front()));
// No template instantiations? Then return.
if (templateInstantiations.empty())
@ -1474,8 +1542,8 @@ void TemplateSimplifier::simplifyTemplates(
//while (!done)
{
//done = true;
std::list<Token *> templates2;
for (std::list<Token *>::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) {
std::list<TokenAndName> templates2;
for (std::list<TokenAndName>::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) {
bool instantiated = TemplateSimplifier::simplifyTemplateInstantiations(tokenlist,
errorlogger,
_settings,
@ -1487,11 +1555,15 @@ void TemplateSimplifier::simplifyTemplates(
templates2.push_back(*iter1);
}
for (std::list<Token *>::const_iterator it = templates2.begin(); it != templates2.end(); ++it) {
std::list<Token *>::iterator it1 = std::find(templates.begin(), templates.end(), *it);
for (std::list<TokenAndName>::const_iterator it = templates2.begin(); it != templates2.end(); ++it) {
std::list<TokenAndName>::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);
}
}
}

View File

@ -72,35 +72,43 @@ public:
*/
static std::set<std::string> 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<Token *> getTemplateDeclarations(Token *tokens, bool &codeWithTemplates);
static std::list<TokenAndName> getTemplateDeclarations(Token *tokens, bool &codeWithTemplates);
/**
* Get template instantiations
* @return list of template instantiations
*/
static std::list<Token *> getTemplateInstantiations(Token *tokens);
static std::list<TokenAndName> 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<Token *> &templates,
std::list<Token *> *templateInstantiations);
static void useDefaultArgumentValues(const std::list<TokenAndName> &templates,
std::list<TokenAndName> *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<const Token *> &typeParametersInDeclaration,
const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<Token *> &templateInstantiations);
std::list<TokenAndName> &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<Token *> &templateInstantiations,
std::list<TokenAndName> &templateInstantiations,
std::set<std::string> &expandedtemplates);
/**
* Replace all matching template usages 'Foo < int >' => 'Foo<int>'
* @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<const Token *> &typesUsedInTemplateInstantiation,
std::list<Token *> &templateInstantiations);
std::list<TokenAndName> &templateInstantiations);
/**
* Simplify templates
@ -200,7 +210,6 @@ public:
static bool simplifyCalculations(Token *_tokens);
private:
/**
* Remove a specific "template < ..." template class/function
*/

View File

@ -105,7 +105,8 @@ 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 TemplateSimplifier::templateParameters
TEST_CASE(templateParameters);
@ -1378,7 +1379,7 @@ private:
"};");
}
void template_namespace() {
void template_namespace_1() {
// #6570
const char code[] = "namespace {\n"
" template<class T> void Fred(T value) { }\n"
@ -1389,6 +1390,16 @@ private:
"void Fred < int > ( int value ) { }", tok(code));
}
void template_namespace_2() {
// #8283
const char code[] = "namespace X {\n"
" template<class T> struct S { };\n"
"}\n"
"X::S<int> s;";
ASSERT_EQUALS("X :: S < int > s ; "
"struct X :: S < int > { } ;", tok(code));
}
unsigned int templateParameters(const char code[]) {
Tokenizer tokenizer(&settings, this);
@ -1477,29 +1488,29 @@ private:
ASSERT_EQUALS("class A < int > : public B { } ;", tok("template<> class A<int> : 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% ("));
}
};