Fixed #3814 (false positive: missing constructor)

This commit is contained in:
Daniel Marjamäki 2012-07-29 16:01:05 +02:00
parent 4e2a86260f
commit 435340b463
4 changed files with 153 additions and 122 deletions

View File

@ -236,7 +236,73 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok)
return 0; return 0;
} }
void TemplateSimplifier::removeTemplates(Token *tok) bool TemplateSimplifier::removeTemplate(Token *tok)
{
if (!Token::simpleMatch(tok, "template <"))
return false;
int indentlevel = 0;
unsigned int countgt = 0; // Counter for ">"
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
if (tok2->str() == "(") {
tok2 = tok2->link();
} else if (tok2->str() == ")") { // garbage code! (#3504)
Token::eraseTokens(tok,tok2);
tok->deleteThis();
return false;
}
else if (tok2->str() == "{") {
tok2 = tok2->link()->next();
Token::eraseTokens(tok, tok2);
if (tok2 && tok2->str() == ";" && tok2->next())
tok->deleteNext();
tok->deleteThis();
return true;
} else if (tok2->str() == "}") { // garbage code! (#3449)
Token::eraseTokens(tok,tok2);
tok->deleteThis();
return false;
}
// Count ">"
if (tok2->str() == ">")
countgt++;
// don't remove constructor
if (tok2->str() == "explicit" ||
(countgt == 1 && Token::Match(tok2->previous(), "> %type% (") && Token::simpleMatch(tok2->next()->link(), ") {"))) {
Token::eraseTokens(tok, tok2);
tok->deleteThis();
return true;
}
if (tok2->str() == ";") {
tok2 = tok2->next();
Token::eraseTokens(tok, tok2);
tok->deleteThis();
return true;
}
if (tok2->str() == "<")
++indentlevel;
else if (indentlevel >= 2 && tok2->str() == ">")
--indentlevel;
else if (Token::Match(tok2, "> class|struct %var% [,)]")) {
tok2 = tok2->next();
Token::eraseTokens(tok, tok2);
tok->deleteThis();
return true;
}
}
return false;
}
void TemplateSimplifier::removeAllTemplates(Token *tok)
{ {
bool goback = false; bool goback = false;
for (; tok; tok = tok->next()) { for (; tok; tok = tok->next()) {
@ -244,70 +310,9 @@ void TemplateSimplifier::removeTemplates(Token *tok)
tok = tok->previous(); tok = tok->previous();
goback = false; goback = false;
} }
if (!Token::simpleMatch(tok, "template <"))
continue;
int indentlevel = 0; if (tok->str() == "template")
unsigned int countgt = 0; // Counter for ">" goback = removeTemplate(tok);
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
if (tok2->str() == "(") {
tok2 = tok2->link();
} else if (tok2->str() == ")") { // garbage code! (#3504)
Token::eraseTokens(tok,tok2);
tok->deleteThis();
break;
}
else if (tok2->str() == "{") {
tok2 = tok2->link()->next();
Token::eraseTokens(tok, tok2);
if (tok2 && tok2->str() == ";" && tok2->next())
tok->deleteNext();
tok->deleteThis();
goback = true;
break;
} else if (tok2->str() == "}") { // garbage code! (#3449)
Token::eraseTokens(tok,tok2);
tok->deleteThis();
break;
}
// Count ">"
if (tok2->str() == ">")
countgt++;
// don't remove constructor
if (tok2->str() == "explicit" ||
(countgt == 1 && Token::Match(tok2->previous(), "> %type% (") && Token::simpleMatch(tok2->next()->link(), ") {"))) {
Token::eraseTokens(tok, tok2);
tok->deleteThis();
goback = true;
break;
}
if (tok2->str() == ";") {
tok2 = tok2->next();
Token::eraseTokens(tok, tok2);
tok->deleteThis();
goback = true;
break;
}
if (tok2->str() == "<")
++indentlevel;
else if (indentlevel >= 2 && tok2->str() == ">")
--indentlevel;
else if (Token::Match(tok2, "> class|struct %var% [,)]")) {
tok2 = tok2->next();
Token::eraseTokens(tok, tok2);
tok->deleteThis();
goback = true;
break;
}
}
} }
} }
@ -955,7 +960,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
} }
void TemplateSimplifier::simplifyTemplateInstantions( bool TemplateSimplifier::simplifyTemplateInstantions(
TokenList& tokenlist, TokenList& tokenlist,
ErrorLogger& errorlogger, ErrorLogger& errorlogger,
const Settings *_settings, const Settings *_settings,
@ -976,7 +981,7 @@ void TemplateSimplifier::simplifyTemplateInstantions(
// bail out if the end of the file was reached // bail out if the end of the file was reached
if (!tok) if (!tok)
return; return false;
// get the position of the template name // get the position of the template name
int namepos = TemplateSimplifier::simplifyTemplatesGetTemplateNamePosition(tok); int namepos = TemplateSimplifier::simplifyTemplatesGetTemplateNamePosition(tok);
@ -986,7 +991,7 @@ void TemplateSimplifier::simplifyTemplateInstantions(
std::list<const Token *> callstack(1, tok); std::list<const Token *> callstack(1, tok);
errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "simplifyTemplates: bailing out", false)); errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "simplifyTemplates: bailing out", false));
} }
return; return false;
} }
// name of template function/class.. // name of template function/class..
@ -998,6 +1003,8 @@ void TemplateSimplifier::simplifyTemplateInstantions(
std::string::size_type amountOftemplateInstantiations = templateInstantiations.size(); std::string::size_type amountOftemplateInstantiations = templateInstantiations.size();
unsigned int recursiveCount = 0; unsigned int recursiveCount = 0;
bool instantiated = false;
for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) { for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) {
if (amountOftemplateInstantiations != templateInstantiations.size()) { if (amountOftemplateInstantiations != templateInstantiations.size()) {
amountOftemplateInstantiations = templateInstantiations.size(); amountOftemplateInstantiations = templateInstantiations.size();
@ -1065,6 +1072,7 @@ void TemplateSimplifier::simplifyTemplateInstantions(
if (expandedtemplates.find(newName) == expandedtemplates.end()) { if (expandedtemplates.find(newName) == expandedtemplates.end()) {
expandedtemplates.insert(newName); expandedtemplates.insert(newName);
TemplateSimplifier::simplifyTemplatesExpandTemplate(tokenlist, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantion,templateInstantiations); TemplateSimplifier::simplifyTemplatesExpandTemplate(tokenlist, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantion,templateInstantiations);
instantiated = true;
} }
// Replace all these template usages.. // Replace all these template usages..
@ -1112,6 +1120,9 @@ void TemplateSimplifier::simplifyTemplateInstantions(
removeTokens.pop_back(); removeTokens.pop_back();
} }
} }
// Template has been instantiated .. then remove the template declaration
return instantiated;
} }
@ -1129,10 +1140,8 @@ void TemplateSimplifier::simplifyTemplates(
// this info is used by checks // this info is used by checks
std::list<Token *> templates(TemplateSimplifier::simplifyTemplatesGetTemplateDeclarations(tokenlist.front(), _codeWithTemplates)); std::list<Token *> templates(TemplateSimplifier::simplifyTemplatesGetTemplateDeclarations(tokenlist.front(), _codeWithTemplates));
if (templates.empty()) { if (templates.empty())
TemplateSimplifier::removeTemplates(tokenlist.front());
return; return;
}
// There are templates.. // There are templates..
// Remove "typename" unless used in template arguments.. // Remove "typename" unless used in template arguments..
@ -1151,11 +1160,9 @@ void TemplateSimplifier::simplifyTemplates(
// Locate possible instantiations of templates.. // Locate possible instantiations of templates..
std::list<Token *> templateInstantiations(TemplateSimplifier::simplifyTemplatesGetTemplateInstantiations(tokenlist.front())); std::list<Token *> templateInstantiations(TemplateSimplifier::simplifyTemplatesGetTemplateInstantiations(tokenlist.front()));
// No template instantiations? Then remove all templates. // No template instantiations? Then return.
if (templateInstantiations.empty()) { if (templateInstantiations.empty())
TemplateSimplifier::removeTemplates(tokenlist.front());
return; return;
}
// Template arguments with default values // Template arguments with default values
TemplateSimplifier::simplifyTemplatesUseDefaultArgumentValues(templates, templateInstantiations); TemplateSimplifier::simplifyTemplatesUseDefaultArgumentValues(templates, templateInstantiations);
@ -1165,14 +1172,24 @@ void TemplateSimplifier::simplifyTemplates(
//while (!done) //while (!done)
{ {
//done = true; //done = true;
std::list<Token *> templates2;
for (std::list<Token *>::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) { for (std::list<Token *>::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) {
TemplateSimplifier::simplifyTemplateInstantions( bool instantiated = TemplateSimplifier::simplifyTemplateInstantions(tokenlist,
tokenlist, errorlogger,
errorlogger, _settings,
_settings, *iter1,
*iter1, templateInstantiations, expandedtemplates); templateInstantiations,
expandedtemplates);
if (instantiated)
templates2.push_back(*iter1);
}
for (std::list<Token *>::iterator it = templates2.begin(); it != templates2.end(); ++it) {
std::list<Token *>::iterator it1 = std::find(templates.begin(), templates.end(), *it);
if (it1 != templates.end()) {
templates.erase(it1);
removeTemplate(*it);
}
} }
} }
TemplateSimplifier::removeTemplates(tokenlist.front());
} }

View File

@ -64,11 +64,6 @@ public:
*/ */
static unsigned int templateParameters(const Token *tok); static unsigned int templateParameters(const Token *tok);
/**
* Remove "template < ..." they can cause false positives because they are not expanded
*/
static void removeTemplates(Token *tok);
/** /**
* Expand specialized templates : "template<>.." * Expand specialized templates : "template<>.."
* @return names of expanded templates * @return names of expanded templates
@ -131,8 +126,9 @@ public:
* @param tok token where the template declaration begins * @param tok token where the template declaration begins
* @param templateInstantiations a list of template usages (not necessarily just for this template) * @param templateInstantiations a list of template usages (not necessarily just for this template)
* @param expandedtemplates all templates that has been expanded so far. The full names are stored. * @param expandedtemplates all templates that has been expanded so far. The full names are stored.
* @return true if the template was instantiated
*/ */
static void simplifyTemplateInstantions( static bool simplifyTemplateInstantions(
TokenList& tokenlist, TokenList& tokenlist,
ErrorLogger& errorlogger, ErrorLogger& errorlogger,
const Settings *_settings, const Settings *_settings,
@ -160,6 +156,19 @@ public:
* false if no modifications are done. * false if no modifications are done.
*/ */
static bool simplifyCalculations(Token *_tokens); static bool simplifyCalculations(Token *_tokens);
private:
/**
* Remove all "template < ..." they can cause false positives because they are not expanded
*/
static void removeAllTemplates(Token *tok);
/**
* Remove a specific "template < ..." template class/function
*/
static bool removeTemplate(Token *tok);
}; };
/// @} /// @}

View File

@ -1649,7 +1649,8 @@ private:
"template <classname T> Fred<T>::Fred() { }\n" "template <classname T> Fred<T>::Fred() { }\n"
"Fred<float> fred;"; "Fred<float> fred;";
const std::string expected("Fred<float> fred ; " const std::string expected("template < classname T > Fred < T > :: Fred ( ) { } " // <- TODO: this should be removed
"Fred<float> fred ; "
"class Fred<float> { } " "class Fred<float> { } "
"Fred<float> :: Fred<float> ( ) { }"); "Fred<float> :: Fred<float> ( ) { }");
@ -1679,7 +1680,7 @@ private:
"\n" "\n"
"};\n"; "};\n";
const std::string expected(";"); const std::string expected("template < class T > class ABC { public: } ;");
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
} }
@ -1695,18 +1696,19 @@ private:
" return 0;\n" " return 0;\n"
"}\n"; "}\n";
const std::string wanted("int main ( ) { " const std::string wanted("template < typename T > class ABC { public: } ; "
"int main ( ) { "
"std :: vector < int > v ; " "std :: vector < int > v ; "
"v . push_back ( 4 ) ; " "v . push_back ( 4 ) ; "
"return 0 ; " "return 0 ; "
"}"); "}");
const std::string current("int main ( ) { " const std::string current("template < typename T > class ABC { public: } ; "
"int main ( ) { "
"ABC < int > :: type v ; " "ABC < int > :: type v ; "
"v . push_back ( 4 ) ; " "v . push_back ( 4 ) ; "
"return 0 ; " "return 0 ; "
"}" "}");
);
TODO_ASSERT_EQUALS(wanted, current, tok(code)); TODO_ASSERT_EQUALS(wanted, current, tok(code));
} }
@ -1722,7 +1724,12 @@ private:
" }\n" " }\n"
"};\n"; "};\n";
const std::string expected(";"); const std::string expected("template < typename T > class ABC { "
"public: void f ( ) { "
"ABC < int > :: type v ; "
"v . push_back ( 4 ) ; "
"} "
"} ;");
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
} }
@ -1747,9 +1754,12 @@ private:
"\n" "\n"
"template<typename T> inline B<T> h() { return B<T>(); }\n"; "template<typename T> inline B<T> h() { return B<T>(); }\n";
ASSERT_EQUALS("", tok(code)); ASSERT_EQUALS("template < typename T > class A ; "
"template < typename T > class B ; "
"template < typename T > class A { void f ( ) { B < T > a ; a = B < T > :: g ( ) ; T b ; b = 0 ; } } ; "
"template < typename T > B < T > h ( ) { return B < T > ( ) ; }", tok(code));
ASSERT_EQUALS("class A { } ;", tok("class A{ template<typename T> int foo(T d);};")); ASSERT_EQUALS("class A { template < typename T > int foo ( T d ) ; } ;", tok("class A{ template<typename T> int foo(T d);};"));
} }
void template9() { void template9() {
@ -1767,7 +1777,9 @@ private:
"} ;\n"; "} ;\n";
// The expected result.. // The expected result..
std::string expected("void f ( ) { A<int> a ; } class A<int> { } class A<T> { }"); std::string expected("void f ( ) { A<int> a ; } "
"template < typename T > class B { void g ( ) { A<T> b ; b = A<T> :: h ( ) ; } } ; "
"class A<int> { } class A<T> { }");
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
} }
@ -1977,7 +1989,8 @@ private:
"A<int> a;\n"; "A<int> a;\n";
// The expected result.. // The expected result..
const std::string expected("A<int> a ; " const std::string expected("template < class T > A < T > :: ~ A ( ) { } " // <- TODO: this should be removed
"A<int> a ; "
"class A<int> { public: ~ A<int> ( ) ; } " "class A<int> { public: ~ A<int> ( ) ; } "
"A<int> :: ~ A<int> ( ) { }"); "A<int> :: ~ A<int> ( ) { }");
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
@ -2014,18 +2027,6 @@ private:
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
} }
{
const char code[] = "template <classname T> struct Fred { };\n"
"template <classname T> Fred<T>::Fred() { }\n"
"Fred<float> fred;";
const std::string expected("Fred<float> fred ; "
"struct Fred<float> { } "
"Fred<float> :: Fred<float> ( ) { }");
ASSERT_EQUALS(expected, tok(code));
}
{ {
const char code[] = "template <classname T> struct Fred { };\n" const char code[] = "template <classname T> struct Fred { };\n"
"Fred<float> fred1;\n" "Fred<float> fred1;\n"
@ -2091,7 +2092,8 @@ private:
"\n" "\n"
"bitset<1> z;"; "bitset<1> z;";
const char actual[] = "bitset<1> z ; " const char actual[] = "template < int n > struct B { int a [ n ] ; } ; "
"bitset<1> z ; "
"class bitset<1> : B < ( ) > { }"; "class bitset<1> : B < ( ) > { }";
const char expected[] = "bitset<1> z ; " const char expected[] = "bitset<1> z ; "
@ -2112,13 +2114,13 @@ private:
"\n" "\n"
"C<2> a;\n"; "C<2> a;\n";
// TODO: expand A also // TODO: expand A also
ASSERT_EQUALS("C<2> a ; class C<2> : public A < char [ 2 ] > { }", tok(code)); ASSERT_EQUALS("template < class T > class A { public: T x ; } ; C<2> a ; class C<2> : public A < char [ 2 ] > { }", tok(code));
} }
void template27() { void template27() {
// #3350 - template inside macro call // #3350 - template inside macro call
const char code[] = "X(template<class T> class Fred);"; const char code[] = "X(template<class T> class Fred);";
ASSERT_EQUALS("X ( class Fred ) ;", tok(code)); ASSERT_EQUALS("X ( template < class T > class Fred ) ;", tok(code));
} }
void template28() { void template28() {
@ -2133,13 +2135,13 @@ private:
const char code[] = "template<typename T> struct A;\n" const char code[] = "template<typename T> struct A;\n"
"struct B { template<typename T> struct C };\n" "struct B { template<typename T> struct C };\n"
"{};"; "{};";
ASSERT_EQUALS("struct B { } ; { } ;", tok(code)); ASSERT_EQUALS("template < typename T > struct A ; struct B { template < typename T > struct C } ; { } ;", tok(code));
} }
void template30() { void template30() {
// #3529 - template < template < .. // #3529 - template < template < ..
const char code[] = "template<template<class> class A, class B> void f(){}"; const char code[] = "template<template<class> class A, class B> void f(){}";
ASSERT_EQUALS("", tok(code)); ASSERT_EQUALS("template < template < class > class A , class B > void f ( ) { }", tok(code));
} }
void template_unhandled() { void template_unhandled() {
@ -2264,7 +2266,7 @@ private:
"{ }"; "{ }";
// The expected result.. // The expected result..
const std::string expected(""); const std::string expected("template < class T > void foo ( T :: t * ) { }");
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
} }
@ -2284,13 +2286,13 @@ private:
const char code[] = "class Fred {\n" const char code[] = "class Fred {\n"
" template<class T> explicit Fred(T t) { }\n" " template<class T> explicit Fred(T t) { }\n"
"}"; "}";
ASSERT_EQUALS("class Fred { explicit Fred ( T t ) { } }", tok(code)); ASSERT_EQUALS("class Fred { template < class T > explicit Fred ( T t ) { } }", tok(code));
// #3532 // #3532
const char code2[] = "class Fred {\n" const char code2[] = "class Fred {\n"
" template<class T> Fred(T t) { }\n" " template<class T> Fred(T t) { }\n"
"}"; "}";
ASSERT_EQUALS("class Fred { Fred ( T t ) { } }", tok(code2)); ASSERT_EQUALS("class Fred { template < class T > Fred ( T t ) { } }", tok(code2));
} }
unsigned int templateParameters(const char code[]) { unsigned int templateParameters(const char code[]) {
@ -4465,7 +4467,7 @@ private:
void simplifyTypedef39() { void simplifyTypedef39() {
const char code[] = "typedef int A;\n" const char code[] = "typedef int A;\n"
"template <const A, volatile A>::value;"; "template <const A, volatile A>::value;";
const char expected[] = ""; const char expected[] = "template < const int , int > :: value ;";
ASSERT_EQUALS(expected, tok(code, false)); ASSERT_EQUALS(expected, tok(code, false));
checkSimplifyTypedef(code); checkSimplifyTypedef(code);
@ -4476,7 +4478,7 @@ private:
const char code[] = "typedef int A;\n" const char code[] = "typedef int A;\n"
"typedef int B;\n" "typedef int B;\n"
"template <class A, class B> class C { };"; "template <class A, class B> class C { };";
const char expected[] = ";"; const char expected[] = "template < class A , class B > class C { } ;";
ASSERT_EQUALS(expected, tok(code, false)); ASSERT_EQUALS(expected, tok(code, false));
checkSimplifyTypedef(code); checkSimplifyTypedef(code);
@ -4954,7 +4956,7 @@ private:
" typedef void (SomeTemplateClass<DISPATCHER>::*MessageDispatcherFunc)(SerialInputMessage&);\n" " typedef void (SomeTemplateClass<DISPATCHER>::*MessageDispatcherFunc)(SerialInputMessage&);\n"
"};\n"; "};\n";
// The expected result.. // The expected result..
const std::string expected(";"); const std::string expected("template < typename DISPATCHER > class SomeTemplateClass { } ;");
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
// Check for output.. // Check for output..

View File

@ -5676,7 +5676,10 @@ private:
"struct S\n" "struct S\n"
"{};\n" "{};\n"
"S<int> s;\n"; "S<int> s;\n";
TODO_ASSERT_EQUALS("S < int , ( int ) 0 > s ;", // wanted result TODO_ASSERT_EQUALS("S<int,(int)0> s ; struct S<int,(int)0> { } ;", // wanted result
"template < class T , T t >\n"
"struct S\n"
"{ } ;\n"
"S < int , ( T ) 0 > s ;", // current result "S < int , ( T ) 0 > s ;", // current result
tokenizeAndStringify(code)); tokenizeAndStringify(code));
} }