Fixed #880 (Tokenizer: The Tokenizer::simplifyTemplates doesn't handle recursive templates)
This commit is contained in:
parent
fec7acdc27
commit
319cdc2b43
113
lib/tokenize.cpp
113
lib/tokenize.cpp
|
@ -651,6 +651,41 @@ static bool templateParameters(const Token *tok)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove "template < ..." they can cause false positives because they are not expanded
|
||||
*/
|
||||
static void removeTemplates(Token *tok)
|
||||
{
|
||||
for (; tok; tok = tok->next())
|
||||
{
|
||||
if (! Token::simpleMatch(tok, "template <"))
|
||||
continue;
|
||||
|
||||
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
|
||||
{
|
||||
if (tok2->str() == "{")
|
||||
{
|
||||
tok2 = tok2->link();
|
||||
tok2 = tok2 ? tok2->next() : 0;
|
||||
Token::eraseTokens(tok, tok2);
|
||||
tok->str(";");
|
||||
break;
|
||||
}
|
||||
if (tok2->str() == "(")
|
||||
{
|
||||
tok2 = tok2->link();
|
||||
if (!tok2)
|
||||
break;
|
||||
}
|
||||
if (tok2->str() == ";")
|
||||
{
|
||||
Token::eraseTokens(tok, tok2);
|
||||
tok->str(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyTemplates()
|
||||
{
|
||||
// Remove "typename" unless used in template arguments..
|
||||
|
@ -691,24 +726,19 @@ void Tokenizer::simplifyTemplates()
|
|||
continue;
|
||||
|
||||
tok2 = tok2->previous();
|
||||
std::string s(tok2->str());
|
||||
std::string s;
|
||||
{
|
||||
const Token *tok3 = tok2->next();
|
||||
while (Token::Match(tok3, "<|, %any%"))
|
||||
std::ostringstream ostr;
|
||||
const Token *tok3 = tok2;
|
||||
for (tok3 = tok2; tok3 && tok3->str() != ">"; tok3 = tok3->next())
|
||||
{
|
||||
if (!tok3->next()->isNumber() && !tok3->next()->isName())
|
||||
break;
|
||||
|
||||
s += " " + tok3->str() + " " + tok3->strAt(1);
|
||||
tok3 = tok3->tokAt(2);
|
||||
if (tok3->str() == "*")
|
||||
{
|
||||
tok3 = tok3->next();
|
||||
s += " *";
|
||||
}
|
||||
if (tok3 != tok2)
|
||||
ostr << " ";
|
||||
ostr << tok3->str();
|
||||
}
|
||||
if (!Token::Match(tok3, "> ("))
|
||||
continue;
|
||||
s = ostr.str();
|
||||
}
|
||||
|
||||
// save search pattern..
|
||||
|
@ -759,7 +789,10 @@ void Tokenizer::simplifyTemplates()
|
|||
}
|
||||
}
|
||||
if (templates.empty())
|
||||
{
|
||||
removeTemplates(_tokens);
|
||||
return;
|
||||
}
|
||||
|
||||
// Locate possible instantiations of templates..
|
||||
std::list<Token *> used;
|
||||
|
@ -768,20 +801,17 @@ void Tokenizer::simplifyTemplates()
|
|||
// template definition.. skip it
|
||||
if (Token::simpleMatch(tok, "template <"))
|
||||
{
|
||||
unsigned int indentlevel = 0;
|
||||
for (; tok; tok = tok->next())
|
||||
{
|
||||
if (tok->str() == "{")
|
||||
if (tok->str() == "{" || tok->str() == "(")
|
||||
{
|
||||
++indentlevel;
|
||||
}
|
||||
else if (tok->str() == "}")
|
||||
{
|
||||
if (indentlevel <= 1)
|
||||
tok = tok->link();
|
||||
if (!tok)
|
||||
break;
|
||||
if (tok->str() == "}")
|
||||
break;
|
||||
--indentlevel;
|
||||
}
|
||||
else if (indentlevel == 0 && tok->str() == ";")
|
||||
else if (tok->str() == ";")
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -789,14 +819,19 @@ void Tokenizer::simplifyTemplates()
|
|||
if (!tok)
|
||||
break;
|
||||
}
|
||||
else if (Token::Match(tok->previous(), "[{};=] %var% <"))
|
||||
else if (Token::Match(tok->previous(), "[{};=] %var% <") ||
|
||||
Token::Match(tok->tokAt(-2), "[,:] private|protected|public %var% <"))
|
||||
{
|
||||
if (templateParameters(tok->next()))
|
||||
used.push_back(tok);
|
||||
}
|
||||
}
|
||||
if (used.empty())
|
||||
{
|
||||
removeTemplates(_tokens);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -870,6 +905,10 @@ void Tokenizer::simplifyTemplates()
|
|||
|
||||
|
||||
// expand templates
|
||||
bool done = false;
|
||||
while (!done)
|
||||
{
|
||||
done = true;
|
||||
for (std::list<Token *>::iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1)
|
||||
{
|
||||
Token *tok = *iter1;
|
||||
|
@ -933,7 +972,8 @@ void Tokenizer::simplifyTemplates()
|
|||
if (tok2->str() != name)
|
||||
continue;
|
||||
|
||||
if (!Token::Match(tok2, (pattern + (isfunc ? "(" : "%var%")).c_str()))
|
||||
if (Token::Match(tok2->previous(), "[;{}=]") &&
|
||||
!Token::Match(tok2, (pattern + (isfunc ? "(" : "%var%")).c_str()))
|
||||
continue;
|
||||
|
||||
// New type..
|
||||
|
@ -1010,6 +1050,8 @@ void Tokenizer::simplifyTemplates()
|
|||
--indentlevel;
|
||||
}
|
||||
|
||||
|
||||
if (tok3->isName())
|
||||
{
|
||||
// search for this token in the type vector
|
||||
unsigned int itype = 0;
|
||||
|
@ -1018,18 +1060,27 @@ void Tokenizer::simplifyTemplates()
|
|||
|
||||
// replace type with given type..
|
||||
if (itype < type.size())
|
||||
{
|
||||
addtoken(types2[itype].c_str(), tok3->linenr(), tok3->fileIndex());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// replace name..
|
||||
else if (Token::Match(tok3, (name + " !!<").c_str()))
|
||||
if (Token::Match(tok3, (name + " !!<").c_str()))
|
||||
{
|
||||
addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex());
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy
|
||||
else
|
||||
{
|
||||
addtoken(tok3->str().c_str(), tok3->linenr(), tok3->fileIndex());
|
||||
if (Token::Match(tok3, (name + " <").c_str()))
|
||||
if (Token::Match(tok3, "%type% <"))
|
||||
{
|
||||
if (!Token::Match(tok3, (name + " <").c_str()))
|
||||
done = false;
|
||||
used.push_back(_tokensBack);
|
||||
}
|
||||
|
||||
// link() newly tokens manually
|
||||
if (tok3->str() == "{")
|
||||
|
@ -1052,8 +1103,7 @@ void Tokenizer::simplifyTemplates()
|
|||
Token::createMutualLinks(brackets.top(), _tokensBack);
|
||||
brackets.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
assert(braces.empty());
|
||||
|
@ -1081,6 +1131,9 @@ void Tokenizer::simplifyTemplates()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeTemplates(_tokens);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void Tokenizer::updateClassList()
|
||||
|
|
|
@ -316,8 +316,6 @@ private:
|
|||
|
||||
void virtualDestructorTemplate()
|
||||
{
|
||||
// Base class has protected destructor, it makes Base *p = new Derived(); fail
|
||||
// during compilation time, so error is not possible. => no error
|
||||
checkVirtualDestructor("template <typename T> class A\n"
|
||||
"{\n"
|
||||
" public:\n"
|
||||
|
@ -333,7 +331,7 @@ private:
|
|||
" public:\n"
|
||||
" ~B(){int a;}\n"
|
||||
"};\n");
|
||||
ASSERT_EQUALS("[test.cpp:7]: (error) Class AA which is inherited by class B does not have a virtual destructor\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:7]: (error) Class AA<double> which is inherited by class B does not have a virtual destructor\n", errout.str());
|
||||
}
|
||||
|
||||
void checkUninitVar(const char code[])
|
||||
|
|
|
@ -86,6 +86,7 @@ private:
|
|||
TEST_CASE(template13);
|
||||
TEST_CASE(template14);
|
||||
TEST_CASE(template15);
|
||||
TEST_CASE(template16);
|
||||
TEST_CASE(template_default_parameter);
|
||||
TEST_CASE(template_typename);
|
||||
|
||||
|
@ -921,8 +922,7 @@ private:
|
|||
const char code[] = "template <classname T> void f(T val) { T a; }\n"
|
||||
"f<int>(10);";
|
||||
|
||||
const std::string expected("template < classname T > void f ( T val ) { T a ; } "
|
||||
"f<int> ( 10 ) ; "
|
||||
const std::string expected("; f<int> ( 10 ) ; "
|
||||
"void f<int> ( int val ) { int a ; }");
|
||||
|
||||
ASSERT_EQUALS(expected, sizeof_(code));
|
||||
|
@ -933,7 +933,7 @@ private:
|
|||
const char code[] = "template <classname T> class Fred { T a; };\n"
|
||||
"Fred<int> fred;";
|
||||
|
||||
const std::string expected("template < classname T > class Fred { T a ; } ; "
|
||||
const std::string expected("; ; "
|
||||
"Fred<int> fred ; "
|
||||
"class Fred<int> { int a ; }");
|
||||
|
||||
|
@ -945,7 +945,7 @@ private:
|
|||
const char code[] = "template <classname T, int sz> class Fred { T data[sz]; };\n"
|
||||
"Fred<float,4> fred;";
|
||||
|
||||
const std::string expected("template < classname T , int sz > class Fred { T data [ sz ] ; } ; "
|
||||
const std::string expected("; ; "
|
||||
"Fred<float,4> fred ; "
|
||||
"class Fred<float,4> { float data [ 4 ] ; }");
|
||||
|
||||
|
@ -957,7 +957,7 @@ private:
|
|||
const char code[] = "template <classname T> class Fred { Fred(); };\n"
|
||||
"Fred<float> fred;";
|
||||
|
||||
const std::string expected("template < classname T > class Fred { Fred ( ) ; } ; "
|
||||
const std::string expected("; ; "
|
||||
"Fred<float> fred ; "
|
||||
"class Fred<float> { Fred<float> ( ) ; }");
|
||||
|
||||
|
@ -970,8 +970,8 @@ private:
|
|||
"template <classname T> Fred<T>::Fred() { }\n"
|
||||
"Fred<float> fred;";
|
||||
|
||||
const std::string expected("template < classname T > class Fred { } ; "
|
||||
"template < classname T > Fred < T > :: Fred ( ) { } "
|
||||
const std::string expected("; ; "
|
||||
"; "
|
||||
"Fred<float> fred ; "
|
||||
"class Fred<float> { } "
|
||||
"Fred<float> :: Fred<float> ( ) { }");
|
||||
|
@ -985,7 +985,7 @@ private:
|
|||
"Fred<float> fred1;\n"
|
||||
"Fred<float> fred2;";
|
||||
|
||||
const std::string expected("template < classname T > class Fred { } ;"
|
||||
const std::string expected("; ;"
|
||||
" Fred<float> fred1 ;"
|
||||
" Fred<float> fred2 ;"
|
||||
" class Fred<float> { }");
|
||||
|
@ -1005,12 +1005,7 @@ private:
|
|||
"\n"
|
||||
"};\n";
|
||||
|
||||
const std::string expected("template < class T > "
|
||||
"class ABC "
|
||||
"{ "
|
||||
"public: "
|
||||
"typedef ABC < T > m ; "
|
||||
"} ;");
|
||||
const std::string expected("; ;");
|
||||
|
||||
ASSERT_EQUALS(expected, sizeof_(code));
|
||||
}
|
||||
|
@ -1026,10 +1021,7 @@ private:
|
|||
" return 0;\n"
|
||||
"}\n";
|
||||
|
||||
const std::string expected("template < typename T > class ABC {"
|
||||
" public: "
|
||||
"typedef std :: vector < T > type ; "
|
||||
"} ; "
|
||||
const std::string expected("; ; "
|
||||
"int main ( ) { "
|
||||
"std :: vector < int > v ; "
|
||||
"v . push_back ( 4 ) ; "
|
||||
|
@ -1050,17 +1042,9 @@ private:
|
|||
" }\n"
|
||||
"};\n";
|
||||
|
||||
const std::string expected("template < typename T > class ABC "
|
||||
"{"
|
||||
" public: typedef std :: vector < T > type ;"
|
||||
" void f ( ) "
|
||||
"{ "
|
||||
"std :: vector < int > v ;"
|
||||
" v . push_back ( 4 ) ;"
|
||||
" } "
|
||||
"} ;");
|
||||
const std::string expected("; ;");
|
||||
|
||||
TODO_ASSERT_EQUALS(expected, sizeof_(code));
|
||||
ASSERT_EQUALS(expected, sizeof_(code));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1084,20 +1068,7 @@ private:
|
|||
"\n"
|
||||
"template<typename T> inline B<T> h() { return B<T>(); }\n";
|
||||
|
||||
const std::string expected("template < typename T > class A ;"
|
||||
" template < typename T > class B ;"
|
||||
""
|
||||
" typedef A < int > x ;"
|
||||
" typedef B < int > y ;"
|
||||
""
|
||||
" template < typename T > class A {"
|
||||
" void f ( ) {"
|
||||
" B < T > a = B < T > :: g ( ) ;"
|
||||
" T b ; b = 0 ;"
|
||||
" }"
|
||||
" } ;"
|
||||
""
|
||||
" template < typename T > inline B < T > h ( ) { return B < T > ( ) ; }");
|
||||
const std::string expected("; ; ;");
|
||||
|
||||
ASSERT_EQUALS(expected, sizeof_(code));
|
||||
}
|
||||
|
@ -1118,12 +1089,7 @@ private:
|
|||
"} ;\n";
|
||||
|
||||
// The expected result..
|
||||
std::string expected(std::string(code) + " class A<int> { }");
|
||||
std::string::size_type pos;
|
||||
while ((pos = expected.find("\n")) != std::string::npos)
|
||||
expected[pos] = ' ';
|
||||
while ((pos = expected.find(" ")) != std::string::npos)
|
||||
expected.erase(pos, 1);
|
||||
std::string expected("; ; void f ( ) { A<int> a ; } ; ; class A<int> { }");
|
||||
|
||||
ASSERT_EQUALS(expected, sizeof_(code));
|
||||
}
|
||||
|
@ -1139,8 +1105,7 @@ private:
|
|||
"}\n";
|
||||
|
||||
// The expected result..
|
||||
const std::string expected("template < int ui , typename T > T * foo ( )"
|
||||
" { return new T [ ui ] ; }"
|
||||
const std::string expected("; "
|
||||
"void f ( ) "
|
||||
"{"
|
||||
" foo<3,int> ( ) ; "
|
||||
|
@ -1160,8 +1125,7 @@ private:
|
|||
"}\n";
|
||||
|
||||
// The expected result..
|
||||
const std::string expected("template < int ui , typename T > T * foo ( )"
|
||||
" { return new T [ ui ] ; }"
|
||||
const std::string expected("; "
|
||||
"void f ( ) "
|
||||
"{"
|
||||
" char * p ; p = foo<3,char> ( ) ; "
|
||||
|
@ -1182,9 +1146,7 @@ private:
|
|||
"}\n";
|
||||
|
||||
// The expected result..
|
||||
const std::string expected("template < int x , int y , int z >"
|
||||
" class A : public B < x , y , ( x - y ) ? ( ( y < z ) ? 1 : - 1 ) : 0 >"
|
||||
" { } ;"
|
||||
const std::string expected("; ; "
|
||||
"void f ( ) "
|
||||
"{"
|
||||
" A<12,12,11> a ; "
|
||||
|
@ -1257,8 +1219,7 @@ private:
|
|||
"}\n";
|
||||
|
||||
// The expected result..
|
||||
const std::string expected("template < int i > void a ( ) "
|
||||
"{ a < i - 1 > ( ) ; } "
|
||||
const std::string expected("; "
|
||||
"void a<0> ( ) { } "
|
||||
"int main ( ) "
|
||||
"{ a<2> ( ) ; return 0 ; } "
|
||||
|
@ -1268,6 +1229,30 @@ private:
|
|||
ASSERT_EQUALS(expected, sizeof_(code));
|
||||
}
|
||||
|
||||
void template16()
|
||||
{
|
||||
const char code[] = "template <unsigned int i> void a()\n"
|
||||
"{ }\n"
|
||||
"\n"
|
||||
"template <unsigned int i> void b()\n"
|
||||
"{ a<i>(); }\n"
|
||||
"\n"
|
||||
"int main()\n"
|
||||
"{\n"
|
||||
" b<2>();\n"
|
||||
" return 0;\n"
|
||||
"}\n";
|
||||
|
||||
// The expected result..
|
||||
const std::string expected("; "
|
||||
"; "
|
||||
"int main ( ) { b<2> ( ) ; return 0 ; } "
|
||||
"void b<2> ( ) { a<2> ( ) ; } "
|
||||
"void a<2> ( ) { }");
|
||||
|
||||
ASSERT_EQUALS(expected, sizeof_(code));
|
||||
}
|
||||
|
||||
void template_default_parameter()
|
||||
{
|
||||
{
|
||||
|
@ -1282,9 +1267,7 @@ private:
|
|||
"}\n";
|
||||
|
||||
// The expected result..
|
||||
const std::string expected("template < class T , int n >"
|
||||
" class A"
|
||||
" { T ar [ n ] ; } ;"
|
||||
const std::string expected("; ; "
|
||||
"void f ( ) "
|
||||
"{"
|
||||
" A<int,2> a1 ;"
|
||||
|
@ -1308,9 +1291,7 @@ private:
|
|||
"}\n";
|
||||
|
||||
// The expected result..
|
||||
const std::string expected("template < class T , int n1 , int n2 >"
|
||||
" class A"
|
||||
" { T ar [ n1 + n2 ] ; } ;"
|
||||
const std::string expected("; ; "
|
||||
"void f ( ) "
|
||||
"{"
|
||||
" A<int,3,2> a1 ;"
|
||||
|
@ -1355,9 +1336,7 @@ private:
|
|||
"{ }";
|
||||
|
||||
// The expected result..
|
||||
const std::string expected("template < class T >"
|
||||
" void foo ( T :: t * )"
|
||||
" { }");
|
||||
const std::string expected(";");
|
||||
ASSERT_EQUALS(expected, sizeof_(code));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue