TemplateSimplifier: Fix instantiations when template parameter is a template

This commit is contained in:
Daniel Marjamäki 2017-12-26 22:34:39 +01:00
parent 4a7f923fca
commit 469cb7e6df
3 changed files with 29 additions and 12 deletions

View File

@ -1352,7 +1352,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
// New type..
std::vector<const Token *> typesUsedInTemplateInstantiation;
std::string typeForNewName;
std::string typeForPatternMatch;
std::list<std::string> typeStringsUsedInTemplateInstantiation;
unsigned int indentlevel = 0;
for (const Token *tok3 = tok2->tokAt(2); tok3 && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) {
// #2648 - unhandled parentheses => bail out
@ -1373,9 +1373,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
typesUsedInTemplateInstantiation.push_back(tok3);
const bool constconst = tok3->str() == "const" && tok3->strAt(1) == "const";
if (!constconst) {
if (!typeForPatternMatch.empty())
typeForPatternMatch += ' ';
typeForPatternMatch += tok3->str();
typeStringsUsedInTemplateInstantiation.push_back(tok3->str());
}
// add additional type information
if (!constconst && !Token::Match(tok3, "class|struct|enum")) {
@ -1390,7 +1388,6 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
typeForNewName += tok3->str();
}
}
const std::string templateParametersMatchPattern("< " + typeForPatternMatch + " >");
if (typeForNewName.empty() || typeParametersInDeclaration.size() != typesUsedInTemplateInstantiation.size()) {
if (printDebug && errorlogger) {
@ -1413,17 +1410,27 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
}
// Replace all these template usages..
replaceTemplateUsage(tok2, iter2->name, templateParametersMatchPattern, newName, typesUsedInTemplateInstantiation, templateInstantiations);
replaceTemplateUsage(tok2, iter2->name, typeStringsUsedInTemplateInstantiation, newName, typesUsedInTemplateInstantiation, templateInstantiations);
}
// Template has been instantiated .. then remove the template declaration
return instantiated;
}
static bool matchTemplateParameters(const Token *nameTok, const std::list<std::string> &strings)
{
std::list<std::string>::const_iterator it = strings.begin();
const Token *tok = nameTok->tokAt(2);
while (tok && it != strings.end() && *it == tok->str()) {
tok = tok->next();
++it;
}
return it == strings.end() && tok && tok->str() == ">";
}
void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
const std::string &templateName,
const std::string &templateParametersMatchPattern,
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<TokenAndName> &templateInstantiations)
@ -1434,7 +1441,7 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
setScopeInfo(nameTok, &scopeInfo);
if (!Token::Match(nameTok, "%name% <"))
continue;
if (!Token::simpleMatch(nameTok->next(), templateParametersMatchPattern.c_str()))
if (!matchTemplateParameters(nameTok, typeStringsUsedInTemplateInstantiation))
continue;
// FIXME Proper name matching

View File

@ -118,6 +118,16 @@ public:
*/
static int getTemplateNamePosition(const Token *tok);
/**
* Expand a template. Create "expanded" class/function at end of tokenlist.
* @param tokenlist The tokenlist that is changed
* @param templateDeclarationToken The template declaration token for the template that will be "expanded"
* @param fullName Full name of template
* @param typeParametersInDeclaration The type parameters of the template
* @param newName New name of class/function.
* @param typesUsedInTemplateInstantiation Type parameters in instantiation
* @param templateInstantiations List of template instantiations.
*/
static void expandTemplate(
TokenList& tokenlist,
const Token *templateDeclarationToken,
@ -165,14 +175,14 @@ public:
* Replace all matching template usages 'Foo < int >' => 'Foo<int>'
* @param instantiationToken Template instantiation token
* @param templateName full template name with scope info
* @param templateParametersMatchPattern template parameters, Token::simpleMatch compatible pattern
* @param typeStringsUsedInTemplateInstantiation template parameters. list of token strings.
* @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 &templateName,
const std::string &templateParametersMatchPattern,
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<TokenAndName> &templateInstantiations);

View File

@ -690,7 +690,7 @@ private:
// #3226 - inner template
const char code[] = "template<class A, class B> class Fred {};\n"
"Fred<int,Fred<int,int> > x;\n";
ASSERT_EQUALS("Fred < int , Fred<int,int> > x ; class Fred<int,int> { } ; class Fred<int,Fred<int,int>> { } ;", tok(code));
ASSERT_EQUALS("Fred<int,Fred<int,int>> x ; class Fred<int,int> { } ; class Fred<int,Fred<int,int>> { } ;", tok(code));
}
void template30() {
@ -734,7 +734,7 @@ private:
"template<class T> struct C { A<B<X<T> > > ab; };\n"
"C<int> c;";
ASSERT_EQUALS("C<int> c ; "
"struct C<int> { A < B<X<int>> > ab ; } ; "
"struct C<int> { A<B<X<int>>> ab ; } ; "
"struct B<X<int>> { } ; " // <- redundant.. but nevermind
"struct A<B<X<int>>> { } ;", tok(code));
}