Cleaning up unsimplified templates
This commit is contained in:
parent
8298937077
commit
d58d4273f9
|
@ -212,6 +212,39 @@ void TemplateSimplifier::cleanupAfterSimplify()
|
|||
}
|
||||
}
|
||||
|
||||
void TemplateSimplifier::removeTemplates()
|
||||
{
|
||||
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
||||
if (!Token::simpleMatch(tok, "template <"))
|
||||
continue;
|
||||
if (tok->previous() && !Token::Match(tok->previous(), "[;}]"))
|
||||
continue;
|
||||
Token *endToken = tok;
|
||||
while (nullptr != (endToken = endToken->next())) {
|
||||
if (endToken->str() == ";")
|
||||
break;
|
||||
if (Token::Match(endToken, "[})]]")) {
|
||||
endToken = nullptr;
|
||||
break;
|
||||
}
|
||||
if (Token::Match(endToken, "[<([]") && endToken->link())
|
||||
endToken = endToken->link();
|
||||
else if (endToken->str() == "{") {
|
||||
endToken = endToken->link();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!endToken)
|
||||
continue;
|
||||
Token::eraseTokens(tok, endToken);
|
||||
tok = endToken;
|
||||
tok->deletePrevious();
|
||||
if (tok->str() == "}") {
|
||||
tok->str(";");
|
||||
tok->link(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateSimplifier::checkComplicatedSyntaxErrorsInTemplates()
|
||||
{
|
||||
|
|
|
@ -53,6 +53,12 @@ public:
|
|||
*/
|
||||
void cleanupAfterSimplify();
|
||||
|
||||
/**
|
||||
* Remove templates, can be used after the simplifications to remove
|
||||
* the templates that failed to be expanded.
|
||||
*/
|
||||
void removeTemplates();
|
||||
|
||||
/**
|
||||
*/
|
||||
void checkComplicatedSyntaxErrorsInTemplates();
|
||||
|
|
|
@ -4442,6 +4442,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
|
|||
// this function will just fix so that the syntax is corrected.
|
||||
validate(); // #6847 - invalid code
|
||||
mTemplateSimplifier->cleanupAfterSimplify();
|
||||
if (!mSettings->checkUnusedTemplates)
|
||||
mTemplateSimplifier->removeTemplates();
|
||||
}
|
||||
|
||||
// Simplify pointer to standard types (C only)
|
||||
|
|
|
@ -1867,10 +1867,11 @@ private:
|
|||
"}\n"
|
||||
"auto g() {\n"
|
||||
" std::vector<int> v;\n"
|
||||
" return by_value(v.begin());\n"
|
||||
" return by_value(v.front());\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS(
|
||||
TODO_ASSERT_EQUALS(
|
||||
"[test.cpp:7] -> [test.cpp:7] -> [test.cpp:3] -> [test.cpp:3] -> [test.cpp:6] -> [test.cpp:7]: (error) Returning object that points to local variable 'v' that will be invalid when returning.\n",
|
||||
"",
|
||||
errout.str());
|
||||
|
||||
check("auto by_ref(int& x) {\n"
|
||||
|
|
|
@ -2079,9 +2079,6 @@ private:
|
|||
check("void f1(const std::string &s) { if(s.empty()) if(s.size() > 42) {}} ");
|
||||
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
|
||||
|
||||
check("template<class T> void f1(const T &s) { if(s.size() > 42) if(s.empty()) {}} ");
|
||||
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
|
||||
|
||||
check("void f2(const std::wstring &s) { if(s.empty()) if(s.size() > 42) {}} ");
|
||||
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
|
||||
|
||||
|
|
|
@ -347,16 +347,6 @@ private:
|
|||
" int x;\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("template <class T> struct A {\n"
|
||||
" A<T>() : x(0) { }\n"
|
||||
" A<T>(const T & t) : x(t.x) { }\n"
|
||||
"private:\n"
|
||||
" int x;\n"
|
||||
" int y;\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("[test.cpp:2]: (warning) Member variable 'A::y' is not initialized in the constructor.\n"
|
||||
"[test.cpp:3]: (warning) Member variable 'A::y' is not initialized in the constructor.\n", errout.str());
|
||||
}
|
||||
|
||||
void simple7() { // ticket #4531
|
||||
|
|
|
@ -1365,7 +1365,7 @@ private:
|
|||
);
|
||||
|
||||
// #3449
|
||||
ASSERT_EQUALS("template < typename T > struct A ;\n"
|
||||
ASSERT_EQUALS(";\n"
|
||||
"struct B { template < typename T > struct C } ;\n"
|
||||
"{ } ;",
|
||||
checkCode("template<typename T> struct A;\n"
|
||||
|
|
|
@ -67,7 +67,6 @@ private:
|
|||
TEST_CASE(nullpointer24); // #5082 fp: chained assignment
|
||||
TEST_CASE(nullpointer25); // #5061
|
||||
TEST_CASE(nullpointer26); // #3589
|
||||
TEST_CASE(nullpointer27); // #6568
|
||||
TEST_CASE(nullpointer28); // #6491
|
||||
TEST_CASE(nullpointer30); // #6392
|
||||
TEST_CASE(nullpointer31); // #8482
|
||||
|
@ -1322,20 +1321,6 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void nullpointer27() { // #6568
|
||||
check("template<class Type>\n"
|
||||
"class Foo {\n"
|
||||
" Foo<Type>& operator = ( Type* );\n"
|
||||
"};\n"
|
||||
"template<class Type>\n"
|
||||
"Foo<Type>& Foo<Type>::operator = ( Type* pointer_ ) {\n"
|
||||
" pointer_=NULL;\n"
|
||||
" *pointer_=0;\n"
|
||||
" return *this;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:8]: (error) Null pointer dereference: pointer_\n", errout.str());
|
||||
}
|
||||
|
||||
void nullpointer28() { // #6491
|
||||
check("typedef struct { int value; } S;\n"
|
||||
"int f(const S *s) { \n"
|
||||
|
|
|
@ -5005,11 +5005,6 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
check("template<int n> void foo(unsigned int x) {\n"
|
||||
"if (x <= 0);\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:2]: (style) Checking if unsigned expression 'x' is less than zero.\n", errout.str());
|
||||
|
||||
// #8836
|
||||
check("uint32_t value = 0xFUL;\n"
|
||||
"void f() {\n"
|
||||
|
@ -7457,12 +7452,11 @@ private:
|
|||
}
|
||||
|
||||
void forwardAndUsed() {
|
||||
check("template<typename T>\n"
|
||||
"void f(T && t) {\n"
|
||||
" g(std::forward<T>(t));\n"
|
||||
" T s = t;\n"
|
||||
check("void f(Foo && foo) {\n"
|
||||
" g(std::forward<Foo>(foo));\n"
|
||||
" Foo s = foo;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (warning) Access of forwarded variable 't'.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3]: (warning) Access of forwarded variable 'foo'.\n", errout.str());
|
||||
}
|
||||
|
||||
void funcArgNamesDifferent() {
|
||||
|
|
|
@ -38,6 +38,7 @@ private:
|
|||
|
||||
void run() OVERRIDE {
|
||||
settings.addEnabled("portability");
|
||||
settings.checkUnusedTemplates = true;
|
||||
|
||||
TEST_CASE(template1);
|
||||
TEST_CASE(template2);
|
||||
|
@ -191,6 +192,8 @@ private:
|
|||
TEST_CASE(templateTypeDeduction2);
|
||||
|
||||
TEST_CASE(simplifyTemplateArgs);
|
||||
|
||||
TEST_CASE(removeTemplates);
|
||||
}
|
||||
|
||||
std::string tok(const char code[], bool debugwarnings = false, Settings::PlatformType type = Settings::Native) {
|
||||
|
@ -386,7 +389,8 @@ private:
|
|||
|
||||
// The expected result..
|
||||
const char expected[] = "class A<int> ; "
|
||||
"void f ( ) { A<int> a ; } ; "
|
||||
"void f ( ) { A<int> a ; } "
|
||||
"template < typename T > class B { void g ( ) { A < T > b ; b = A < T > :: h ( ) ; } } ; "
|
||||
"class A<int> { } ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
|
@ -1385,6 +1389,7 @@ private:
|
|||
"template <class T, unsigned S> C3<T, S>::C3(const C3<T, S> &v) { C1<T *> c1; }\n"
|
||||
"C3<int,6> c3;";
|
||||
const char exp[] = "struct C1<int*> ; "
|
||||
"template < class T > void f ( ) { x = y ? ( C1 < int > :: allocate ( 1 ) ) : 0 ; } "
|
||||
"class C3<int,6> ; "
|
||||
"C3<int,6> c3 ; "
|
||||
"class C3<int,6> { } ; "
|
||||
|
@ -2392,6 +2397,7 @@ private:
|
|||
"template <typename T> class Fred {};\n"
|
||||
"ObjectCache<Fred> _cache;";
|
||||
const char exp[] = "class ObjectCache<Fred> ; "
|
||||
"template < typename T > class Fred { } ; "
|
||||
"ObjectCache<Fred> _cache ; "
|
||||
"class ObjectCache<Fred> { } ;";
|
||||
ASSERT_EQUALS(exp, tok(code));
|
||||
|
@ -2499,7 +2505,8 @@ private:
|
|||
"template < class T > struct Unconst < const T & > { } ; "
|
||||
"template < class T > struct Unconst < T * const > { } ; "
|
||||
"template < class T1 , class T2 > struct type_equal { enum Anonymous0 { value = 0 } ; } ; "
|
||||
"template < class T > struct type_equal < T , T > { enum Anonymous1 { value = 1 } ; } ;";
|
||||
"template < class T > struct type_equal < T , T > { enum Anonymous1 { value = 1 } ; } ; "
|
||||
"template < class T > struct template_is_const { enum Anonymous2 { value = ! type_equal < T , Unconst < T > :: type > :: value } ; } ;";
|
||||
ASSERT_EQUALS(exp1, tok(code1));
|
||||
}
|
||||
|
||||
|
@ -2739,7 +2746,7 @@ private:
|
|||
const char code[] = "class Fred {\n"
|
||||
" template<class T> explicit Fred(T t) { }\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("class Fred { }", tok(code));
|
||||
ASSERT_EQUALS("class Fred { template < class T > explicit Fred ( T t ) { } }", tok(code));
|
||||
|
||||
// #3532
|
||||
const char code2[] = "class Fred {\n"
|
||||
|
@ -3562,6 +3569,26 @@ private:
|
|||
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < ( 1 - 1) ? true : false >;"));
|
||||
}
|
||||
|
||||
std::string removeTemplates(const char code[]) {
|
||||
Settings settings2;
|
||||
settings2.checkUnusedTemplates = false;
|
||||
|
||||
errout.str("");
|
||||
|
||||
Tokenizer tokenizer(&settings2, this);
|
||||
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp");
|
||||
|
||||
return tokenizer.tokens()->stringifyList(0, true);
|
||||
}
|
||||
|
||||
void removeTemplates() {
|
||||
// #9057
|
||||
ASSERT_EQUALS(";", removeTemplates("template <typename T> using foo = enable_if_t<is_same<T, int>() && sizeof(int) == 4, int>;\n"
|
||||
"template <typename T, typename U = foo<T>> struct bar {};\n"
|
||||
"template <typename T> using baz = bar<T>;\n"));
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestSimplifyTemplate)
|
||||
|
|
|
@ -43,7 +43,9 @@ private:
|
|||
LOAD_LIB_2(settings_std.library, "std.cfg");
|
||||
LOAD_LIB_2(settings_windows.library, "windows.cfg");
|
||||
settings0.addEnabled("portability");
|
||||
settings0.checkUnusedTemplates = true;
|
||||
settings1.addEnabled("style");
|
||||
settings1.checkUnusedTemplates = true;
|
||||
settings_windows.addEnabled("portability");
|
||||
|
||||
// Make sure the Tokenizer::simplifyTokenList works.
|
||||
|
|
|
@ -41,6 +41,9 @@ private:
|
|||
void run() OVERRIDE {
|
||||
settings0.addEnabled("style");
|
||||
settings2.addEnabled("style");
|
||||
settings0.checkUnusedTemplates = true;
|
||||
settings1.checkUnusedTemplates = true;
|
||||
settings2.checkUnusedTemplates = true;
|
||||
|
||||
TEST_CASE(simplifyTypedef1)
|
||||
TEST_CASE(simplifyTypedef2)
|
||||
|
@ -2527,7 +2530,8 @@ private:
|
|||
"template <long, class> struct c; "
|
||||
"template <int g> struct d { enum { e = c<g, b>::f }; };";
|
||||
const char exp [] = "class a ; "
|
||||
"template < long , class > struct c ;";
|
||||
"template < long , class > struct c ; "
|
||||
"template < int g > struct d { enum Anonymous0 { e = c < g , int ( a :: * ) > :: f } ; } ;";
|
||||
ASSERT_EQUALS(exp, tok(code, false));
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ private:
|
|||
void run() OVERRIDE {
|
||||
settings0.addEnabled("style");
|
||||
settings2.addEnabled("style");
|
||||
settings0.checkUnusedTemplates = true;
|
||||
settings1.checkUnusedTemplates = true;
|
||||
settings2.checkUnusedTemplates = true;
|
||||
|
||||
TEST_CASE(simplifyUsing1);
|
||||
TEST_CASE(simplifyUsing2);
|
||||
|
@ -489,7 +492,8 @@ private:
|
|||
"class c { "
|
||||
"int i ; i = 0 ; "
|
||||
"c ( ) { i -- ; } "
|
||||
"} ;";
|
||||
"} ; "
|
||||
"template < class T > class s { } ;";
|
||||
|
||||
ASSERT_EQUALS(exp, tok(code, true, Settings::Win64));
|
||||
}
|
||||
|
|
|
@ -106,6 +106,7 @@ private:
|
|||
|
||||
void run() OVERRIDE {
|
||||
LOAD_LIB_2(settings1.library, "std.cfg");
|
||||
settings1.checkUnusedTemplates = true;
|
||||
settings2.platform(Settings::Unspecified);
|
||||
|
||||
TEST_CASE(array);
|
||||
|
|
|
@ -47,6 +47,10 @@ private:
|
|||
void run() OVERRIDE {
|
||||
LOAD_LIB_2(settings_windows.library, "windows.cfg");
|
||||
|
||||
settings0.checkUnusedTemplates = true;
|
||||
settings1.checkUnusedTemplates = true;
|
||||
settings2.checkUnusedTemplates = true;
|
||||
|
||||
TEST_CASE(tokenize1);
|
||||
TEST_CASE(tokenize2);
|
||||
TEST_CASE(tokenize3);
|
||||
|
|
|
@ -32,6 +32,7 @@ private:
|
|||
public:
|
||||
explicit givenACodeSampleToTokenize(const char sample[], bool createOnly = false, bool cpp = true)
|
||||
: _tokenizer(&_settings, 0) {
|
||||
_settings.checkUnusedTemplates = true;
|
||||
std::istringstream iss(sample);
|
||||
if (createOnly)
|
||||
_tokenizer.list.createTokens(iss, cpp ? "test.cpp" : "test.c");
|
||||
|
|
|
@ -199,6 +199,7 @@ private:
|
|||
errout.str("");
|
||||
|
||||
Settings settings;
|
||||
settings.checkUnusedTemplates = true;
|
||||
settings.platform(Settings::Unix64);
|
||||
settings.standards.c = Standards::C89;
|
||||
settings.standards.cpp = Standards::CPP11;
|
||||
|
@ -218,6 +219,7 @@ private:
|
|||
errout.str("");
|
||||
|
||||
Settings settings;
|
||||
settings.checkUnusedTemplates = true;
|
||||
settings.platform(Settings::Unix64);
|
||||
settings.standards.c = Standards::C89;
|
||||
settings.standards.cpp = Standards::CPP11;
|
||||
|
|
Loading…
Reference in New Issue