Tokenizer: improved handling of inner templates. Partial fix for #3226

This commit is contained in:
Daniel Marjamäki 2011-12-04 11:38:41 +01:00
parent f47ac539d6
commit 49784a44e1
2 changed files with 51 additions and 3 deletions

View File

@ -2614,8 +2614,11 @@ static unsigned int templateParameters(const Token *tok)
return 0;
tok = tok->next();
unsigned int level = 0;
while (tok) {
++numberOfParameters;
if (level == 0)
++numberOfParameters;
// skip std::
while (Token::Match(tok, "%var% ::"))
@ -2632,9 +2635,20 @@ static unsigned int templateParameters(const Token *tok)
if (tok->str() == "*")
tok = tok->next();
// inner template
if (tok->str() == "<") {
++level;
tok = tok->next();
continue;
}
// ,/>
if (tok->str() == ">")
return numberOfParameters;
while (tok->str() == ">") {
if (level == 0)
return numberOfParameters;
--level;
tok = tok->next();
}
if (tok->str() != ",")
break;
tok = tok->next();
@ -2817,6 +2831,32 @@ std::list<Token *> Tokenizer::simplifyTemplatesGetTemplateInstantiations()
break;
} else if (Token::Match(tok->previous(), "[({};=] %var% <") ||
Token::Match(tok->tokAt(-2), "[,:] private|protected|public %var% <")) {
// Add inner template instantiations first => go to the ">"
// and then parse backwards, adding all seen instantiations
const Token *tok2;
// goto end ">" token
unsigned int level = 0;
for (tok2 = tok; tok2; tok2 = tok2->next()) {
if (tok2->str() == "<") {
++level;
} else if (tok2->str() == ">") {
if (level <= 1)
break;
--level;
}
}
// parse backwards and add template instantiations
for (; tok2 && tok2 != tok; tok2 = tok2->previous()) {
if (Token::Match(tok2, ", %var% <") &&
templateParameters(tok2->tokAt(2))) {
used.push_back(tok2->next());
}
}
// Add outer template..
if (templateParameters(tok->next()))
used.push_back(tok);
}

View File

@ -118,6 +118,7 @@ private:
TEST_CASE(template25); // #2648 - another test for sizeof template parameter
TEST_CASE(template26); // #2721 - passing 'char[2]' as template parameter
TEST_CASE(template27); // #3350 - removing unused template in macro call
TEST_CASE(template28);
TEST_CASE(template_unhandled);
TEST_CASE(template_default_parameter);
TEST_CASE(template_default_type);
@ -2102,6 +2103,13 @@ private:
ASSERT_EQUALS("X ( class Fred ) ;", sizeof_(code));
}
void template28() {
// #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>> { }", sizeof_(code));
}
void template_unhandled() {
// An unhandled template usage should be simplified..
ASSERT_EQUALS("; x<int> ( ) ;", sizeof_(";x<int>();"));