Skip to content

Commit d58d427

Browse files
committed
Cleaning up unsimplified templates
1 parent 8298937 commit d58d427

17 files changed

Lines changed: 99 additions & 46 deletions

lib/templatesimplifier.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,39 @@ void TemplateSimplifier::cleanupAfterSimplify()
212212
}
213213
}
214214

215+
void TemplateSimplifier::removeTemplates()
216+
{
217+
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
218+
if (!Token::simpleMatch(tok, "template <"))
219+
continue;
220+
if (tok->previous() && !Token::Match(tok->previous(), "[;}]"))
221+
continue;
222+
Token *endToken = tok;
223+
while (nullptr != (endToken = endToken->next())) {
224+
if (endToken->str() == ";")
225+
break;
226+
if (Token::Match(endToken, "[})]]")) {
227+
endToken = nullptr;
228+
break;
229+
}
230+
if (Token::Match(endToken, "[<([]") && endToken->link())
231+
endToken = endToken->link();
232+
else if (endToken->str() == "{") {
233+
endToken = endToken->link();
234+
break;
235+
}
236+
}
237+
if (!endToken)
238+
continue;
239+
Token::eraseTokens(tok, endToken);
240+
tok = endToken;
241+
tok->deletePrevious();
242+
if (tok->str() == "}") {
243+
tok->str(";");
244+
tok->link(nullptr);
245+
}
246+
}
247+
}
215248

