Fixed #3814 (false positive: missing constructor)
This commit is contained in:
parent
4e2a86260f
commit
435340b463
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
|
@ -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..
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue