/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2023 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "errortypes.h"
#include "platform.h"
#include "settings.h"
#include "templatesimplifier.h"
#include "fixture.h"
#include "token.h"
#include "tokenize.h"
#include "tokenlist.h"
#include
#include // IWYU pragma: keep
#include
#include
class TestSimplifyTemplate : public TestFixture {
public:
TestSimplifyTemplate() : TestFixture("TestSimplifyTemplate") {}
private:
// If there are unused templates, keep those
const Settings settings = settingsBuilder().severity(Severity::portability).checkUnusedTemplates().build();
void run() override {
TEST_CASE(template1);
TEST_CASE(template2);
TEST_CASE(template3);
TEST_CASE(template4);
TEST_CASE(template5);
TEST_CASE(template6);
TEST_CASE(template7);
TEST_CASE(template8);
TEST_CASE(template9);
TEST_CASE(template10);
TEST_CASE(template11);
TEST_CASE(template12);
TEST_CASE(template13);
TEST_CASE(template14);
TEST_CASE(template15); // recursive templates
TEST_CASE(template16);
TEST_CASE(template17);
TEST_CASE(template18);
TEST_CASE(template19);
TEST_CASE(template20);
TEST_CASE(template21);
TEST_CASE(template22);
TEST_CASE(template23);
TEST_CASE(template24); // #2648 - using sizeof in template parameter
TEST_CASE(template25); // #2648 - another test for sizeof template parameter
TEST_CASE(template26); // #2721 - passing 'char[2]' as template parameter
TEST_CASE(template27); // #3350 - removing unused template in macro call
TEST_CASE(template28);
TEST_CASE(template30); // #3529 - template < template < ..
TEST_CASE(template31); // #4010 - reference type
TEST_CASE(template32); // #3818 - mismatching template not handled well
TEST_CASE(template33); // #3818,#4544 - inner templates in template instantiation not handled well
TEST_CASE(template34); // #3706 - namespace => hang
TEST_CASE(template35); // #4074 - A<'x'> a;
TEST_CASE(template36); // #4310 - passing unknown template instantiation as template argument
TEST_CASE(template37); // #4544 - A a;
TEST_CASE(template38); // #4832 - crash on C++11 right angle brackets
TEST_CASE(template39); // #4742 - freeze
TEST_CASE(template40); // #5055 - template specialization outside struct
TEST_CASE(template41); // #4710 - const in instantiation not handled perfectly
TEST_CASE(template42); // #4878 - variadic templates
TEST_CASE(template43); // #5097 - assert due to '>>' not treated as end of template instantiation
TEST_CASE(template44); // #5297 - TemplateSimplifier::simplifyCalculations not eager enough
TEST_CASE(template45); // #5814 - syntax error reported for valid code
TEST_CASE(template46); // #5816 - syntax error reported for valid code
TEST_CASE(template47); // #6023 - syntax error reported for valid code
TEST_CASE(template48); // #6134 - 100% CPU upon invalid code
TEST_CASE(template49); // #6237 - template instantiation
TEST_CASE(template50); // #4272 - simple partial specialization
TEST_CASE(template52); // #6437 - crash upon valid code
TEST_CASE(template53); // #4335 - bail out for valid code
TEST_CASE(template54); // #6587 - memory corruption upon valid code
TEST_CASE(template55); // #6604 - simplify "const const" to "const" in template instantiations
TEST_CASE(template56); // #7117 - const ternary operator simplification as template parameter
TEST_CASE(template57); // #7891
TEST_CASE(template58); // #6021 - use after free (deleted tokens in simplifyCalculations)
TEST_CASE(template59); // #8051 - TemplateSimplifier::simplifyTemplateInstantiation failure
TEST_CASE(template60); // handling of methods outside template definition
TEST_CASE(template61); // daca2, kodi
TEST_CASE(template62); // #8314 - inner template instantiation
TEST_CASE(template63); // #8576 - qualified type
TEST_CASE(template64); // #8683
TEST_CASE(template65); // #8321
TEST_CASE(template66); // #8725
TEST_CASE(template67); // #8122
TEST_CASE(template68); // union
TEST_CASE(template69); // #8791
TEST_CASE(template70); // #5289
TEST_CASE(template71); // #8821
TEST_CASE(template72);
TEST_CASE(template73);
TEST_CASE(template74);
TEST_CASE(template75);
TEST_CASE(template76);
TEST_CASE(template77);
TEST_CASE(template78);
TEST_CASE(template79); // #5133
TEST_CASE(template80);
TEST_CASE(template81);
TEST_CASE(template82); // #8603
TEST_CASE(template83); // #8867
TEST_CASE(template84); // #8880
TEST_CASE(template85); // #8902 crash
TEST_CASE(template86); // crash
TEST_CASE(template87);
TEST_CASE(template88); // #6183
TEST_CASE(template89); // #8917
TEST_CASE(template90); // crash
TEST_CASE(template91);
TEST_CASE(template92);
TEST_CASE(template93); // crash
TEST_CASE(template94); // #8927 crash
TEST_CASE(template95); // #7417
TEST_CASE(template96); // #7854
TEST_CASE(template97);
TEST_CASE(template98); // #8959
TEST_CASE(template99); // #8960
TEST_CASE(template100); // #8967
TEST_CASE(template101); // #8968
TEST_CASE(template102); // #9005
TEST_CASE(template103);
TEST_CASE(template104); // #9021
TEST_CASE(template105); // #9076
TEST_CASE(template106);
TEST_CASE(template107); // #8663
TEST_CASE(template108); // #9109
TEST_CASE(template109); // #9144
TEST_CASE(template110);
TEST_CASE(template111); // crash
TEST_CASE(template112); // #9146 syntax error
TEST_CASE(template113);
TEST_CASE(template114); // #9155
TEST_CASE(template115); // #9153
TEST_CASE(template116); // #9178
TEST_CASE(template117);
TEST_CASE(template118);
TEST_CASE(template119); // #9186
TEST_CASE(template120);
TEST_CASE(template121); // #9193
TEST_CASE(template122); // #9147
TEST_CASE(template123); // #9183
TEST_CASE(template124); // #9197
TEST_CASE(template125);
TEST_CASE(template126); // #9217
TEST_CASE(template127); // #9225
TEST_CASE(template128); // #9224
TEST_CASE(template129);
TEST_CASE(template130); // #9246
TEST_CASE(template131); // #9249
TEST_CASE(template132); // #9250
TEST_CASE(template133);
TEST_CASE(template134);
TEST_CASE(template135);
TEST_CASE(template136); // #9287
TEST_CASE(template137); // #9288
TEST_CASE(template138);
TEST_CASE(template139);
TEST_CASE(template140);
TEST_CASE(template141); // #9337
TEST_CASE(template142); // #9338
TEST_CASE(template143);
TEST_CASE(template144); // #9046
TEST_CASE(template145); // syntax error
TEST_CASE(template146); // syntax error
TEST_CASE(template147); // syntax error
TEST_CASE(template148); // syntax error
TEST_CASE(template149); // unknown macro
TEST_CASE(template150); // syntax error
TEST_CASE(template151); // crash
TEST_CASE(template152); // #9467
TEST_CASE(template153); // #9483
TEST_CASE(template154); // #9495
TEST_CASE(template155); // #9539
TEST_CASE(template156);
TEST_CASE(template157); // #9854
TEST_CASE(template158); // daca crash
TEST_CASE(template159); // #9886
TEST_CASE(template160);
TEST_CASE(template161);
TEST_CASE(template162);
TEST_CASE(template163); // #9685 syntax error
TEST_CASE(template164); // #9394
TEST_CASE(template165); // #10032 syntax error
TEST_CASE(template166); // #10081 hang
TEST_CASE(template167);
TEST_CASE(template168);
TEST_CASE(template169);
TEST_CASE(template170); // crash
TEST_CASE(template171); // crash
TEST_CASE(template172); // #10258 crash
TEST_CASE(template173); // #10332 crash
TEST_CASE(template174); // #10506 hang
TEST_CASE(template175); // #10908
TEST_CASE(template176); // #11146
TEST_CASE(template177);
TEST_CASE(template_specialization_1); // #7868 - template specialization template struct S> {..};
TEST_CASE(template_specialization_2); // #7868 - template specialization template struct S> {..};
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
TEST_CASE(template_unhandled);
TEST_CASE(template_default_parameter);
TEST_CASE(template_forward_declared_default_parameter);
TEST_CASE(template_default_type);
TEST_CASE(template_typename);
TEST_CASE(template_constructor); // #3152 - template constructor is removed
TEST_CASE(syntax_error_templates_1);
TEST_CASE(template_member_ptr); // Ticket #5786 - crash upon valid code
TEST_CASE(template_namespace_1);
TEST_CASE(template_namespace_2);
TEST_CASE(template_namespace_3);
TEST_CASE(template_namespace_4);
TEST_CASE(template_namespace_5);
TEST_CASE(template_namespace_6);
TEST_CASE(template_namespace_7); // #8768
TEST_CASE(template_namespace_8);
TEST_CASE(template_namespace_9);
TEST_CASE(template_namespace_10);
TEST_CASE(template_namespace_11); // #7145
TEST_CASE(template_pointer_type);
TEST_CASE(template_array_type);
// Test TemplateSimplifier::templateParameters
TEST_CASE(templateParameters);
TEST_CASE(templateNamePosition);
TEST_CASE(findTemplateDeclarationEnd);
TEST_CASE(getTemplateParametersInDeclaration);
TEST_CASE(expandSpecialized1);
TEST_CASE(expandSpecialized2);
TEST_CASE(expandSpecialized3); // #8671
TEST_CASE(expandSpecialized4);
TEST_CASE(expandSpecialized5); // #10494
TEST_CASE(templateAlias1);
TEST_CASE(templateAlias2);
TEST_CASE(templateAlias3); // #8315
TEST_CASE(templateAlias4); // #9070
TEST_CASE(templateAlias5);
// Test TemplateSimplifier::instantiateMatch
TEST_CASE(instantiateMatchTest);
TEST_CASE(templateParameterWithoutName); // #8602 Template default parameter without name yields syntax error
TEST_CASE(templateTypeDeduction1); // #8962
TEST_CASE(templateTypeDeduction2);
TEST_CASE(templateTypeDeduction3);
TEST_CASE(templateTypeDeduction4); // #9983
TEST_CASE(templateTypeDeduction5);
TEST_CASE(simplifyTemplateArgs1);
TEST_CASE(simplifyTemplateArgs2);
TEST_CASE(simplifyTemplateArgs3);
TEST_CASE(template_variadic_1); // #9144
TEST_CASE(template_variadic_2); // #4349
TEST_CASE(template_variadic_3); // #6172
TEST_CASE(template_variable_1);
TEST_CASE(template_variable_2);
TEST_CASE(template_variable_3);
TEST_CASE(template_variable_4);
TEST_CASE(simplifyDecltype);
TEST_CASE(castInExpansion);
TEST_CASE(fold_expression_1);
TEST_CASE(fold_expression_2);
TEST_CASE(fold_expression_3);
TEST_CASE(fold_expression_4);
TEST_CASE(concepts1);
TEST_CASE(requires1);
TEST_CASE(requires2);
TEST_CASE(requires3);
TEST_CASE(requires4);
TEST_CASE(requires5);
TEST_CASE(explicitBool1);
TEST_CASE(explicitBool2);
}
#define tok(...) tok_(__FILE__, __LINE__, __VA_ARGS__)
std::string tok_(const char* file, int line, const char code[], bool debugwarnings = false, cppcheck::Platform::Type type = cppcheck::Platform::Type::Native) {
errout.str("");
const Settings settings1 = settingsBuilder(settings).debugwarnings(debugwarnings).platform(type).build();
Tokenizer tokenizer(&settings1, this);
std::istringstream istr(code);
ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line);
return tokenizer.tokens()->stringifyList(nullptr, true);
}
void template1() {
const char code[] = "template T f(T val) { T a; }\n"
"f(10);";
const char expected[] = "int f ( int val ) ; "
"f ( 10 ) ; "
"int f ( int val ) { int a ; }";
ASSERT_EQUALS(expected, tok(code));
}
void template2() {
const char code[] = "template class Fred { T a; };\n"
"Fred fred;";
const char expected[] = "class Fred ; "
"Fred fred ; "
"class Fred { int a ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template3() {
const char code[] = "template class Fred { T data[sz]; };\n"
"Fred fred;";
const char expected[] = "class Fred ; "
"Fred fred ; "
"class Fred { float data [ 4 ] ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template4() {
const char code[] = "template class Fred { Fred(); };\n"
"Fred fred;";
const char expected[] = "class Fred ; "
"Fred fred ; "
"class Fred { Fred ( ) ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template5() {
const char code[] = "template class Fred { };\n"
"template Fred::Fred() { }\n"
"Fred fred;";
const char expected[] = "class Fred ; "
"Fred fred ; "
"class Fred { } ; "
"Fred :: Fred ( ) { }";
ASSERT_EQUALS(expected, tok(code));
}
void template6() {
const char code[] = "template class Fred { };\n"
"Fred fred1;\n"
"Fred fred2;";
const char expected[] = "class Fred ; "
"Fred fred1 ; "
"Fred fred2 ; "
"class Fred { } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template7() {
// A template class that is not used => no simplification
{
const char code[] = "template \n"
"class ABC\n"
"{\n"
"public:\n"
" typedef ABC m;\n"
"};\n";
const char expected[] = "template < class T > class ABC { public: } ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template class ABC {\n"
"public:\n"
" typedef std::vector type;\n"
"};\n"
"int main() {\n"
" ABC::type v;\n"
" v.push_back(4);\n"
" return 0;\n"
"}\n";
const char wanted[] = "class ABC ; "
"int main ( ) { "
"std :: vector < int > v ; "
"v . push_back ( 4 ) ; "
"return 0 ; "
"} "
"class ABC { public: } ;";
const char current[] = "class ABC ; "
"int main ( ) { "
"ABC :: type v ; "
"v . push_back ( 4 ) ; "
"return 0 ; "
"} "
"class ABC { public: } ;";
TODO_ASSERT_EQUALS(wanted, current, tok(code));
}
{
const char code[] = "template class ABC {\n"
"public:\n"
" typedef std::vector type;\n"
" void f()\n"
" {\n"
" ABC::type v;\n"
" v.push_back(4);\n"
" }\n"
"};\n";
const char expected[] = "template < typename T > class ABC { "
"public: void f ( ) { "
"ABC < int > :: type v ; "
"v . push_back ( 4 ) ; "
"} "
"} ;";
ASSERT_EQUALS(expected, tok(code));
}
}
// Template definitions but no usage => no expansion
void template8() {
const char code[] = "template class A;\n"
"template class B;\n"
"\n"
"typedef A x;\n"
"typedef B y;\n"
"\n"
"template class A {\n"
" void f() {\n"
" B a = B::g();\n"
" T b = 0;\n"
" if (b)\n"
" b = 0;\n"
" }\n"
"};\n"
"\n"
"template inline B h() { return B(); }\n";
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 ; if ( b ) { b = 0 ; } } } ; "
"template < typename T > B < T > h ( ) { return B < T > ( ) ; }", tok(code));
ASSERT_EQUALS("class A { template < typename T > int foo ( T d ) ; } ;", tok("class A{ template int foo(T d);};"));
}
void template9() {
const char code[] = "template < typename T > class A { } ;\n"
"\n"
"void f ( ) {\n"
" A < int > a ;\n"
"}\n"
"\n"
"template < typename T >\n"
"class B {\n"
" void g ( ) {\n"
" A < T > b = A < T > :: h ( ) ;\n"
" }\n"
"} ;\n";
// The expected result..
const char expected[] = "class A ; "
"void f ( ) { A a ; } "
"template < typename T > class B { void g ( ) { A < T > b ; b = A < T > :: h ( ) ; } } ; "
"class A { } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template10() {
const char code[] = "template T * foo()\n"
"{ return new T[ui]; }\n"
"\n"
"void f ( )\n"
"{\n"
" foo<3,int>();\n"
"}\n";
// The expected result..
const char expected[] = "int * foo<3,int> ( ) ; "
"void f ( ) "
"{"
" foo<3,int> ( ) ; "
"} "
"int * foo<3,int> ( ) { return new int [ 3 ] ; }";
ASSERT_EQUALS(expected, tok(code));
}
void template11() {
const char code[] = "template T * foo()\n"
"{ return new T[ui]; }\n"
"\n"
"void f ( )\n"
"{\n"
" char * p = foo<3,char>();\n"
"}\n";
// The expected result..
const char expected[] = "char * foo<3,char> ( ) ; "
"void f ( ) "
"{"
" char * p ; p = foo<3,char> ( ) ; "
"} "
"char * foo<3,char> ( ) { return new char [ 3 ] ; }";
ASSERT_EQUALS(expected, tok(code));
}
void template12() {
const char code[] = "template \n"
"class A : public B\n"
"{ };\n"
"\n"
"void f()\n"
"{\n"
" A<12,12,11> a;\n"
"}\n";
const char expected[] = "class A<12,12,11> ; "
"void f ( ) "
"{"
" A<12,12,11> a ; "
"} "
"class A<12,12,11> : public B < 12 , 12 , 0 > "
"{ } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template13() {
const char code[] = "class BB {};\n"
"\n"
"template \n"
"class AA {\n"
"public:\n"
" static AA create(T* newObject);\n"
" static int size();\n"
"};\n"
"\n"
"class CC { public: CC(AA, int) {} };\n"
"\n"
"class XX {\n"
" AA y;\n"
"public:\n"
" XX();\n"
"};\n"
"\n"
"XX::XX():\n"
" y(AA::create(new CC(AA(), 0)))\n"
" {}\n"
"\n"
"int yy[AA::size()];";
const char expected[] = "class BB { } ; "
"class AA ; "
"class AA ; "
"class CC { public: CC ( AA , int ) { } } ; "
"class XX { "
"AA y ; "
"public: "
"XX ( ) ; "
"} ; "
"XX :: XX ( ) : "
"y ( AA :: create ( new CC ( AA ( ) , 0 ) ) ) "
"{ } "
"int yy [ AA :: size ( ) ] ; "
"class AA { "
"public: "
"static AA create ( BB * newObject ) ; "
"static int size ( ) ; "
"} ; "
"class AA { "
"public: "
"static AA create ( CC * newObject ) ; "
"static int size ( ) ; "
"} ;";
ASSERT_EQUALS(expected, tok(code));
}
void template14() {
const char code[] = "template <> void foo()\n"
"{ x(); }\n"
"\n"
"int main()\n"
"{\n"
"foo();\n"
"}\n";
const char expected[] = "void foo ( ) ; "
"void foo ( ) "
"{ x ( ) ; } "
"int main ( ) "
"{ foo ( ) ; }";
ASSERT_EQUALS(expected, tok(code));
}
void template15() { // recursive templates #3130 etc
const char code[] = "template void a()\n"
"{\n"
" a();\n"
"}\n"
"\n"
"template <> void a<0>()\n"
"{ }\n"
"\n"
"int main()\n"
"{\n"
" a<2>();\n"
" return 0;\n"
"}\n";
// The expected result..
const char expected[] = "void a<0> ( ) ; "
"void a<2> ( ) ; "
"void a<1> ( ) ; "
"void a<0> ( ) { } "
"int main ( ) "
"{ a<2> ( ) ; return 0 ; } "
"void a<2> ( ) { a<1> ( ) ; } "
"void a<1> ( ) { a<0> ( ) ; }";
ASSERT_EQUALS(expected, tok(code));
// #3130
const char code2[] = "template struct vec {\n"
" vec() {}\n"
" vec(const vec& v) {}\n" // <- never used don't instantiate
"};\n"
"\n"
"vec<4> v;";
const char expected2[] = "struct vec<4> ; "
"vec<4> v ; "
"struct vec<4> { "
"vec<4> ( ) { } "
"vec<4> ( const vec < 4 - 1 > & v ) { } "
"} ;";
ASSERT_EQUALS(expected2, tok(code2));
}
void template16() {
const char code[] = "template void a()\n"
"{ }\n"
"\n"
"template void b()\n"
"{ a(); }\n"
"\n"
"int main()\n"
"{\n"
" b<2>();\n"
" return 0;\n"
"}\n";
const char expected[] = "void a<2> ( ) ; "
"void b<2> ( ) ; "
"int main ( ) { b<2> ( ) ; return 0 ; } "
"void b<2> ( ) { a<2> ( ) ; } "
"void a<2> ( ) { }";
ASSERT_EQUALS(expected, tok(code));
}
void template17() {
const char code[] = "template\n"
"class Fred\n"
"{\n"
" template\n"
" static shared_ptr< Fred > CreateFred()\n"
" {\n"
" }\n"
"};\n"
"\n"
"shared_ptr i;\n";
const char expected[] = "template < class T > "
"class Fred "
"{ "
"template < class T > "
"static shared_ptr < Fred < T > > CreateFred ( ) "
"{ "
"} "
"} ; "
"shared_ptr < int > i ;";
ASSERT_EQUALS(expected, tok(code));
}
void template18() {
const char code[] = "template class foo { T a; };\n"
"foo *f;";
const char expected[] = "class foo ; "
"foo * f ; "
"class foo { int a ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template19() {
const char code[] = "template T & foo()\n"
"{ static T temp; return temp; }\n"
"\n"
"void f ( )\n"
"{\n"
" char p = foo();\n"
"}\n";
// The expected result..
const char expected[] = "char & foo ( ) ; "
"void f ( ) "
"{"
" char p ; p = foo ( ) ; "
"} "
"char & foo ( ) { static char temp ; return temp ; }";
ASSERT_EQUALS(expected, tok(code));
}
void template20() {
// Ticket #1788 - the destructor implementation is lost
const char code[] = "template class A { public: ~A(); };\n"
"template A::~A() {}\n"
"A a;\n";
// The expected result..
const char expected[] = "class A ; "
"A a ; "
"class A { public: ~ A ( ) ; } ; "
"A :: ~ A ( ) { }";
ASSERT_EQUALS(expected, tok(code));
}
void template21() {
{
const char code[] = "template struct Fred { T a; };\n"
"Fred fred;";
const char expected[] = "struct Fred ; "
"Fred fred ; "
"struct Fred { int a ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template struct Fred { T data[sz]; };\n"
"Fred fred;";
const char expected[] = "struct Fred ; "
"Fred fred ; "
"struct Fred { float data [ 4 ] ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template struct Fred { Fred(); };\n"
"Fred fred;";
const char expected[] = "struct Fred ; "
"Fred fred ; "
"struct Fred { Fred ( ) ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template struct Fred { };\n"
"Fred fred1;\n"
"Fred fred2;";
const char expected[] = "struct Fred ; "
"Fred fred1 ; "
"Fred fred2 ; "
"struct Fred { } ;";
ASSERT_EQUALS(expected, tok(code));
}
}
void template22() {
const char code[] = "template struct Fred { T a; };\n"
"Fred fred;";
const char expected[] = "struct Fred ; "
"Fred fred ; "
"struct Fred { std :: string a ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template23() {
const char code[] = "template void foo() { }\n"
"void bar() {\n"
" std::cout << (foo());\n"
"}";
const char expected[] = "void foo ( ) ; "
"void bar ( ) {"
" std :: cout << ( foo ( ) ) ; "
"} "
"void foo ( ) { }";
ASSERT_EQUALS(expected, tok(code));
}
void template24() {
// #2648
const char code[] = "template struct B\n"
"{\n"
" int a[n];\n"
"};\n"
"\n"
"template class bitset: B\n"
"{};\n"
"\n"
"bitset<1> z;";
const char expected[] = "struct B<4> ; "
"class bitset<1> ; "
"bitset<1> z ; "
"class bitset<1> : B<4> { } ; "
"struct B<4> { int a [ 4 ] ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template25() {
const char code[] = "template struct B\n"
"{\n"
" int a[n];\n"
"};\n"
"\n"
"template class bitset: B<((sizeof(int)) ? : 1)>\n"
"{};\n"
"\n"
"bitset<1> z;";
const char expected[] = "struct B<4> ; "
"class bitset<1> ; "
"bitset<1> z ; "
"class bitset<1> : B<4> { } ; "
"struct B<4> { int a [ 4 ] ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
void template26() {
// #2721
const char code[] = "template\n"
"class A { public: T x; };\n"
"\n"
"template\n"
"class C: public A {};\n"
"\n"
"C<2> a;\n";
ASSERT_EQUALS("class A ; class C<2> ; C<2> a ; class C<2> : public A { } ; class A { public: char [ 2 ] x ; } ;", tok(code));
}
void template27() {
// #3350 - template inside macro call
const char code[] = "X(template class Fred);";
ASSERT_THROW(tok(code), InternalError);
}
void template28() {
// #3226 - inner template
const char code[] = "template class Fred {};\n"
"Fred > x;\n";
ASSERT_EQUALS("class Fred ; "
"class Fred> ; "
"Fred> x ; "
"class Fred { } ; "
"class Fred> { } ;", tok(code));
}
void template30() {
// #3529 - template < template < ..
const char code[] = "template class A, class B> void f(){}";
ASSERT_EQUALS("template < template < class > class A , class B > void f ( ) { }", tok(code));
}
void template31() {
// #4010 - template reference type
const char code[] = "template struct A{}; A a;";
ASSERT_EQUALS("struct A ; "
"A a ; "
"struct A { } ;", tok(code));
// #7409 - rvalue
const char code2[] = "template struct A{}; A a;";
ASSERT_EQUALS("struct A ; "
"A a ; "
"struct A { } ;", tok(code2));
}
void template32() {
// #3818 - mismatching template not handled well
const char code[] = "template struct A { };\n"
"\n"
"template \n"
"struct B\n"
"{\n"
" public:\n"
" A < int, Pair, int > a;\n" // mismatching parameters => don't instantiate
"};\n"
"\n"
"B b;\n";
ASSERT_EQUALS("template < class T1 , class T2 , class T3 , class T4 > struct A { } ; "
"struct B ; "
"B b ; "
"struct B { public: A < int , Pair < int , int > , int > a ; } ;", tok(code));
}
void template33() {
{
// #3818 - inner templates in template instantiation not handled well
const char code[] = "template struct A { };\n"
"template struct B { };\n"
"template struct C { A > > ab; };\n"
"C c;";
ASSERT_EQUALS("struct A>> ; "
"struct B> ; "
"struct C ; "
"C c ; "
"struct C { A>> ab ; } ; "
"struct B> { } ; " // <- redundant.. but nevermind
"struct A>> { } ;", tok(code));
}
{
// #4544
const char code[] = "struct A { };\n"
"template struct B { };\n"
"template struct C { };\n"
"C< B > c;";
ASSERT_EQUALS("struct A { } ; "
"template < class T > struct B { } ; " // <- redundant.. but nevermind
"struct C> ; "
"C> c ; "
"struct C> { } ;",
tok(code));
}
}
void template34() {
// #3706 - namespace => hang
const char code[] = "namespace abc {\n"
"template struct X { void f(X &x) {} };\n"
"}\n"
"template <> int X::Y(0);";
tok(code);
}
void template35() { // #4074 - "A<'x'> a;" is not recognized as template instantiation
const char code[] = "template class A {};\n"
"A <'x'> a;";
ASSERT_EQUALS("class A<'x'> ; "
"A<'x'> a ; "
"class A<'x'> { } ;", tok(code));
}
void template36() { // #4310 - Passing unknown template instantiation as template argument
const char code[] = "template struct X { T t; };\n"
"template struct Y { Foo < X< Bar > > _foo; };\n" // <- Bar is unknown
"Y bar;";
ASSERT_EQUALS("struct X> ; "
"struct Y ; "
"Y bar ; "
"struct Y { Foo < X> > _foo ; } ; "
"struct X> { Bar < int > t ; } ;",
tok(code));
}
void template37() { // #4544 - A a;
{
const char code[] = "class A { };\n"
"template class B {};\n"
"B b1;\n"
"B b2;";
ASSERT_EQUALS("class A { } ; class B ; B b1 ; B b2 ; class B { } ;",
tok(code));
}
{
const char code[] = "struct A { };\n"
"template class B {};\n"
"B b1;\n"
"B b2;";
ASSERT_EQUALS("struct A { } ; class B ; B b1 ; B b2 ; class B { } ;",
tok(code));
}
{
const char code[] = "enum A { };\n"
"template class B {};\n"
"B b1;\n"
"B b2;";
ASSERT_EQUALS("enum A { } ; class B ; B b1 ; B b2 ; class B { } ;",
tok(code));
}
}
void template_unhandled() {
// An unhandled template usage should not be simplified..
ASSERT_EQUALS("x < int > ( ) ;", tok("x();"));
}
void template38() { // #4832 - Crash on C++11 right angle brackets
const char code[] = "template class A {\n"
" T mT;\n"
"public:\n"
" void foo() {}\n"
"};\n"
"\n"
"int main() {\n"
" A> gna1;\n"
" A gna2;\n"
"}\n";
const char expected[] = "class A ; "
"class A> ; "
"int main ( ) { "
"A> gna1 ; "
"A gna2 ; "
"} "
"class A { "
"BLA mT ; "
"public: "
"void foo ( ) { } "
"} ; "
"class A> { "
"A mT ; "
"public: "
"void foo ( ) { } "
"} ;";
ASSERT_EQUALS(expected, tok(code));
}
void template39() { // #4742 - Used to freeze in 1.60
const char code[] = "template