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

View File

@ -118,6 +118,16 @@ public:
*/ */
static int getTemplateNamePosition(const Token *tok); 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( static void expandTemplate(
TokenList& tokenlist, TokenList& tokenlist,
const Token *templateDeclarationToken, const Token *templateDeclarationToken,
@ -165,14 +175,14 @@ public:
* Replace all matching template usages 'Foo < int >' => 'Foo<int>' * Replace all matching template usages 'Foo < int >' => 'Foo<int>'
* @param instantiationToken Template instantiation token * @param instantiationToken Template instantiation token
* @param templateName full template name with scope info * @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 newName The new type name
* @param typesUsedInTemplateInstantiation template instantiation parameters * @param typesUsedInTemplateInstantiation template instantiation parameters
* @param templateInstantiations All seen instantiations * @param templateInstantiations All seen instantiations
*/ */
static void replaceTemplateUsage(Token *const instantiationToken, static void replaceTemplateUsage(Token *const instantiationToken,
const std::string &templateName, const std::string &templateName,
const std::string &templateParametersMatchPattern, const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
const std::string &newName, const std::string &newName,
const std::vector<const Token *> &typesUsedInTemplateInstantiation, const std::vector<const Token *> &typesUsedInTemplateInstantiation,
std::list<TokenAndName> &templateInstantiations); std::list<TokenAndName> &templateInstantiations);

View File

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