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;
}
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;
for (; tok; tok = tok->next()) {
@ -244,70 +310,9 @@ void TemplateSimplifier::removeTemplates(Token *tok)
tok = tok->previous();
goback = false;
}
if (!Token::simpleMatch(tok, "template <"))
continue;
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();
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;
}
}
if (tok->str() == "template")
goback = removeTemplate(tok);
}
}
@ -955,7 +960,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
}
void TemplateSimplifier::simplifyTemplateInstantions(
bool TemplateSimplifier::simplifyTemplateInstantions(
TokenList& tokenlist,
ErrorLogger& errorlogger,
const Settings *_settings,
@ -976,7 +981,7 @@ void TemplateSimplifier::simplifyTemplateInstantions(
// bail out if the end of the file was reached
if (!tok)
return;
return false;
// get the position of the template name
int namepos = TemplateSimplifier::simplifyTemplatesGetTemplateNamePosition(tok);
@ -986,7 +991,7 @@ void TemplateSimplifier::simplifyTemplateInstantions(
std::list<const Token *> callstack(1, tok);
errorlogger.reportErr(ErrorLogger::ErrorMessage(callstack, &tokenlist, Severity::debug, "debug", "simplifyTemplates: bailing out", false));
}
return;
return false;
}
// name of template function/class..
@ -998,6 +1003,8 @@ void TemplateSimplifier::simplifyTemplateInstantions(
std::string::size_type amountOftemplateInstantiations = templateInstantiations.size();
unsigned int recursiveCount = 0;
bool instantiated = false;
for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) {
if (amountOftemplateInstantiations != templateInstantiations.size()) {
amountOftemplateInstantiations = templateInstantiations.size();
@ -1065,6 +1072,7 @@ void TemplateSimplifier::simplifyTemplateInstantions(
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
expandedtemplates.insert(newName);
TemplateSimplifier::simplifyTemplatesExpandTemplate(tokenlist, tok,name,typeParametersInDeclaration,newName,typesUsedInTemplateInstantion,templateInstantiations);
instantiated = true;
}
// Replace all these template usages..
@ -1112,6 +1120,9 @@ void TemplateSimplifier::simplifyTemplateInstantions(
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
std::list<Token *> templates(TemplateSimplifier::simplifyTemplatesGetTemplateDeclarations(tokenlist.front(), _codeWithTemplates));
if (templates.empty()) {
TemplateSimplifier::removeTemplates(tokenlist.front());
if (templates.empty())
return;
}
// There are templates..
// Remove "typename" unless used in template arguments..
@ -1151,11 +1160,9 @@ void TemplateSimplifier::simplifyTemplates(
// Locate possible instantiations of templates..
std::list<Token *> templateInstantiations(TemplateSimplifier::simplifyTemplatesGetTemplateInstantiations(tokenlist.front()));
// No template instantiations? Then remove all templates.
if (templateInstantiations.empty()) {
TemplateSimplifier::removeTemplates(tokenlist.front());
// No template instantiations? Then return.
if (templateInstantiations.empty())
return;
}
// Template arguments with default values
TemplateSimplifier::simplifyTemplatesUseDefaultArgumentValues(templates, templateInstantiations);
@ -1165,14 +1172,24 @@ void TemplateSimplifier::simplifyTemplates(
//while (!done)
{
//done = true;
std::list<Token *> templates2;
for (std::list<Token *>::reverse_iterator iter1 = templates.rbegin(); iter1 != templates.rend(); ++iter1) {
TemplateSimplifier::simplifyTemplateInstantions(
tokenlist,
errorlogger,
_settings,
*iter1, templateInstantiations, expandedtemplates);
bool instantiated = TemplateSimplifier::simplifyTemplateInstantions(tokenlist,
errorlogger,
_settings,
*iter1,
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);
/**
* Remove "template < ..." they can cause false positives because they are not expanded
*/
static void removeTemplates(Token *tok);
/**
* Expand specialized templates : "template<>.."
* @return names of expanded templates
@ -131,8 +126,9 @@ public:
* @param tok token where the template declaration begins
* @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.
* @return true if the template was instantiated
*/
static void simplifyTemplateInstantions(
static bool simplifyTemplateInstantions(
TokenList& tokenlist,
ErrorLogger& errorlogger,
const Settings *_settings,
@ -160,6 +156,19 @@ public:
* false if no modifications are done.
*/
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"
"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> { } "
"Fred<float> :: Fred<float> ( ) { }");
@ -1679,7 +1680,7 @@ private:
"\n"
"};\n";
const std::string expected(";");
const std::string expected("template < class T > class ABC { public: } ;");
ASSERT_EQUALS(expected, tok(code));
}
@ -1695,18 +1696,19 @@ private:
" return 0;\n"
"}\n";
const std::string wanted("int main ( ) { "
const std::string wanted("template < typename T > class ABC { public: } ; "
"int main ( ) { "
"std :: vector < int > v ; "
"v . push_back ( 4 ) ; "
"return 0 ; "
"}");
const std::string current("int main ( ) { "
const std::string current("template < typename T > class ABC { public: } ; "
"int main ( ) { "
"ABC < int > :: type v ; "
"v . push_back ( 4 ) ; "
"return 0 ; "
"}"
);
"}");
TODO_ASSERT_EQUALS(wanted, current, tok(code));
}
@ -1722,7 +1724,12 @@ private:
" }\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));
}
@ -1747,9 +1754,12 @@ private:
"\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() {
@ -1767,7 +1777,9 @@ private:
"} ;\n";
// 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));
}
@ -1977,7 +1989,8 @@ private:
"A<int> a;\n";
// 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> ( ) ; } "
"A<int> :: ~ A<int> ( ) { }");
ASSERT_EQUALS(expected, tok(code));
@ -2014,18 +2027,6 @@ private:
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"
"Fred<float> fred1;\n"
@ -2091,7 +2092,8 @@ private:
"\n"
"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 < ( ) > { }";
const char expected[] = "bitset<1> z ; "
@ -2112,13 +2114,13 @@ private:
"\n"
"C<2> a;\n";
// 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() {
// #3350 - template inside macro call
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() {
@ -2133,13 +2135,13 @@ private:
const char code[] = "template<typename T> struct A;\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() {
// #3529 - template < template < ..
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() {
@ -2264,7 +2266,7 @@ private:
"{ }";
// The expected result..
const std::string expected("");
const std::string expected("template < class T > void foo ( T :: t * ) { }");
ASSERT_EQUALS(expected, tok(code));
}
@ -2284,13 +2286,13 @@ private:
const char code[] = "class Fred {\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
const char code2[] = "class Fred {\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[]) {
@ -4465,7 +4467,7 @@ private:
void simplifyTypedef39() {
const char code[] = "typedef int A;\n"
"template <const A, volatile A>::value;";
const char expected[] = "";
const char expected[] = "template < const int , int > :: value ;";
ASSERT_EQUALS(expected, tok(code, false));
checkSimplifyTypedef(code);
@ -4476,7 +4478,7 @@ private:
const char code[] = "typedef int A;\n"
"typedef int B;\n"
"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));
checkSimplifyTypedef(code);
@ -4954,7 +4956,7 @@ private:
" typedef void (SomeTemplateClass<DISPATCHER>::*MessageDispatcherFunc)(SerialInputMessage&);\n"
"};\n";
// The expected result..
const std::string expected(";");
const std::string expected("template < typename DISPATCHER > class SomeTemplateClass { } ;");
ASSERT_EQUALS(expected, tok(code));
// Check for output..

View File

@ -5676,7 +5676,10 @@ private:
"struct S\n"
"{};\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
tokenizeAndStringify(code));
}