Tokenizer: improved handling of inner templates. Partial fix for #3226
This commit is contained in:
parent
f47ac539d6
commit
49784a44e1
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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>();"));
|
||||
|
|
Loading…
Reference in New Issue