Templates: Better handling of recursive templates

This commit is contained in:
Daniel Marjamäki 2009-11-01 15:56:00 +01:00
parent eebbc1b906
commit fec7acdc27
2 changed files with 182 additions and 85 deletions

View File

@ -615,6 +615,42 @@ bool Tokenizer::tokenize(std::istream &code, const char FileName[])
}
//---------------------------------------------------------------------------
/**
* is the token pointing at a template parameters block..
* < int , 3 > => yes
* \param tok start token that must point at "<"
* \return true if the tokens look like template parameters
*/
static bool templateParameters(const Token *tok)
{
if (!tok)
return false;
if (tok->str() != "<")
return false;
tok = tok->next();
while (tok)
{
// num/type ..
if (!tok->isNumber() && !tok->isName())
return false;
tok = tok->next();
// optional "*"
if (tok->str() == "*")
tok = tok->next();
// ,/>
if (tok->str() == ">")
return true;
if (tok->str() != ",")
break;
tok = tok->next();
}
return false;
}
void Tokenizer::simplifyTemplates()
{
// Remove "typename" unless used in template arguments..
@ -632,6 +668,8 @@ void Tokenizer::simplifyTemplates()
}
}
std::set<std::string> expandedtemplates;
// Locate specialized templates..
for (Token *tok = _tokens; tok; tok = tok->next())
{
@ -645,16 +683,22 @@ void Tokenizer::simplifyTemplates()
while (tok2 && (tok2->isName() || tok2->str() == "*"))
tok2 = tok2->next();
if (!templateParameters(tok2))
continue;
// unknown template.. bail out
if (!tok2 || !tok2->previous()->isName())
if (!tok2->previous()->isName())
continue;
tok2 = tok2->previous();
std::string s(tok2->str());
{
const Token *tok3 = tok2->next();
while (Token::Match(tok3, "<|, %type%"))
while (Token::Match(tok3, "<|, %any%"))
{
if (!tok3->next()->isNumber() && !tok3->next()->isName())
break;
s += " " + tok3->str() + " " + tok3->strAt(1);
tok3 = tok3->tokAt(2);
if (tok3->str() == "*")
@ -674,6 +718,7 @@ void Tokenizer::simplifyTemplates()
while (s.find(" ") != std::string::npos)
s.erase(s.find(" "), 1);
const std::string name(s + ">");
expandedtemplates.insert(name);
// Rename template..
Token::eraseTokens(tok2, Token::findmatch(tok2, "("));
@ -746,6 +791,7 @@ void Tokenizer::simplifyTemplates()
}
else if (Token::Match(tok->previous(), "[{};=] %var% <"))
{
if (templateParameters(tok->next()))
used.push_back(tok);
}
}
@ -864,8 +910,24 @@ void Tokenizer::simplifyTemplates()
}
const std::string pattern(s + "> ");
std::string::size_type sz1 = used.size();
unsigned int recursiveCount = 0;
for (std::list<Token *>::iterator iter2 = used.begin(); iter2 != used.end(); ++iter2)
{
// If the size of "used" has changed, simplify calculations
if (sz1 != used.size())
{
sz1 = used.size();
simplifyCalculations();
recursiveCount++;
if (recursiveCount > 100)
{
// bail out..
break;
}
}
Token *tok2 = *iter2;
if (tok2->str() != name)
@ -888,6 +950,9 @@ void Tokenizer::simplifyTemplates()
// New classname/funcname..
const std::string name2(name + "<" + type2 + ">");
if (expandedtemplates.find(name2) == expandedtemplates.end())
{
expandedtemplates.insert(name2);
// Copy template..
int _indentlevel = 0;
int _parlevel = 0;
@ -956,13 +1021,15 @@ void Tokenizer::simplifyTemplates()
addtoken(types2[itype].c_str(), tok3->linenr(), tok3->fileIndex());
// replace name..
else if (tok3->str() == name)
else if (Token::Match(tok3, (name + " !!<").c_str()))
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
// copy
else
{
addtoken(tok3->str().c_str(), tok3->linenr(), tok3->fileIndex());
if (Token::Match(tok3, (name + " <").c_str()))
used.push_back(_tokensBack);
// link() newly tokens manually
if (tok3->str() == "{")
@ -992,6 +1059,7 @@ void Tokenizer::simplifyTemplates()
assert(braces.empty());
assert(brackets.empty());
}
}
// Replace all these template usages..
s = name + " < " + type2 + " >";

View File

@ -85,6 +85,7 @@ private:
TEST_CASE(template12);
TEST_CASE(template13);
TEST_CASE(template14);
TEST_CASE(template15);
TEST_CASE(template_default_parameter);
TEST_CASE(template_typename);
@ -1239,6 +1240,34 @@ private:
ASSERT_EQUALS(expected, sizeof_(code));
}
void template15()
{
const char code[] = "template <unsigned int i> void a()\n"
"{\n"
" a<i-1>();\n"
"}\n"
"\n"
"template <> void a<0>()\n"
"{ }\n"
"\n"
"int main()\n"
"{\n"
" a<2>();\n"
" return 0;\n"
"}\n";
// The expected result..
const std::string expected("template < int i > void a ( ) "
"{ a < i - 1 > ( ) ; } "
"void a<0> ( ) { } "
"int main ( ) "
"{ a<2> ( ) ; return 0 ; } "
"void a<2> ( ) { a<1> ( ) ; } "
"void a<1> ( ) { a<0> ( ) ; }");
ASSERT_EQUALS(expected, sizeof_(code));
}
void template_default_parameter()
{
{