216249
void TemplateSimplifier::checkComplicatedSyntaxErrorsInTemplates()
217250
{

lib/templatesimplifier.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ class CPPCHECKLIB TemplateSimplifier {
5353
*/
5454
void cleanupAfterSimplify();
5555

56+
/**
57+
* Remove templates, can be used after the simplifications to remove
58+
* the templates that failed to be expanded.
59+
*/
60+
void removeTemplates();
61+
5662
/**
5763
*/
5864
void checkComplicatedSyntaxErrorsInTemplates();

lib/tokenize.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4442,6 +4442,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
44424442
// this function will just fix so that the syntax is corrected.
44434443
validate(); // #6847 - invalid code
44444444
mTemplateSimplifier->cleanupAfterSimplify();
4445+
if (!mSettings->checkUnusedTemplates)
4446+
mTemplateSimplifier->removeTemplates();
44454447
}
44464448

44474449
// Simplify pointer to standard types (C only)

test/testautovariables.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,10 +1867,11 @@ class TestAutoVariables : public TestFixture {
18671867
"}\n"
18681868
"auto g() {\n"
18691869
" std::vector<int> v;\n"
1870-
" return by_value(v.begin());\n"
1870+
" return by_value(v.front());\n"
18711871
"}\n");
1872-
ASSERT_EQUALS(
1872+
TODO_ASSERT_EQUALS(
18731873
"[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",
1874+
"",
18741875
errout.str());
18751876

18761877
check("auto by_ref(int& x) {\n"

test/testcondition.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,9 +2079,6 @@ class TestCondition : public TestFixture {
20792079
check("void f1(const std::string &s) { if(s.empty()) if(s.size() > 42) {}} ");
20802080
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
20812081

2082-
check("template<class T> void f1(const T &s) { if(s.size() > 42) if(s.empty()) {}} ");
2083-
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
2084-
20852082
check("void f2(const std::wstring &s) { if(s.empty()) if(s.size() > 42) {}} ");
20862083
ASSERT_EQUALS("[test.cpp:1] -> [test.cpp:1]: (warning) Opposite inner 'if' condition leads to a dead code block.\n", errout.str());
20872084

test/testconstructors.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -347,16 +347,6 @@ class TestConstructors : public TestFixture {
347347
" int x;\n"
348348
"};");
349349
ASSERT_EQUALS("", errout.str());
350-
351-
check("template <class T> struct A {\n"
352-
" A<T>() : x(0) { }\n"
353-
" A<T>(const T & t) : x(t.x) { }\n"
354-
"private:\n"
355-
" int x;\n"
356-
" int y;\n"
357-
"};");
358-
ASSERT_EQUALS("[test.cpp:2]: (warning) Member variable 'A::y' is not initialized in the constructor.\n"
359-
"[test.cpp:3]: (warning) Member variable 'A::y' is not initialized in the constructor.\n", errout.str());
360350
}
361351

362352
void simple7() { // ticket #4531

test/testgarbage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ class TestGarbage : public TestFixture {
13651365
);
13661366

13671367
// #3449
1368-
ASSERT_EQUALS("template < typename T > struct A ;\n"
1368+
ASSERT_EQUALS(";\n"
13691369
"struct B { template < typename T > struct C } ;\n"
13701370
"{ } ;",
13711371
checkCode("template<typename T> struct A;\n"

test/testnullpointer.cpp

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ class TestNullPointer : public TestFixture {
6767
TEST_CASE(nullpointer24); // #5082 fp: chained assignment
6868
TEST_CASE(nullpointer25); // #5061
6969
TEST_CASE(nullpointer26); // #3589
70-
TEST_CASE(nullpointer27); // #6568
7170
TEST_CASE(nullpointer28); // #6491
7271
TEST_CASE(nullpointer30); // #6392
7372
TEST_CASE(nullpointer31); // #8482
@@ -1322,20 +1321,6 @@ class TestNullPointer : public TestFixture {
13221321
ASSERT_EQUALS("", errout.str());
13231322
}
13241323

1325-
void nullpointer27() { // #6568
1326-
check("template<class Type>\n"
1327-
"class Foo {\n"
1328-
" Foo<Type>& operator = ( Type* );\n"
1329-
"};\n"
1330-
"template<class Type>\n"
1331-
"Foo<Type>& Foo<Type>::operator = ( Type* pointer_ ) {\n"
1332-
" pointer_=NULL;\n"
1333-
" *pointer_=0;\n"
1334-
" return *this;\n"
1335-
"}");
1336-
ASSERT_EQUALS("[test.cpp:8]: (error) Null pointer dereference: pointer_\n", errout.str());
1337-
}
1338-
13391324
void nullpointer28() { // #6491
13401325
check("typedef struct { int value; } S;\n"
13411326
"int f(const S *s) { \n"

test/testother.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5005,11 +5005,6 @@ class TestOther : public TestFixture {
50055005
ASSERT_EQUALS("", errout.str());
50065006
}
50075007

5008-
check("template<int n> void foo(unsigned int x) {\n"
5009-
"if (x <= 0);\n"
5010-
"}\n");
5011-
ASSERT_EQUALS("[test.cpp:2]: (style) Checking if unsigned expression 'x' is less than zero.\n", errout.str());
5012-
50135008
// #8836
50145009
check("uint32_t value = 0xFUL;\n"
50155010
"void f() {\n"
@@ -7457,12 +7452,11 @@ class TestOther : public TestFixture {
74577452
}
74587453

74597454
void forwardAndUsed() {
7460-
check("template<typename T>\n"
7461-
"void f(T && t) {\n"
7462-
" g(std::forward<T>(t));\n"
7463-
" T s = t;\n"
7455+
check("void f(Foo && foo) {\n"
7456+
" g(std::forward<Foo>(foo));\n"
7457+
" Foo s = foo;\n"
74647458
"}");
7465-
ASSERT_EQUALS("[test.cpp:4]: (warning) Access of forwarded variable 't'.\n", errout.str());
7459+
ASSERT_EQUALS("[test.cpp:3]: (warning) Access of forwarded variable 'foo'.\n", errout.str());
74667460
}
74677461

74687462
void funcArgNamesDifferent() {

test/testsimplifytemplate.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class TestSimplifyTemplate : public TestFixture {
3838

3939
void run() OVERRIDE {
4040
settings.addEnabled("portability");
41+
settings.checkUnusedTemplates = true;
4142

4243
TEST_CASE(template1);
4344
TEST_CASE(template2);
@@ -191,6 +192,8 @@ class TestSimplifyTemplate : public TestFixture {
191192
TEST_CASE(templateTypeDeduction2);
192193

193194
TEST_CASE(simplifyTemplateArgs);
195+
196+
TEST_CASE(removeTemplates);
194197
}
195198

196199
std::string tok(const char code[], bool debugwarnings = false, Settings::PlatformType type = Settings::Native) {
@@ -386,7 +389,8 @@ class TestSimplifyTemplate : public TestFixture {
386389

387390
// The expected result..
388391
const char expected[] = "class A<int> ; "
389-
"void f ( ) { A<int> a ; } ; "
392+
"void f ( ) { A<int> a ; } "
393+
"template < typename T > class B { void g ( ) { A < T > b ; b = A < T > :: h ( ) ; } } ; "
390394
"class A<int> { } ;";
391395

392396
ASSERT_EQUALS(expected, tok(code));
@@ -1385,6 +1389,7 @@ class TestSimplifyTemplate : public TestFixture {
13851389
"template <class T, unsigned S> C3<T, S>::C3(const C3<T, S> &v) { C1<T *> c1; }\n"
13861390
"C3<int,6> c3;";
13871391
const char exp[] = "struct C1<int*> ; "
1392+
"template < class T > void f ( ) { x = y ? ( C1 < int > :: allocate ( 1 ) ) : 0 ; } "
13881393
"class C3<int,6> ; "
13891394
"C3<int,6> c3 ; "
13901395
"class C3<int,6> { } ; "
@@ -2392,6 +2397,7 @@ class TestSimplifyTemplate : public TestFixture {
23922397
"template <typename T> class Fred {};\n"
23932398
"ObjectCache<Fred> _cache;";
23942399
const char exp[] = "class ObjectCache<Fred> ; "
2400+
"template < typename T > class Fred { } ; "
23952401
"ObjectCache<Fred> _cache ; "
23962402
"class ObjectCache<Fred> { } ;";
23972403
ASSERT_EQUALS(exp, tok(code));
@@ -2499,7 +2505,8 @@ class TestSimplifyTemplate : public TestFixture {
24992505
"template < class T > struct Unconst < const T & > { } ; "
25002506
"template < class T > struct Unconst < T * const > { } ; "
25012507
"template < class T1 , class T2 > struct type_equal { enum Anonymous0 { value = 0 } ; } ; "
2502-
"template < class T > struct type_equal < T , T > { enum Anonymous1 { value = 1 } ; } ;";
2508+
"template < class T > struct type_equal < T , T > { enum Anonymous1 { value = 1 } ; } ; "
2509+
"template < class T > struct template_is_const { enum Anonymous2 { value = ! type_equal < T , Unconst < T > :: type > :: value } ; } ;";
25032510
ASSERT_EQUALS(exp1, tok(code1));
25042511
}
25052512

@@ -2739,7 +2746,7 @@ class TestSimplifyTemplate : public TestFixture {
27392746
const char code[] = "class Fred {\n"
27402747
" template<class T> explicit Fred(T t) { }\n"
27412748
"}";
2742-
ASSERT_EQUALS("class Fred { }", tok(code));
2749+
ASSERT_EQUALS("class Fred { template < class T > explicit Fred ( T t ) { } }", tok(code));
27432750

27442751
// #3532
27452752
const char code2[] = "class Fred {\n"
@@ -3562,6 +3569,26 @@ class TestSimplifyTemplate : public TestFixture {
35623569
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < ( 1 - 1) ? true : false >;"));
35633570
}
35643571

3572+
std::string removeTemplates(const char code[]) {
3573+
Settings settings2;
3574+
settings2.checkUnusedTemplates = false;
3575+
3576+
errout.str("");
3577+
3578+
Tokenizer tokenizer(&settings2, this);
3579+
3580+
std::istringstream istr(code);
3581+
tokenizer.tokenize(istr, "test.cpp");
3582+
3583+
return tokenizer.tokens()->stringifyList(0, true);
3584+
}
3585+
3586+
void removeTemplates() {
3587+
// #9057
3588+
ASSERT_EQUALS(";", removeTemplates("template <typename T> using foo = enable_if_t<is_same<T, int>() && sizeof(int) == 4, int>;\n"
3589+
"template <typename T, typename U = foo<T>> struct bar {};\n"
3590+
"template <typename T> using baz = bar<T>;\n"));
3591+
}
35653592
};
35663593

35673594
REGISTER_TEST(TestSimplifyTemplate)

0 commit comments

Comments
 (0)