This fixes simplifyUsing to remove 'typename' and 'template' from type aliases of the form: using T3 = typename T1::template T3<T2>; This lets the template simplifier instantiate the type alias which will then remove the using type alias. The crash will still happen if there is no instantiation because the type alias will not be removed. The type alias is what cppcheck is crashing on after the template simplifier and that still needs fixing.
3575 lines
168 KiB
C++
3575 lines
168 KiB
C++
/*
|
|
* Cppcheck - A tool for static C/C++ code analysis
|
|
* Copyright (C) 2007-2019 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include "config.h"
|
|
#include "platform.h"
|
|
#include "settings.h"
|
|
#include "templatesimplifier.h"
|
|
#include "testsuite.h"
|
|
#include "token.h"
|
|
#include "tokenize.h"
|
|
|
|
struct InternalError;
|
|
|
|
|
|
class TestSimplifyTemplate : public TestFixture {
|
|
public:
|
|
TestSimplifyTemplate() : TestFixture("TestSimplifyTemplate") {
|
|
}
|
|
|
|
private:
|
|
Settings settings;
|
|
|
|
void run() OVERRIDE {
|
|
settings.addEnabled("portability");
|
|
|
|
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<class B> 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(template51); // #6172 - crash upon valid code
|
|
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(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
|
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
|
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 TemplateSimplifier::templateParameters
|
|
TEST_CASE(templateParameters);
|
|
|
|
TEST_CASE(templateNamePosition);
|
|
|
|
TEST_CASE(expandSpecialized1);
|
|
TEST_CASE(expandSpecialized2);
|
|
TEST_CASE(expandSpecialized3); // #8671
|
|
TEST_CASE(expandSpecialized4);
|
|
|
|
TEST_CASE(templateAlias1);
|
|
TEST_CASE(templateAlias2);
|
|
TEST_CASE(templateAlias3); // #8315
|
|
TEST_CASE(templateAlias4); // #9070
|
|
|
|
// Test TemplateSimplifier::instantiateMatch
|
|
TEST_CASE(instantiateMatch);
|
|
TEST_CASE(templateParameterWithoutName); // #8602 Template default parameter without name yields syntax error
|
|
|
|
TEST_CASE(templateTypeDeduction1); // #8962
|
|
TEST_CASE(templateTypeDeduction2);
|
|
|
|
TEST_CASE(simplifyTemplateArgs);
|
|
}
|
|
|
|
std::string tok(const char code[], bool debugwarnings = false, Settings::PlatformType type = Settings::Native) {
|
|
errout.str("");
|
|
|
|
settings.debugwarnings = debugwarnings;
|
|
settings.platform(type);
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
tokenizer.tokenize(istr, "test.cpp");
|
|
|
|
return tokenizer.tokens()->stringifyList(0, true);
|
|
}
|
|
|
|
void template1() {
|
|
const char code[] = "template <class T> T f(T val) { T a; }\n"
|
|
"f<int>(10);";
|
|
|
|
const char expected[] = "int f<int> ( int val ) ; "
|
|
"f<int> ( 10 ) ; "
|
|
"int f<int> ( int val ) { int a ; }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template2() {
|
|
const char code[] = "template <class T> class Fred { T a; };\n"
|
|
"Fred<int> fred;";
|
|
|
|
const char expected[] = "class Fred<int> ; "
|
|
"Fred<int> fred ; "
|
|
"class Fred<int> { int a ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template3() {
|
|
const char code[] = "template <class T, int sz> class Fred { T data[sz]; };\n"
|
|
"Fred<float,4> fred;";
|
|
|
|
const char expected[] = "class Fred<float,4> ; "
|
|
"Fred<float,4> fred ; "
|
|
"class Fred<float,4> { float data [ 4 ] ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template4() {
|
|
const char code[] = "template <class T> class Fred { Fred(); };\n"
|
|
"Fred<float> fred;";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"Fred<float> fred ; "
|
|
"class Fred<float> { Fred<float> ( ) ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template5() {
|
|
const char code[] = "template <class T> class Fred { };\n"
|
|
"template <class T> Fred<T>::Fred() { }\n"
|
|
"Fred<float> fred;";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"Fred<float> fred ; "
|
|
"class Fred<float> { } ; "
|
|
"Fred<float> :: Fred<float> ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template6() {
|
|
const char code[] = "template <class T> class Fred { };\n"
|
|
"Fred<float> fred1;\n"
|
|
"Fred<float> fred2;";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"Fred<float> fred1 ; "
|
|
"Fred<float> fred2 ; "
|
|
"class Fred<float> { } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template7() {
|
|
// A template class that is not used => no simplification
|
|
{
|
|
const char code[] = "template <class T>\n"
|
|
"class ABC\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" typedef ABC<T> m;\n"
|
|
"};\n";
|
|
|
|
const char expected[] = "template < class T > class ABC { public: } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <typename T> class ABC {\n"
|
|
"public:\n"
|
|
" typedef std::vector<T> type;\n"
|
|
"};\n"
|
|
"int main() {\n"
|
|
" ABC<int>::type v;\n"
|
|
" v.push_back(4);\n"
|
|
" return 0;\n"
|
|
"}\n";
|
|
|
|
const char wanted[] = "class ABC<int> ; "
|
|
"int main ( ) { "
|
|
"std :: vector < int > v ; "
|
|
"v . push_back ( 4 ) ; "
|
|
"return 0 ; "
|
|
"} "
|
|
"class ABC<int> { public: } ;";
|
|
|
|
const char current[] = "class ABC<int> ; "
|
|
"int main ( ) { "
|
|
"ABC<int> :: type v ; "
|
|
"v . push_back ( 4 ) ; "
|
|
"return 0 ; "
|
|
"} "
|
|
"class ABC<int> { public: } ;";
|
|
|
|
TODO_ASSERT_EQUALS(wanted, current, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <typename T> class ABC {\n"
|
|
"public:\n"
|
|
" typedef std::vector<T> type;\n"
|
|
" void f()\n"
|
|
" {\n"
|
|
" ABC<int>::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<typename T> class A;\n"
|
|
"template<typename T> class B;\n"
|
|
"\n"
|
|
"typedef A<int> x;\n"
|
|
"typedef B<int> y;\n"
|
|
"\n"
|
|
"template<typename T> class A {\n"
|
|
" void f() {\n"
|
|
" B<T> a = B<T>::g();\n"
|
|
" T b = 0;\n"
|
|
" if (b)\n"
|
|
" b = 0;\n"
|
|
" }\n"
|
|
"};\n"
|
|
"\n"
|
|
"template<typename T> inline B<T> h() { return B<T>(); }\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<typename T> 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<int> ; "
|
|
"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));
|
|
}
|
|
|
|
void template10() {
|
|
const char code[] = "template <int ui, typename T> 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 <int ui, typename T> 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 <int x, int y, int z>\n"
|
|
"class A : public B<x, y, (x - y) ? ((y < z) ? 1 : -1) : 0>\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 <class T>\n"
|
|
"class AA {\n"
|
|
"public:\n"
|
|
" static AA<T> create(T* newObject);\n"
|
|
" static int size();\n"
|
|
"};\n"
|
|
"\n"
|
|
"class CC { public: CC(AA<BB>, int) {} };\n"
|
|
"\n"
|
|
"class XX {\n"
|
|
" AA<CC> y;\n"
|
|
"public:\n"
|
|
" XX();\n"
|
|
"};\n"
|
|
"\n"
|
|
"XX::XX():\n"
|
|
" y(AA<CC>::create(new CC(AA<BB>(), 0)))\n"
|
|
" {}\n"
|
|
"\n"
|
|
"int yy[AA<CC>::size()];";
|
|
const char expected[] = "class BB { } ; "
|
|
"class AA<BB> ; "
|
|
"class AA<CC> ; "
|
|
"class CC { public: CC ( AA<BB> , int ) { } } ; "
|
|
"class XX { "
|
|
"AA<CC> y ; "
|
|
"public: "
|
|
"XX ( ) ; "
|
|
"} ; "
|
|
"XX :: XX ( ) : "
|
|
"y ( AA<CC> :: create ( new CC ( AA<BB> ( ) , 0 ) ) ) "
|
|
"{ } "
|
|
"int yy [ AA<CC> :: size ( ) ] ; "
|
|
"class AA<BB> { "
|
|
"public: "
|
|
"static AA<BB> create ( BB * newObject ) ; "
|
|
"static int size ( ) ; "
|
|
"} ; "
|
|
"class AA<CC> { "
|
|
"public: "
|
|
"static AA<CC> create ( CC * newObject ) ; "
|
|
"static int size ( ) ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template14() {
|
|
const char code[] = "template <> void foo<int *>()\n"
|
|
"{ x(); }\n"
|
|
"\n"
|
|
"int main()\n"
|
|
"{\n"
|
|
"foo<int*>();\n"
|
|
"}\n";
|
|
const char expected[] = "void foo<int*> ( ) ; "
|
|
"void foo<int*> ( ) "
|
|
"{ x ( ) ; } "
|
|
"int main ( ) "
|
|
"{ foo<int*> ( ) ; }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template15() { // recursive templates #3130 etc
|
|
const char code[] = "template <unsigned int i> void a()\n"
|
|
"{\n"
|
|
" a<i-1>();\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 <int n> struct vec {\n"
|
|
" vec() {}\n"
|
|
" vec(const vec<n-1>& 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 <unsigned int i> void a()\n"
|
|
"{ }\n"
|
|
"\n"
|
|
"template <unsigned int i> void b()\n"
|
|
"{ a<i>(); }\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<class T>\n"
|
|
"class Fred\n"
|
|
"{\n"
|
|
" template<class T>\n"
|
|
" static shared_ptr< Fred<T> > CreateFred()\n"
|
|
" {\n"
|
|
" }\n"
|
|
"};\n"
|
|
"\n"
|
|
"shared_ptr<int> 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 T> class foo { T a; };\n"
|
|
"foo<int> *f;";
|
|
|
|
const char expected[] = "class foo<int> ; "
|
|
"foo<int> * f ; "
|
|
"class foo<int> { int a ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template19() {
|
|
const char code[] = "template <typename T> T & foo()\n"
|
|
"{ static T temp; return temp; }\n"
|
|
"\n"
|
|
"void f ( )\n"
|
|
"{\n"
|
|
" char p = foo<char>();\n"
|
|
"}\n";
|
|
|
|
// The expected result..
|
|
const char expected[] = "char & foo<char> ( ) ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" char p ; p = foo<char> ( ) ; "
|
|
"} "
|
|
"char & foo<char> ( ) { static char temp ; return temp ; }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template20() {
|
|
// Ticket #1788 - the destructor implementation is lost
|
|
const char code[] = "template <class T> class A { public: ~A(); };\n"
|
|
"template <class T> A<T>::~A() {}\n"
|
|
"A<int> a;\n";
|
|
|
|
// The expected result..
|
|
const char expected[] = "class A<int> ; "
|
|
"A<int> a ; "
|
|
"class A<int> { public: ~ A<int> ( ) ; } ; "
|
|
"A<int> :: ~ A<int> ( ) { }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template21() {
|
|
{
|
|
const char code[] = "template <class T> struct Fred { T a; };\n"
|
|
"Fred<int> fred;";
|
|
|
|
const char expected[] = "struct Fred<int> ; "
|
|
"Fred<int> fred ; "
|
|
"struct Fred<int> { int a ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <class T, int sz> struct Fred { T data[sz]; };\n"
|
|
"Fred<float,4> fred;";
|
|
|
|
const char expected[] = "struct Fred<float,4> ; "
|
|
"Fred<float,4> fred ; "
|
|
"struct Fred<float,4> { float data [ 4 ] ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <class T> struct Fred { Fred(); };\n"
|
|
"Fred<float> fred;";
|
|
|
|
const char expected[] = "struct Fred<float> ; "
|
|
"Fred<float> fred ; "
|
|
"struct Fred<float> { Fred<float> ( ) ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "template <class T> struct Fred { };\n"
|
|
"Fred<float> fred1;\n"
|
|
"Fred<float> fred2;";
|
|
|
|
const char expected[] = "struct Fred<float> ; "
|
|
"Fred<float> fred1 ; "
|
|
"Fred<float> fred2 ; "
|
|
"struct Fred<float> { } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
}
|
|
|
|
void template22() {
|
|
const char code[] = "template <class T> struct Fred { T a; };\n"
|
|
"Fred<std::string> fred;";
|
|
|
|
const char expected[] = "struct Fred<std::string> ; "
|
|
"Fred<std::string> fred ; "
|
|
"struct Fred<std::string> { std :: string a ; } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template23() {
|
|
const char code[] = "template <class T> void foo() { }\n"
|
|
"void bar() {\n"
|
|
" std::cout << (foo<double>());\n"
|
|
"}";
|
|
|
|
const char expected[] = "void foo<double> ( ) ; "
|
|
"void bar ( ) {"
|
|
" std :: cout << ( foo<double> ( ) ) ; "
|
|
"} "
|
|
"void foo<double> ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template24() {
|
|
// #2648
|
|
const char code[] = "template<int n> struct B\n"
|
|
"{\n"
|
|
" int a[n];\n"
|
|
"};\n"
|
|
"\n"
|
|
"template<int x> class bitset: B<sizeof(int)>\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<int n> struct B\n"
|
|
"{\n"
|
|
" int a[n];\n"
|
|
"};\n"
|
|
"\n"
|
|
"template<int x> 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<class T>\n"
|
|
"class A { public: T x; };\n"
|
|
"\n"
|
|
"template<class M>\n"
|
|
"class C: public A<char[M]> {};\n"
|
|
"\n"
|
|
"C<2> a;\n";
|
|
// TODO: expand A also
|
|
ASSERT_EQUALS("template < class T > class A { public: T x ; } ; class C<2> ; 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_THROW(tok(code), InternalError);
|
|
}
|
|
|
|
void template28() {
|
|
// #3226 - inner template
|
|
const char code[] = "template<class A, class B> class Fred {};\n"
|
|
"Fred<int,Fred<int,int> > x;\n";
|
|
ASSERT_EQUALS("class Fred<int,int> ; "
|
|
"class Fred<int,Fred<int,int>> ; "
|
|
"Fred<int,Fred<int,int>> x ; "
|
|
"class Fred<int,int> { } ; "
|
|
"class Fred<int,Fred<int,int>> { } ;", tok(code));
|
|
}
|
|
|
|
void template30() {
|
|
// #3529 - template < template < ..
|
|
const char code[] = "template<template<class> 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<class T> struct A{}; A<int&> a;";
|
|
ASSERT_EQUALS("struct A<int&> ; "
|
|
"A<int&> a ; "
|
|
"struct A<int&> { } ;", tok(code));
|
|
|
|
// #7409 - rvalue
|
|
const char code2[] = "template<class T> struct A{}; A<int&&> a;";
|
|
ASSERT_EQUALS("struct A<int&&> ; "
|
|
"A<int&&> a ; "
|
|
"struct A<int&&> { } ;", tok(code2));
|
|
}
|
|
|
|
void template32() {
|
|
// #3818 - mismatching template not handled well
|
|
const char code[] = "template <class T1, class T2, class T3, class T4 > struct A { };\n"
|
|
"\n"
|
|
"template <class T>\n"
|
|
"struct B\n"
|
|
"{\n"
|
|
" public:\n"
|
|
" A < int, Pair<T, int>, int > a;\n" // mismatching parameters => don't instantiate
|
|
"};\n"
|
|
"\n"
|
|
"B<int> b;\n";
|
|
ASSERT_EQUALS("template < class T1 , class T2 , class T3 , class T4 > struct A { } ; "
|
|
"struct B<int> ; "
|
|
"B<int> b ; "
|
|
"struct B<int> { 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<class T> struct A { };\n"
|
|
"template<class T> struct B { };\n"
|
|
"template<class T> struct C { A<B<X<T> > > ab; };\n"
|
|
"C<int> c;";
|
|
ASSERT_EQUALS("struct A<B<X<int>>> ; "
|
|
"struct B<X<int>> ; "
|
|
"struct C<int> ; "
|
|
"C<int> c ; "
|
|
"struct C<int> { A<B<X<int>>> ab ; } ; "
|
|
"struct B<X<int>> { } ; " // <- redundant.. but nevermind
|
|
"struct A<B<X<int>>> { } ;", tok(code));
|
|
}
|
|
|
|
{
|
|
// #4544
|
|
const char code[] = "struct A { };\n"
|
|
"template<class T> struct B { };\n"
|
|
"template<class T> struct C { };\n"
|
|
"C< B<A> > c;";
|
|
ASSERT_EQUALS("struct A { } ; "
|
|
"template < class T > struct B { } ; " // <- redundant.. but nevermind
|
|
"struct C<B<A>> ; "
|
|
"C<B<A>> c ; "
|
|
"struct C<B<A>> { } ;",
|
|
tok(code));
|
|
}
|
|
}
|
|
|
|
void template34() {
|
|
// #3706 - namespace => hang
|
|
const char code[] = "namespace abc {\n"
|
|
"template <typename T> struct X { void f(X<T> &x) {} };\n"
|
|
"}\n"
|
|
"template <> int X<int>::Y(0);";
|
|
tok(code);
|
|
}
|
|
|
|
void template35() { // #4074 - "A<'x'> a;" is not recognized as template instantiation
|
|
const char code[] = "template <char c> 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 <class T> struct X { T t; };\n"
|
|
"template <class C> struct Y { Foo < X< Bar<C> > > _foo; };\n" // <- Bar is unknown
|
|
"Y<int> bar;";
|
|
ASSERT_EQUALS("struct X<Bar<int>> ; "
|
|
"struct Y<int> ; "
|
|
"Y<int> bar ; "
|
|
"struct Y<int> { Foo < X<Bar<int>> > _foo ; } ; "
|
|
"struct X<Bar<int>> { Bar < int > t ; } ;",
|
|
tok(code));
|
|
}
|
|
|
|
void template37() { // #4544 - A<class B> a;
|
|
{
|
|
const char code[] = "class A { };\n"
|
|
"template<class T> class B {};\n"
|
|
"B<class A> b1;\n"
|
|
"B<A> b2;";
|
|
ASSERT_EQUALS("class A { } ; class B<A> ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
|
|
tok(code));
|
|
}
|
|
{
|
|
const char code[] = "struct A { };\n"
|
|
"template<class T> class B {};\n"
|
|
"B<struct A> b1;\n"
|
|
"B<A> b2;";
|
|
ASSERT_EQUALS("struct A { } ; class B<A> ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
|
|
tok(code));
|
|
}
|
|
{
|
|
const char code[] = "enum A { };\n"
|
|
"template<class T> class B {};\n"
|
|
"B<enum A> b1;\n"
|
|
"B<A> b2;";
|
|
ASSERT_EQUALS("enum A { } ; class B<A> ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
|
|
tok(code));
|
|
}
|
|
}
|
|
|
|
void template_unhandled() {
|
|
// An unhandled template usage should be simplified..
|
|
ASSERT_EQUALS("x<int> ( ) ;", tok("x<int>();"));
|
|
}
|
|
|
|
void template38() { // #4832 - Crash on C++11 right angle brackets
|
|
const char code[] = "template <class T> class A {\n"
|
|
" T mT;\n"
|
|
"public:\n"
|
|
" void foo() {}\n"
|
|
"};\n"
|
|
"\n"
|
|
"int main() {\n"
|
|
" A<A<BLA>> gna1;\n"
|
|
" A<BLA> gna2;\n"
|
|
"}\n";
|
|
const char expected[] = "class A<A<BLA>> ; "
|
|
"class A<BLA> ; "
|
|
"int main ( ) { "
|
|
"A<A<BLA>> gna1 ; "
|
|
"A<BLA> gna2 ; "
|
|
"} "
|
|
"class A<A<BLA>> { "
|
|
"A<BLA> mT ; "
|
|
"public: "
|
|
"void foo ( ) { } "
|
|
"} ; "
|
|
"class A<BLA> { "
|
|
"BLA mT ; "
|
|
"public: "
|
|
"void foo ( ) { } "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template39() { // #4742 - Used to freeze in 1.60
|
|
const char code[] = "template<typename T> struct vector {"
|
|
" operator T() const;"
|
|
"};"
|
|
"void f() {"
|
|
" vector<vector<int>> v;"
|
|
" const vector<int> vi = static_cast<vector<int>>(v);"
|
|
"}";
|
|
tok(code);
|
|
}
|
|
|
|
void template40() { // #5055 - false negatives when there is template specialization outside struct
|
|
const char code[] = "struct A {"
|
|
" template<typename T> struct X { T t; };"
|
|
"};"
|
|
"template<> struct A::X<int> { int *t; };";
|
|
ASSERT_EQUALS("struct A { struct X<int> ; } ; struct A :: X<int> { int t ; } ;", tok(code));
|
|
}
|
|
|
|
void template41() { // #4710 - const in template instantiation not handled perfectly
|
|
const char code1[] = "template<class T> struct X { };\n"
|
|
"void f(const X<int> x) { }";
|
|
ASSERT_EQUALS("struct X<int> ; "
|
|
"void f ( const X<int> x ) { } "
|
|
"struct X<int> { } ;", tok(code1));
|
|
|
|
const char code2[] = "template<class T> T f(T t) { return t; }\n"
|
|
"int x() { return f<int>(123); }";
|
|
ASSERT_EQUALS("int f<int> ( int t ) ; "
|
|
"int x ( ) { return f<int> ( 123 ) ; } "
|
|
"int f<int> ( int t ) { return t ; }", tok(code2));
|
|
}
|
|
|
|
void template42() { // #4878 cppcheck aborts in ext-blocks.cpp (clang testcode)
|
|
const char code[] = "template<typename ...Args>\n"
|
|
"int f0(Args ...args) {\n"
|
|
" return ^ {\n"
|
|
" return sizeof...(Args);\n"
|
|
" }() + ^ {\n"
|
|
" return sizeof...(args);\n"
|
|
" }();\n"
|
|
"}";
|
|
ASSERT_THROW(tok(code), InternalError);
|
|
}
|
|
|
|
void template43() { // #5097 - Assert due to '>>' in 'B<A<C>>' not being treated as end of template instantiation
|
|
const char code[] = "template <typename T> struct E { typedef int Int; };\n"
|
|
"template <typename T> struct C { };\n"
|
|
"template <typename T> struct D { static int f() { return C<T>::f(); } };\n"
|
|
"template <typename T> inline int f2() { return D<T>::f(); }\n"
|
|
"template <typename T> int f1 (int x, T *) { int id = f2<T>(); return id; }\n"
|
|
"template <typename T> struct B { void f3(B<T> & other) { } };\n"
|
|
"struct A { };\n"
|
|
"template <> struct C<B<A>> {\n"
|
|
" static int f() { return f1<B<A>>(0, reinterpret_cast<B<A>*>(E<void*>::Int(-1))); }\n"
|
|
"};\n"
|
|
"int main(void) {\n"
|
|
" C<A> ca;\n"
|
|
" return 0;\n"
|
|
"}";
|
|
const char expected[] = "struct E<void*> ; "
|
|
"struct C<A> ; "
|
|
"struct D<B<A>> ; "
|
|
"int f2<B<A>> ( ) ; "
|
|
"int f1<B<A>> ( int x , B<A> * ) ; "
|
|
"struct B<A> ; "
|
|
"struct A { } ; "
|
|
"struct C<B<A>> { "
|
|
"static int f ( ) { "
|
|
"return f1<B<A>> ( 0 , reinterpret_cast < B<A> * > ( E<void*> :: Int ( -1 ) ) ) ; "
|
|
"} "
|
|
"} ; "
|
|
"int main ( ) { "
|
|
"C<A> ca ; "
|
|
"return 0 ; "
|
|
"} "
|
|
"struct B<A> { "
|
|
"void f3 ( B<A> & other ) { } "
|
|
"} ; "
|
|
"int f1<B<A>> ( int x , B<A> * ) { "
|
|
"int id ; id = f2<B<A>> ( ) ; "
|
|
"return id ; "
|
|
"} "
|
|
"int f2<B<A>> ( ) { "
|
|
"return D<B<A>> :: f ( ) ; "
|
|
"} "
|
|
"struct D<B<A>> { "
|
|
"static int f ( ) { "
|
|
"return C<B<A>> :: f ( ) ; "
|
|
"} "
|
|
"} ; "
|
|
"struct C<A> { } ; struct E<void*> { "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template44() { // #5297
|
|
const char code[] = "template<class T> struct StackContainer {"
|
|
" void foo(int i) {"
|
|
" if (0 >= 1 && i<0) {}"
|
|
" }"
|
|
"};"
|
|
"template<class T> class ZContainer : public StackContainer<T> {};"
|
|
"struct FGSTensor {};"
|
|
"class FoldedZContainer : public ZContainer<FGSTensor> {};";
|
|
const char expected[] = "struct StackContainer<FGSTensor> ; "
|
|
"class ZContainer<FGSTensor> ; "
|
|
"struct FGSTensor { } ; "
|
|
"class FoldedZContainer : public ZContainer<FGSTensor> { } ; "
|
|
"class ZContainer<FGSTensor> : public StackContainer<FGSTensor> { } ; "
|
|
"struct StackContainer<FGSTensor> { "
|
|
"void foo ( int i ) { "
|
|
"if ( 0 >= 1 && i < 0 ) { } "
|
|
"} "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template45() { // #5814
|
|
const char code[] = "namespace Constants { const int fourtytwo = 42; } "
|
|
"template <class T, int U> struct TypeMath { "
|
|
" static const int mult = sizeof(T) * U; "
|
|
"}; "
|
|
"template <class T> struct FOO { "
|
|
" enum { value = TypeMath<T, Constants::fourtytwo>::mult }; "
|
|
"}; "
|
|
"FOO<int> foo;";
|
|
const char expected[] = "namespace Constants { const int fourtytwo = 42 ; } "
|
|
"struct TypeMath<int,Constants::fourtytwo> ; "
|
|
"struct FOO<int> ; "
|
|
"FOO<int> foo ; "
|
|
"struct FOO<int> { "
|
|
"enum Anonymous0 { value = TypeMath<int,Constants::fourtytwo> :: mult } ; "
|
|
"} ; "
|
|
"struct TypeMath<int,Constants::fourtytwo> { "
|
|
"static const int mult = sizeof ( int ) * Constants :: fourtytwo ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code, true));
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template46() { // #5816
|
|
tok("template<class T, class U> struct A { static const int value = 0; }; "
|
|
"template <class T> struct B { "
|
|
" enum { value = A<typename T::type, int>::value }; "
|
|
"};");
|
|
ASSERT_EQUALS("", errout.str());
|
|
tok("template <class T, class U> struct A {}; "
|
|
"enum { e = sizeof(A<int, int>) }; "
|
|
"template <class T, class U> struct B {};");
|
|
ASSERT_EQUALS("", errout.str());
|
|
tok("template<class T, class U> struct A { static const int value = 0; }; "
|
|
"template<class T> struct B { typedef int type; }; "
|
|
"template <class T> struct C { "
|
|
" enum { value = A<typename B<T>::type, int>::value }; "
|
|
"};");
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template47() { // #6023
|
|
tok("template <typename T1, typename T2 = T3<T1> > class C1 {}; "
|
|
"class C2 : public C1<C2> {};");
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template48() { // #6134
|
|
tok("template <int> int f( { } ); "
|
|
"int foo = f<1>(0);");
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template49() { // #6237
|
|
const char code[] = "template <class T> class Fred { void f(); void g(); };\n"
|
|
"template <class T> void Fred<T>::f() { }\n"
|
|
"template <class T> void Fred<T>::g() { }\n"
|
|
"template void Fred<float>::f();\n"
|
|
"template void Fred<int>::g();\n";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"class Fred<int> ; "
|
|
"class Fred<float> { void f ( ) ; void g ( ) ; } ; "
|
|
"void Fred<float> :: f ( ) { } "
|
|
"void Fred<float> :: g ( ) { } "
|
|
"class Fred<int> { void f ( ) ; void g ( ) ; } ; "
|
|
"void Fred<int> :: f ( ) { } "
|
|
"void Fred<int> :: g ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template50() { // #4272
|
|
const char code[] = "template <class T> class Fred { void f(); };\n"
|
|
"template <class T> void Fred<T>::f() { }\n"
|
|
"template<> void Fred<float>::f() { }\n"
|
|
"template<> void Fred<int>::f() { }\n";
|
|
|
|
const char expected[] = "class Fred<float> ; "
|
|
"class Fred<int> ; "
|
|
"template < > void Fred<float> :: f ( ) { } "
|
|
"template < > void Fred<int> :: f ( ) { } "
|
|
"class Fred<float> { void f ( ) ; } ; "
|
|
"void Fred<float> :: f ( ) { } "
|
|
"class Fred<int> { void f ( ) ; } ; "
|
|
"void Fred<int> :: f ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template51() { // #6172
|
|
tok("template<int N, int ... M> struct A { "
|
|
" static void foo() { "
|
|
" int i = N; "
|
|
" } "
|
|
"}; "
|
|
"void bar() { "
|
|
" A<0>::foo(); "
|
|
"}");
|
|
}
|
|
|
|
void template52() { // #6437
|
|
const char code[] = "template <int value> int sum() { "
|
|
" return value + sum<value/2>(); "
|
|
"} "
|
|
"template<int x, int y> int calculate_value() { "
|
|
" if (x != y) { "
|
|
" return sum<x - y>(); "
|
|
" } else { "
|
|
" return 0; "
|
|
" } "
|
|
"} "
|
|
"int value = calculate_value<1,1>();";
|
|
const char expected[] = "int sum<0> ( ) ; "
|
|
"int calculate_value<1,1> ( ) ; "
|
|
"int value ; value = calculate_value<1,1> ( ) ; "
|
|
"int calculate_value<1,1> ( ) { "
|
|
"if ( 1 != 1 ) { "
|
|
"return sum<0> ( ) ; "
|
|
"} else { "
|
|
"return 0 ; "
|
|
"} "
|
|
"} "
|
|
"int sum<0> ( ) { "
|
|
"return 0 + sum<0> ( ) ; "
|
|
"}";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template53() { // #4335
|
|
const char code[] = "template<int N> struct Factorial { "
|
|
" enum { value = N * Factorial<N - 1>::value }; "
|
|
"};"
|
|
"template <> struct Factorial<0> { "
|
|
" enum { value = 1 }; "
|
|
"};"
|
|
"const int x = Factorial<4>::value;";
|
|
const char expected[] = "struct Factorial<4> ; "
|
|
"struct Factorial<3> ; "
|
|
"struct Factorial<2> ; "
|
|
"struct Factorial<1> ; "
|
|
"struct Factorial<0> { "
|
|
"enum Anonymous1 { value = 1 } ; "
|
|
"} ; "
|
|
"const int x = Factorial<4> :: value ; "
|
|
"struct Factorial<4> { "
|
|
"enum Anonymous0 { value = 4 * Factorial<3> :: value } ; "
|
|
"} ; "
|
|
"struct Factorial<3> { "
|
|
"enum Anonymous0 { value = 3 * Factorial<2> :: value } ; "
|
|
"} ; "
|
|
"struct Factorial<2> { "
|
|
"enum Anonymous0 { value = 2 * Factorial<1> :: value } ; "
|
|
"} ; "
|
|
"struct Factorial<1> { "
|
|
"enum Anonymous0 { value = 1 * Factorial<0> :: value } ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code, true));
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template54() { // #6587
|
|
tok("template<typename _Tp> _Tp* fn(); "
|
|
"template <class T> struct A { "
|
|
" template <class U, class S = decltype(fn<T>())> "
|
|
" struct B { }; "
|
|
"}; "
|
|
"A<int> a;");
|
|
}
|
|
|
|
void template55() { // #6604
|
|
// Avoid constconstconst in macro instantiations
|
|
ASSERT_EQUALS(
|
|
"template < class T > class AtSmartPtr : public ConstCastHelper < AtSmartPtr < const T > , T > { "
|
|
"friend struct ConstCastHelper < AtSmartPtr < const T > , T > ; "
|
|
"AtSmartPtr ( const AtSmartPtr < T > & r ) ; "
|
|
"} ;",
|
|
tok("template<class T> class AtSmartPtr : public ConstCastHelper<AtSmartPtr<const T>, T>\n"
|
|
"{\n"
|
|
" friend struct ConstCastHelper<AtSmartPtr<const T>, T>;\n"
|
|
" AtSmartPtr(const AtSmartPtr<T>& r);\n"
|
|
"};"));
|
|
|
|
// Similar problem can also happen with ...
|
|
ASSERT_EQUALS(
|
|
"struct A<int> ; "
|
|
"struct A<int...> ; "
|
|
"A<int> a ( 0 ) ; "
|
|
"struct A<int> { "
|
|
"A<int> ( int * p ) { ( A<int...> * ) ( p ) ; } "
|
|
"} ; "
|
|
"struct A<int...> { "
|
|
"A<int...> ( int * p ) { "
|
|
"( A<int...> * ) ( p ) ; "
|
|
"} } ;",
|
|
tok("template <typename... T> struct A\n"
|
|
"{\n"
|
|
" A(T* p) {\n"
|
|
" (A<T...>*)(p);\n"
|
|
" }\n"
|
|
"};\n"
|
|
"A<int> a(0);"));
|
|
}
|
|
|
|
void template56() { // #7117
|
|
const char code[] = "template<bool B> struct Foo { "
|
|
" std::array<int, B ? 1 : 2> mfoo; "
|
|
"}; "
|
|
"void foo() { "
|
|
" Foo<true> myFoo; "
|
|
"}";
|
|
const char expected[] = "struct Foo<true> ; "
|
|
"void foo ( ) { "
|
|
"Foo<true> myFoo ; "
|
|
"} struct Foo<true> { "
|
|
"std :: array < int , 1 > mfoo ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code, true));
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template57() { // #7891
|
|
const char code[] = "template<class T> struct Test { Test(T); };\n"
|
|
"Test<unsigned long> test( 0 );";
|
|
const char exp [] = "struct Test<unsignedlong> ; "
|
|
"Test<unsignedlong> test ( 0 ) ; "
|
|
"struct Test<unsignedlong> { Test<unsignedlong> ( unsigned long ) ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template58() { // #6021
|
|
const char code[] = "template <typename A>\n"
|
|
"void TestArithmetic() {\n"
|
|
" x(1 * CheckedNumeric<A>());\n"
|
|
"}\n"
|
|
"void foo() {\n"
|
|
" TestArithmetic<int>();\n"
|
|
"}";
|
|
const char exp[] = "void TestArithmetic<int> ( ) ; "
|
|
"void foo ( ) {"
|
|
" TestArithmetic<int> ( ) ; "
|
|
"} "
|
|
"void TestArithmetic<int> ( ) {"
|
|
" x ( 1 * CheckedNumeric < int > ( ) ) ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template59() { // #8051
|
|
const char code[] = "template<int N>\n"
|
|
"struct Factorial {\n"
|
|
" enum FacHelper { value = N * Factorial<N - 1>::value };\n"
|
|
"};\n"
|
|
"template <>\n"
|
|
"struct Factorial<0> {\n"
|
|
" enum FacHelper { value = 1 };\n"
|
|
"};\n"
|
|
"template<int DiagonalDegree>\n"
|
|
"int diagonalGroupTest() {\n"
|
|
" return Factorial<DiagonalDegree>::value;\n"
|
|
"}\n"
|
|
"int main () {\n"
|
|
" return diagonalGroupTest<4>();\n"
|
|
"}";
|
|
const char exp[] = "struct Factorial<4> ; "
|
|
"struct Factorial<3> ; "
|
|
"struct Factorial<2> ; "
|
|
"struct Factorial<1> ; "
|
|
"struct Factorial<0> { enum FacHelper { value = 1 } ; } ; "
|
|
"int diagonalGroupTest<4> ( ) ; "
|
|
"int main ( ) { return diagonalGroupTest<4> ( ) ; } "
|
|
"int diagonalGroupTest<4> ( ) { return Factorial<4> :: value ; } "
|
|
"struct Factorial<4> { enum FacHelper { value = 4 * Factorial<3> :: value } ; } ; "
|
|
"struct Factorial<3> { enum FacHelper { value = 3 * Factorial<2> :: value } ; } ; "
|
|
"struct Factorial<2> { enum FacHelper { value = 2 * Factorial<1> :: value } ; } ; "
|
|
"struct Factorial<1> { enum FacHelper { value = 1 * Factorial<0> :: value } ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template60() { // Extracted from Clang testfile
|
|
const char code[] = "template <typename T> struct S { typedef int type; };\n"
|
|
"template <typename T> void f() {}\n"
|
|
"template <typename T> void h() { f<typename S<T>::type(0)>(); }\n"
|
|
"\n"
|
|
"void j() { h<int>(); }";
|
|
const char exp[] = "struct S<int> ; "
|
|
"template < typename T > void f ( ) { } " // <- TODO: This template is not expanded
|
|
"void h<int> ( ) ; "
|
|
"void j ( ) { h<int> ( ) ; } "
|
|
"void h<int> ( ) { f < S<int> :: type ( 0 ) > ( ) ; } "
|
|
"struct S<int> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template61() { // hang in daca, code extracted from kodi
|
|
const char code[] = "template <typename T> struct Foo {};\n"
|
|
"template <typename T> struct Bar {\n"
|
|
" void f1(Bar<T> x) {}\n"
|
|
" Foo<Bar<T>> f2() { }\n"
|
|
"};\n"
|
|
"Bar<int> c;";
|
|
const char exp[] = "struct Foo<Bar<int>> ; "
|
|
"struct Bar<int> ; "
|
|
"Bar<int> c ; "
|
|
"struct Bar<int> {"
|
|
" void f1 ( Bar<int> x ) { }"
|
|
" Foo<Bar<int>> f2 ( ) { } "
|
|
"} ; "
|
|
"struct Foo<Bar<int>> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template62() { // #8314
|
|
const char code[] = "template <class T> struct C1 {};\n"
|
|
"template <class T> void f() { x = y ? C1<int>::allocate(1) : 0; }\n"
|
|
"template <class T, unsigned S> class C3 {};\n"
|
|
"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> { } ; "
|
|
"C3<int,6> :: C3<int,6> ( const C3<int,6> & v ) { C1<int*> c1 ; } "
|
|
"struct C1<int*> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template63() { // #8576
|
|
const char code[] = "template<class T> struct TestClass { T m_hi; };"
|
|
"TestClass<std::auto_ptr<v>> objTest3;";
|
|
const char exp[] = "struct TestClass<std::auto_ptr<v>> ; "
|
|
"TestClass<std::auto_ptr<v>> objTest3 ; "
|
|
"struct TestClass<std::auto_ptr<v>> { std :: auto_ptr < v > m_hi ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template64() { // #8683
|
|
const char code[] = "template <typename T>\n"
|
|
"bool foo(){return true;}\n"
|
|
"struct A {\n"
|
|
"template<int n>\n"
|
|
"void t_func()\n"
|
|
"{\n"
|
|
" if( n != 0 || foo<int>());\n"
|
|
"}\n"
|
|
"void t_caller()\n"
|
|
"{\n"
|
|
" t_func<0>();\n"
|
|
" t_func<1>();\n"
|
|
"}\n"
|
|
"};";
|
|
const char exp [] = "bool foo<int> ( ) ; "
|
|
"struct A { "
|
|
"void t_func<0> ( ) ; "
|
|
"void t_func<1> ( ) ; "
|
|
"void t_caller ( ) "
|
|
"{ "
|
|
"t_func<0> ( ) ; "
|
|
"t_func<1> ( ) ; "
|
|
"} "
|
|
"} ; "
|
|
"void A :: t_func<0> ( ) "
|
|
"{ "
|
|
"if ( 0 != 0 || foo<int> ( ) ) { ; } "
|
|
"} "
|
|
"void A :: t_func<1> ( ) "
|
|
"{ "
|
|
"if ( 1 != 0 || foo<int> ( ) ) { ; } "
|
|
"} "
|
|
"bool foo<int> ( ) { return true ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template65() { // #8321 (crash)
|
|
const char code[] = "namespace bpp\n"
|
|
"{\n"
|
|
"template<class N, class E, class DAGraphImpl>\n"
|
|
"class AssociationDAGraphImplObserver :\n"
|
|
" public AssociationGraphImplObserver<N, E, DAGraphImpl>\n"
|
|
"{};\n"
|
|
"template<class N, class E>\n"
|
|
"using AssociationDAGlobalGraphObserver = AssociationDAGraphImplObserver<N, E, DAGlobalGraph>;\n"
|
|
"}\n"
|
|
"using namespace bpp;\n"
|
|
"using namespace std;\n"
|
|
"int main() {\n"
|
|
" AssociationDAGlobalGraphObserver<string,unsigned int> grObs;\n"
|
|
" return 1;\n"
|
|
"}";
|
|
const char exp [] = "namespace bpp "
|
|
"{ "
|
|
"class AssociationDAGraphImplObserver<string,unsignedint,DAGlobalGraph> ; "
|
|
"} "
|
|
"using namespace bpp ; "
|
|
"int main ( ) { "
|
|
"bpp :: AssociationDAGraphImplObserver<string,unsignedint,DAGlobalGraph> grObs ; "
|
|
"return 1 ; "
|
|
"} class bpp :: AssociationDAGraphImplObserver<string,unsignedint,DAGlobalGraph> : "
|
|
"public AssociationGraphImplObserver < std :: string , unsigned int , DAGlobalGraph > "
|
|
"{ } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template66() { // #8725
|
|
const char code[] = "template <class T> struct Fred {\n"
|
|
" const int ** foo();\n"
|
|
"};\n"
|
|
"template <class T> const int ** Fred<T>::foo() { return nullptr; }\n"
|
|
"Fred<int> fred;";
|
|
const char exp [] = "struct Fred<int> ; "
|
|
"Fred<int> fred ; "
|
|
"struct Fred<int> { "
|
|
"const int * * foo ( ) ; "
|
|
"} ; "
|
|
"const int * * Fred<int> :: foo ( ) { return nullptr ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template67() { // ticket #8122
|
|
const char code[] = "template <class T> struct Container {\n"
|
|
" Container();\n"
|
|
" Container(const Container &);\n"
|
|
" Container & operator = (const Container &);\n"
|
|
" ~Container();\n"
|
|
" T* mElements;\n"
|
|
" const Container * c;\n"
|
|
"};\n"
|
|
"template <class T> Container<T>::Container() : mElements(nullptr), c(nullptr) {}\n"
|
|
"template <class T> Container<T>::Container(const Container & x) { nElements = x.nElements; c = x.c; }\n"
|
|
"template <class T> Container<T> & Container<T>::operator = (const Container & x) { mElements = x.mElements; c = x.c; return *this; }\n"
|
|
"template <class T> Container<T>::~Container() {}\n"
|
|
"Container<int> intContainer;";
|
|
|
|
const char expected[] = "struct Container<int> ; "
|
|
"Container<int> intContainer ; "
|
|
"struct Container<int> { "
|
|
"Container<int> ( ) ; "
|
|
"Container<int> ( const Container<int> & ) ; "
|
|
"Container<int> & operator= ( const Container<int> & ) ; "
|
|
"~ Container<int> ( ) ; "
|
|
"int * mElements ; "
|
|
"const Container<int> * c ; "
|
|
"} ; "
|
|
"Container<int> :: Container<int> ( ) : mElements ( nullptr ) , c ( nullptr ) { } "
|
|
"Container<int> :: Container<int> ( const Container<int> & x ) { nElements = x . nElements ; c = x . c ; } "
|
|
"Container<int> & Container<int> :: operator= ( const Container<int> & x ) { mElements = x . mElements ; c = x . c ; return * this ; } "
|
|
"Container<int> :: ~ Container<int> ( ) { }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void template68() {
|
|
const char code[] = "template <class T> union Fred {\n"
|
|
" char dummy[sizeof(T)];\n"
|
|
" T value;\n"
|
|
"};\n"
|
|
"Fred<int> fred;";
|
|
const char exp [] = "union Fred<int> ; "
|
|
"Fred<int> fred ; "
|
|
"union Fred<int> { "
|
|
"char dummy [ sizeof ( int ) ] ; "
|
|
"int value ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template69() { // #8791
|
|
const char code[] = "class Test {\n"
|
|
" int test;\n"
|
|
" template <class T> T lookup() { return test; }\n"
|
|
" int Fun() { return lookup<int>(); }\n"
|
|
"};";
|
|
const char exp [] = "class Test { "
|
|
"int test ; "
|
|
"int lookup<int> ( ) ; "
|
|
"int Fun ( ) { return lookup<int> ( ) ; } "
|
|
"} ; "
|
|
"int Test :: lookup<int> ( ) { return test ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template70() { // #5289
|
|
const char code[] = "template<typename T, typename V, int KeySize = 0> class Bar;\n"
|
|
"template<>\n"
|
|
"class Bar<void, void> {\n"
|
|
"};\n"
|
|
"template<typename K, typename V, int KeySize>\n"
|
|
"class Bar : private Bar<void, void> {\n"
|
|
" void foo() { }\n"
|
|
"};";
|
|
const char exp [] = "template < typename T , typename V , int KeySize = 0 > class Bar ; "
|
|
"class Bar<void,void> { "
|
|
"} ; "
|
|
"template < typename K , typename V , int KeySize = 0 > "
|
|
"class Bar : private Bar<void,void> { "
|
|
"void foo ( ) { } "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template71() { // #8821
|
|
const char code[] = "int f1(int * pInterface, int x) { return 0; }\n"
|
|
"\n"
|
|
"template< class interface_type > class Reference {\n"
|
|
" template< class interface_type > int i();\n"
|
|
" int *pInterface;\n"
|
|
"};\n"
|
|
"\n"
|
|
"template< class interface_type > int Reference< interface_type >::i() {\n"
|
|
" return f1(pInterface, interface_type::static_type());\n"
|
|
"}\n"
|
|
"\n"
|
|
"Reference< class XPropertyList > dostuff();";
|
|
const char exp [] = "int f1 ( int * pInterface , int x ) { return 0 ; } "
|
|
"class Reference<XPropertyList> ; "
|
|
"Reference<XPropertyList> dostuff ( ) ; "
|
|
"class Reference<XPropertyList> { template < class XPropertyList > int i ( ) ; int * pInterface ; } ; "
|
|
"int Reference<XPropertyList> :: i ( ) { return f1 ( pInterface , XPropertyList :: static_type ( ) ) ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template72() {
|
|
const char code[] = "template <typename N, typename P> class Tokenizer;\n"
|
|
"const Tokenizer<Node, Path> *tokenizer() const;\n"
|
|
"template <typename N, typename P>\n"
|
|
"Tokenizer<N, P>::Tokenizer() { }";
|
|
const char exp [] = "template < typename N , typename P > class Tokenizer ; "
|
|
"const Tokenizer < Node , Path > * tokenizer ( ) const ; "
|
|
"template < typename N , typename P > "
|
|
"Tokenizer < N , P > :: Tokenizer ( ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template73() {
|
|
const char code[] = "template<typename T>\n"
|
|
"void keep_range(T& value, const T mini, const T maxi){}\n"
|
|
"template void keep_range<float>(float& v, const float l, const float u);\n"
|
|
"template void keep_range<int>(int& v, const int l, const int u);";
|
|
const char exp[] = "void keep_range<float> ( float & value , const float mini , const float maxi ) ; "
|
|
"void keep_range<int> ( int & value , const int mini , const int maxi ) ; "
|
|
"void keep_range<float> ( float & value , const float mini , const float maxi ) { } "
|
|
"void keep_range<int> ( int & value , const int mini , const int maxi ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template74() {
|
|
const char code[] = "template <class T> class BTlist { };\n"
|
|
"class PushBackStreamBuf {\n"
|
|
"public:\n"
|
|
" void pushBack(const BTlist<int> &vec);\n"
|
|
"};";
|
|
const char exp[] = "class BTlist<int> ; "
|
|
"class PushBackStreamBuf { "
|
|
"public: "
|
|
"void pushBack ( const BTlist<int> & vec ) ; "
|
|
"} ; "
|
|
"class BTlist<int> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template75() {
|
|
const char code[] = "template<typename T>\n"
|
|
"T foo(T& value){ return value; }\n"
|
|
"template std::vector<std::vector<int>> foo<std::vector<std::vector<int>>>(std::vector<std::vector<int>>& v);";
|
|
const char exp[] = "std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) ; "
|
|
"std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) { return value ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template76() {
|
|
const char code[] = "namespace NS {\n"
|
|
" template<typename T> T foo(T& value) { return value; }\n"
|
|
" template std::vector<std::vector<int>> foo<std::vector<std::vector<int>>>(std::vector<std::vector<int>>& v);\n"
|
|
"}\n"
|
|
"std::vector<std::vector<int>> v;\n"
|
|
"v = foo<std::vector<std::vector<int>>>(v);\n";
|
|
const char exp[] = "namespace NS { "
|
|
"std :: vector < std :: vector < int > > foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) ; "
|
|
"} "
|
|
"std :: vector < std :: vector < int > > v ; "
|
|
"v = foo<std::vector<std::vector<int>>> ( v ) ; "
|
|
"std :: vector < std :: vector < int > > NS :: foo<std::vector<std::vector<int>>> ( std :: vector < std :: vector < int > > & value ) { return value ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template77() {
|
|
const char code[] = "template<typename T>\n"
|
|
"struct is_void : std::false_type { };\n"
|
|
"template<>\n"
|
|
"struct is_void<void> : std::true_type { };\n"
|
|
"int main() {\n"
|
|
" std::cout << is_void<char>::value << std::endl;\n"
|
|
" std::cout << is_void<void>::value << std::endl;\n"
|
|
"}";
|
|
const char exp[] = "struct is_void<char> ; "
|
|
"struct is_void<void> : std :: true_type { } ; "
|
|
"int main ( ) { "
|
|
"std :: cout << is_void<char> :: value << std :: endl ; "
|
|
"std :: cout << is_void<void> :: value << std :: endl ; "
|
|
"} "
|
|
"struct is_void<char> : std :: false_type { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template78() {
|
|
const char code[] = "template <typename>\n"
|
|
"struct Base { };\n"
|
|
"struct S : Base <void>::Type { };";
|
|
const char exp[] = "struct Base<void> ; "
|
|
"struct S : Base<void> :: Type { } ; "
|
|
"struct Base<void> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template79() { // #5133
|
|
const char code[] = "class Foo {\n"
|
|
"public:\n"
|
|
" template<typename T> void foo() { bar<T>(); }\n"
|
|
"private:\n"
|
|
" template<typename T> void bar() { bazz(); }\n"
|
|
" void bazz() { }\n"
|
|
"};\n"
|
|
"void some_func() {\n"
|
|
" Foo x;\n"
|
|
" x.foo<int>();\n"
|
|
"}";
|
|
const char exp[] = "class Foo { "
|
|
"public: "
|
|
"void foo<int> ( ) ; "
|
|
"private: "
|
|
"void bar<int> ( ) ; "
|
|
"void bazz ( ) { } "
|
|
"} ; "
|
|
"void some_func ( ) { "
|
|
"Foo x ; "
|
|
"x . foo<int> ( ) ; "
|
|
"} "
|
|
"void Foo :: foo<int> ( ) { bar<int> ( ) ; } "
|
|
"void Foo :: bar<int> ( ) { bazz ( ) ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template80() {
|
|
const char code[] = "class Fred {\n"
|
|
" template <typename T> T foo(T t) const { return t; }\n"
|
|
"};\n"
|
|
"const void * p = Fred::foo<const void *>(nullptr);";
|
|
const char exp[] = "class Fred { "
|
|
"const void * foo<constvoid*> ( const void * t ) const ; "
|
|
"} ; "
|
|
"const void * p ; p = Fred :: foo<constvoid*> ( nullptr ) ; "
|
|
"const void * Fred :: foo<constvoid*> ( const void * t ) const { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template81() {
|
|
const char code[] = "template <typename Type>\n"
|
|
"struct SortWith {\n"
|
|
" SortWith(Type);\n"
|
|
"};\n"
|
|
"template <typename Type>\n"
|
|
"SortWith<Type>::SortWith(Type) {}\n"
|
|
"int main() {\n"
|
|
" SortWith<int>(0);\n"
|
|
"}";
|
|
const char exp[] = "template < typename Type > "
|
|
"struct SortWith { "
|
|
"SortWith ( Type ) ; "
|
|
"} ; "
|
|
"SortWith<int> :: SortWith<int> ( int ) ; "
|
|
"int main ( ) { "
|
|
"SortWith<int> ( 0 ) ; "
|
|
"} "
|
|
"SortWith<int> :: SortWith<int> ( int ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template82() { // 8603
|
|
const char code[] = "typedef int comp;\n"
|
|
"const int f16=16;\n"
|
|
"template<int x>\n"
|
|
"class tvec2 {};\n"
|
|
"template<int x>\n"
|
|
"class tvec3 {};\n"
|
|
"namespace swizzle {\n"
|
|
"template <comp> void swizzle(tvec2<f16> v) { }\n"
|
|
"template <comp x, comp y> void swizzle(tvec3<f16> v) { }\n"
|
|
"}\n"
|
|
"void foo() {\n"
|
|
" using namespace swizzle;\n"
|
|
" tvec2<f16> tt2;\n"
|
|
" swizzle<1>(tt2);\n"
|
|
" tvec3<f16> tt3;\n"
|
|
" swizzle<2,3>(tt3);\n"
|
|
"}";
|
|
const char exp[] = "const int f16 = 16 ; "
|
|
"class tvec2<f16> ; "
|
|
"class tvec3<f16> ; "
|
|
"namespace swizzle { "
|
|
"void swizzle<1> ( tvec2<f16> v ) ; "
|
|
"void swizzle<2,3> ( tvec3<f16> v ) ; "
|
|
"} "
|
|
"void foo ( ) { "
|
|
"using namespace swizzle ; "
|
|
"tvec2<f16> tt2 ; "
|
|
"swizzle :: swizzle<1> ( tt2 ) ; "
|
|
"tvec3<f16> tt3 ; "
|
|
"swizzle :: swizzle<2,3> ( tt3 ) ; "
|
|
"} "
|
|
"void swizzle :: swizzle<2,3> ( tvec3<f16> v ) { } "
|
|
"void swizzle :: swizzle<1> ( tvec2<f16> v ) { } "
|
|
"class tvec3<f16> { } ; "
|
|
"class tvec2<f16> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template83() { // #8867
|
|
const char code[] = "template<typename Task>\n"
|
|
"class MultiConsumer {\n"
|
|
" MultiConsumer();\n"
|
|
"};\n"
|
|
"template<typename Task>\n"
|
|
"MultiConsumer<Task>::MultiConsumer() : sizeBuffer(0) {}\n"
|
|
"MultiReads::MultiReads() {\n"
|
|
" mc = new MultiConsumer<reads_packet>();\n"
|
|
"}";
|
|
const char exp[] = "template < typename Task > " // TODO: this should be expanded
|
|
"class MultiConsumer { "
|
|
"MultiConsumer ( ) ; "
|
|
"} ; "
|
|
"MultiConsumer<reads_packet> :: MultiConsumer<reads_packet> ( ) ; "
|
|
"MultiReads :: MultiReads ( ) { "
|
|
"mc = new MultiConsumer<reads_packet> ( ) ; "
|
|
"} "
|
|
"MultiConsumer<reads_packet> :: MultiConsumer<reads_packet> ( ) : sizeBuffer ( 0 ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template84() { // #8880
|
|
const char code[] = "template <class b, int c, class>\n"
|
|
"auto d() -> typename a<decltype(b{})>::e {\n"
|
|
" d<int, c, int>();\n"
|
|
"}";
|
|
const char exp[] = "auto d<int,c,int> ( ) . a < decltype ( int { } ) > :: e ; "
|
|
"auto d<int,c,int> ( ) . a < decltype ( int { } ) > :: e { "
|
|
"d<int,c,int> ( ) ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template85() { // #8902 - crash
|
|
const char code[] = "template<typename T>\n"
|
|
"struct C\n"
|
|
"{\n"
|
|
" template<typename U, typename std::enable_if<(!std::is_fundamental<U>::value)>::type* = nullptr>\n"
|
|
" void foo();\n"
|
|
"};\n"
|
|
"extern template void C<int>::foo<int, nullptr>();\n"
|
|
"template<typename T>\n"
|
|
"template<typename U, typename std::enable_if<(!std::is_fundamental<U>::value)>::type>\n"
|
|
"void C<T>::foo() {}";
|
|
// @todo the output is very wrong but we are only worried about the crash for now
|
|
tok(code);
|
|
}
|
|
|
|
void template86() { // crash
|
|
const char code[] = "struct S {\n"
|
|
" S();\n"
|
|
"};\n"
|
|
"template <typename T>\n"
|
|
"struct U {\n"
|
|
" static S<T> u;\n"
|
|
"};\n"
|
|
"template <typename T>\n"
|
|
"S<T> U<T>::u;\n"
|
|
"template S<int> U<int>::u;\n"
|
|
"S<int> &i = U<int>::u;";
|
|
tok(code);
|
|
}
|
|
|
|
void template87() {
|
|
const char code[] = "template<typename T>\n"
|
|
"T f1(T t) { return t; }\n"
|
|
"template const char * f1<const char *>();\n"
|
|
"template const char & f1<const char &>();";
|
|
const char exp[] = "const char * f1<constchar*> ( const char * t ) ; "
|
|
"const char & f1<constchar&> ( const char & t ) ; "
|
|
"const char * f1<constchar*> ( const char * t ) { return t ; } "
|
|
"const char & f1<constchar&> ( const char & t ) { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template88() { // #6183.cpp
|
|
const char code[] = "class CTest {\n"
|
|
"public:\n"
|
|
" template <typename T>\n"
|
|
" static void Greeting(T val) {\n"
|
|
" std::cout << val << std::endl;\n"
|
|
" }\n"
|
|
"private:\n"
|
|
" static void SayHello() {\n"
|
|
" std::cout << \"Hello World!\" << std::endl;\n"
|
|
" }\n"
|
|
"};\n"
|
|
"template<>\n"
|
|
"void CTest::Greeting(bool) {\n"
|
|
" CTest::SayHello();\n"
|
|
"}\n"
|
|
"int main() {\n"
|
|
" CTest::Greeting<bool>(true);\n"
|
|
" return 0;\n"
|
|
"}";
|
|
const char exp[] = "class CTest { "
|
|
"public: "
|
|
"static void Greeting<bool> ( bool ) ; "
|
|
"template < typename T > "
|
|
"static void Greeting ( T val ) { "
|
|
"std :: cout << val << std :: endl ; "
|
|
"} "
|
|
"private: "
|
|
"static void SayHello ( ) { "
|
|
"std :: cout << \"Hello World!\" << std :: endl ; "
|
|
"} "
|
|
"} ; "
|
|
"void CTest :: Greeting<bool> ( bool ) { "
|
|
"CTest :: SayHello ( ) ; "
|
|
"} "
|
|
"int main ( ) { "
|
|
"CTest :: Greeting<bool> ( true ) ; "
|
|
"return 0 ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template89() { // #8917
|
|
const char code[] = "struct Fred {\n"
|
|
" template <typename T> static void foo() { }\n"
|
|
"};\n"
|
|
"template void Fred::foo<char>();\n"
|
|
"template void Fred::foo<float>();\n"
|
|
"template <> void Fred::foo<bool>() { }\n"
|
|
"template <> void Fred::foo<int>() { }";
|
|
const char exp[] = "struct Fred { "
|
|
"static void foo<int> ( ) ; "
|
|
"static void foo<bool> ( ) ; "
|
|
"static void foo<char> ( ) ; "
|
|
"static void foo<float> ( ) ; "
|
|
"} ; "
|
|
"void Fred :: foo<bool> ( ) { } "
|
|
"void Fred :: foo<int> ( ) { } "
|
|
"void Fred :: foo<char> ( ) { } "
|
|
"void Fred :: foo<float> ( ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template90() { // crash
|
|
const char code[] = "template <typename T> struct S1 {};\n"
|
|
"void f(S1<double>) {}\n"
|
|
"template <typename T>\n"
|
|
"decltype(S1<T>().~S1<T>()) fun1() {};";
|
|
const char exp[] = "struct S1<double> ; "
|
|
"void f ( S1<double> ) { } "
|
|
"template < typename T > "
|
|
"decltype ( S1 < T > ( ) . ~ S1 < T > ( ) ) fun1 ( ) { } ; "
|
|
"struct S1<double> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template91() {
|
|
{
|
|
const char code[] = "template<typename T> T foo(T t) { return t; }\n"
|
|
"template<> char foo<char>(char a) { return a; }\n"
|
|
"template<> int foo<int>(int a) { return a; }\n"
|
|
"template float foo<float>(float);\n"
|
|
"template double foo<double>(double);";
|
|
const char exp[] = "int foo<int> ( int a ) ; "
|
|
"char foo<char> ( char a ) ; "
|
|
"float foo<float> ( float t ) ; "
|
|
"double foo<double> ( double t ) ; "
|
|
"char foo<char> ( char a ) { return a ; } "
|
|
"int foo<int> ( int a ) { return a ; } "
|
|
"float foo<float> ( float t ) { return t ; } "
|
|
"double foo<double> ( double t ) { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "struct Fred {\n"
|
|
" template<typename T> T foo(T t) { return t; }\n"
|
|
" template<> char foo<char>(char a) { return a; }\n"
|
|
" template<> int foo<int>(int a) { return a; }\n"
|
|
"};\n"
|
|
"template float Fred::foo<float>(float);\n"
|
|
"template double Fred::foo<double>(double);";
|
|
const char exp[] = "struct Fred { "
|
|
"int foo<int> ( int a ) ; "
|
|
"char foo<char> ( char a ) ; "
|
|
"float foo<float> ( float t ) ; "
|
|
"double foo<double> ( double t ) ; "
|
|
"char foo<char> ( char a ) { return a ; } "
|
|
"int foo<int> ( int a ) { return a ; } "
|
|
"} ; "
|
|
"float Fred :: foo<float> ( float t ) { return t ; } "
|
|
"double Fred :: foo<double> ( double t ) { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "namespace NS1 {\n"
|
|
" namespace NS2 {\n"
|
|
" template<typename T> T foo(T t) { return t; }\n"
|
|
" template<> char foo<char>(char a) { return a; }\n"
|
|
" template<> int foo<int>(int a) { return a; }\n"
|
|
" }\n"
|
|
" template float NS2::foo<float>(float);\n"
|
|
"}\n"
|
|
"template double NS1::NS2::foo<double>(double);";
|
|
const char exp[] = "namespace NS1 { "
|
|
"namespace NS2 { "
|
|
"int foo<int> ( int a ) ; "
|
|
"char foo<char> ( char a ) ; "
|
|
"float foo<float> ( float t ) ; "
|
|
"double foo<double> ( double t ) ; "
|
|
"char foo<char> ( char a ) { return a ; } "
|
|
"int foo<int> ( int a ) { return a ; } "
|
|
"} "
|
|
"} "
|
|
"float NS1 :: NS2 :: foo<float> ( float t ) { return t ; } "
|
|
"double NS1 :: NS2 :: foo<double> ( double t ) { return t ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template92() {
|
|
const char code[] = "template<class T> void foo(T const& t) { }\n"
|
|
"template<> void foo<double>(double const& d) { }\n"
|
|
"template void foo<float>(float const& f);\n"
|
|
"int main() {\n"
|
|
" foo<int>(2);\n"
|
|
" foo<double>(3.14);\n"
|
|
" foo<float>(3.14f);\n"
|
|
"}";
|
|
const char exp[] = "void foo<double> ( const double & d ) ; "
|
|
"void foo<float> ( const float & t ) ; "
|
|
"void foo<int> ( const int & t ) ; "
|
|
"void foo<double> ( const double & d ) { } "
|
|
"int main ( ) { "
|
|
"foo<int> ( 2 ) ; "
|
|
"foo<double> ( 3.14 ) ; "
|
|
"foo<float> ( 3.14f ) ; "
|
|
"} "
|
|
"void foo<float> ( const float & t ) { } "
|
|
"void foo<int> ( const int & t ) { }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template93() { // crash
|
|
const char code[] = "template <typename Iterator>\n"
|
|
"void ForEach() { }\n"
|
|
"template <typename Type>\n"
|
|
"class Vector2 : public Vector {\n"
|
|
" template <typename Iterator>\n"
|
|
" void ForEach();\n"
|
|
"public:\n"
|
|
" void process();\n"
|
|
"};\n"
|
|
"template <typename Type>\n"
|
|
"void Vector2<Type>::process() {\n"
|
|
" ForEach<iterator>();\n"
|
|
"}\n"
|
|
"Vector2<string> c;";
|
|
const char exp[] = "void ForEach<iterator> ( ) ; "
|
|
"class Vector2<string> ; "
|
|
"Vector2<string> c ; "
|
|
"class Vector2<string> : public Vector { "
|
|
"template < typename Iterator > "
|
|
"void ForEach ( ) ; "
|
|
"public: "
|
|
"void process ( ) ; "
|
|
"} ; "
|
|
"void Vector2<string> :: process ( ) { "
|
|
"ForEach<iterator> ( ) ; "
|
|
"} "
|
|
"void ForEach<iterator> ( ) { "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template94() { // #8927 crash
|
|
const char code[] = "template <typename T>\n"
|
|
"class Array { };\n"
|
|
"template<typename T>\n"
|
|
"Array<T> foo() {};\n"
|
|
"template <> Array<double> foo<double>() { }\n"
|
|
"template <> Array<std::complex<float>> foo<std::complex<float>>() { }\n"
|
|
"template <> Array<float> foo<float>() { }\n"
|
|
"template < typename T >\n"
|
|
"Array<T> matmul() {\n"
|
|
" return foo<T>( );\n"
|
|
"}\n"
|
|
"template Array<std::complex<float>> matmul<std::complex<float>>();";
|
|
const char exp[] = "class Array<double> ; "
|
|
"class Array<std::complex<float>> ; "
|
|
"class Array<float> ; "
|
|
"Array<float> foo<float> ( ) ; "
|
|
"Array<std::complex<float>> foo<std::complex<float>> ( ) ; "
|
|
"Array<double> foo<double> ( ) ; "
|
|
"template < typename T > "
|
|
"Array < T > foo ( ) { } ; "
|
|
"Array<double> foo<double> ( ) { } "
|
|
"Array<std::complex<float>> foo<std::complex<float>> ( ) { } "
|
|
"Array<float> foo<float> ( ) { } "
|
|
"Array<std::complex<float>> matmul<std::complex<float>> ( ) ; "
|
|
"Array<std::complex<float>> matmul<std::complex<float>> ( ) { "
|
|
"return foo<std::complex<float>> ( ) ; "
|
|
"} "
|
|
"class Array<double> { } ; "
|
|
"class Array<std::complex<float>> { } ; "
|
|
"class Array<float> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template95() { // #7417
|
|
const char code[] = "template <typename T>\n"
|
|
"T Value = 123;\n"
|
|
"template<>\n"
|
|
"int Value<int> = 456;\n"
|
|
"float f = Value<float>;\n"
|
|
"int i = Value<int>;";
|
|
const char exp[] = "float Value<float> ; Value<float> = 123 ; "
|
|
"int Value<int> ; Value<int> = 456 ; "
|
|
"float f ; f = Value<float> ; "
|
|
"int i ; i = Value<int> ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template96() { // #7854
|
|
{
|
|
const char code[] = "template<unsigned int n>\n"
|
|
" constexpr long fib = fib<n-1> + fib<n-2>;\n"
|
|
"template<>\n"
|
|
" constexpr long fib<0> = 0;\n"
|
|
"template<>\n"
|
|
" constexpr long fib<1> = 1;\n"
|
|
"long f0 = fib<0>;\n"
|
|
"long f1 = fib<1>;\n"
|
|
"long f2 = fib<2>;\n"
|
|
"long f3 = fib<3>;";
|
|
const char exp[] = "const long fib<2> = fib<1> + fib<0> ; "
|
|
"const long fib<3> = fib<2> + fib<1> ; "
|
|
"const long fib<0> = 0 ; "
|
|
"const long fib<1> = 1 ; "
|
|
"long f0 ; f0 = fib<0> ; "
|
|
"long f1 ; f1 = fib<1> ; "
|
|
"long f2 ; f2 = fib<2> ; "
|
|
"long f3 ; f3 = fib<3> ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<unsigned int n>\n"
|
|
" constexpr long fib = fib<n-1> + fib<n-2>;\n"
|
|
"template<>\n"
|
|
" constexpr long fib<0> = 0;\n"
|
|
"template<>\n"
|
|
" constexpr long fib<1> = 1;\n"
|
|
"long f5 = fib<5>;\n";
|
|
const char exp[] = "const long fib<5> = fib<4> + fib<3> ; "
|
|
"const long fib<4> = fib<3> + fib<2> ; "
|
|
"const long fib<3> = fib<2> + fib<1> ; "
|
|
"const long fib<2> = fib<1> + fib<0> ; "
|
|
"const long fib<0> = 0 ; "
|
|
"const long fib<1> = 1 ; "
|
|
"long f5 ; f5 = fib<5> ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template97() {
|
|
const char code[] ="namespace NS1 {\n"
|
|
" namespace NS2 {\n"
|
|
" namespace NS3 {\n"
|
|
" namespace NS4 {\n"
|
|
" template<class T>\n"
|
|
" class Fred {\n"
|
|
" T * t;\n"
|
|
" public:\n"
|
|
" Fred<T>() : t(nullptr) {}\n"
|
|
" };\n"
|
|
" }\n"
|
|
" using namespace NS4;\n"
|
|
" Fred<bool> fred_bool;\n"
|
|
" NS4::Fred<char> fred_char;\n"
|
|
" }\n"
|
|
" using namespace NS3;\n"
|
|
" NS4::Fred<short> fred_short;\n"
|
|
" using namespace NS3::NS4;\n"
|
|
" Fred<int> fred_int;\n"
|
|
" NS3::NS4::Fred<long> fred_long;\n"
|
|
" NS2::NS3::NS4::Fred<float> fred_float;\n"
|
|
" NS1::NS2::NS3::NS4::Fred<double> fred_double;\n"
|
|
" }\n"
|
|
" using namespace NS2;\n"
|
|
" NS3::NS4::Fred<float> fred_float1;\n"
|
|
" NS2::NS3::NS4::Fred<double> fred_double1;\n"
|
|
"}\n"
|
|
"using namespace NS1::NS2::NS3::NS4;\n"
|
|
"Fred<bool> fred_bool1;\n"
|
|
"NS1::NS2::NS3::NS4::Fred<int> fred_int1;";
|
|
const char exp[] = "namespace NS1 { "
|
|
"namespace NS2 { "
|
|
"namespace NS3 { "
|
|
"namespace NS4 { "
|
|
"class Fred<bool> ; "
|
|
"class Fred<char> ; "
|
|
"class Fred<short> ; "
|
|
"class Fred<int> ; "
|
|
"class Fred<long> ; "
|
|
"class Fred<float> ; "
|
|
"class Fred<double> ; "
|
|
"} "
|
|
"using namespace NS4 ; "
|
|
"NS4 :: Fred<bool> fred_bool ; "
|
|
"NS4 :: Fred<char> fred_char ; "
|
|
"} "
|
|
"using namespace NS3 ; "
|
|
"NS3 :: NS4 :: Fred<short> fred_short ; "
|
|
"using namespace NS3 :: NS4 ; "
|
|
"NS3 :: NS4 :: Fred<int> fred_int ; "
|
|
"NS3 :: NS4 :: Fred<long> fred_long ; "
|
|
"NS2 :: NS3 :: NS4 :: Fred<float> fred_float ; "
|
|
"NS1 :: NS2 :: NS3 :: NS4 :: Fred<double> fred_double ; "
|
|
"} "
|
|
"using namespace NS2 ; "
|
|
"NS2 :: NS3 :: NS4 :: Fred<float> fred_float1 ; "
|
|
"NS2 :: NS3 :: NS4 :: Fred<double> fred_double1 ; "
|
|
"} "
|
|
"using namespace NS1 :: NS2 :: NS3 :: NS4 ; "
|
|
"NS1 :: NS2 :: NS3 :: NS4 :: Fred<bool> fred_bool1 ; "
|
|
"NS1 :: NS2 :: NS3 :: NS4 :: Fred<int> fred_int1 ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<bool> { "
|
|
"bool * t ; "
|
|
"public: "
|
|
"Fred<bool> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<char> { "
|
|
"char * t ; "
|
|
"public: "
|
|
"Fred<char> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<short> { "
|
|
"short * t ; "
|
|
"public: "
|
|
"Fred<short> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<int> { "
|
|
"int * t ; "
|
|
"public: "
|
|
"Fred<int> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<long> { "
|
|
"long * t ; "
|
|
"public: "
|
|
"Fred<long> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<float> { "
|
|
"float * t ; "
|
|
"public: "
|
|
"Fred<float> ( ) : t ( nullptr ) { } "
|
|
"} ; "
|
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<double> { "
|
|
"double * t ; "
|
|
"public: "
|
|
"Fred<double> ( ) : t ( nullptr ) { } "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template98() { // #8959
|
|
const char code[] = "template <typename T>\n"
|
|
"using unique_ptr_with_deleter = std::unique_ptr<T, std::function<void(T*)>>;\n"
|
|
"class A {};\n"
|
|
"static void func() {\n"
|
|
" unique_ptr_with_deleter<A> tmp(new A(), [](A* a) {\n"
|
|
" delete a;\n"
|
|
" });\n"
|
|
"}";
|
|
const char exp[] = "; "
|
|
"class A { } ; "
|
|
"static void func ( ) { "
|
|
"std :: unique_ptr < A , std :: function < void ( A * ) > > tmp ( new A ( ) , [ ] ( A * a ) { "
|
|
"delete a ; "
|
|
"} ) ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template99() { // #8960
|
|
const char code[] = "template <typename T>\n"
|
|
"class Base {\n"
|
|
"public:\n"
|
|
" using ArrayType = std::vector<Base<T>>;\n"
|
|
"};\n"
|
|
"using A = Base<int>;\n"
|
|
"static A::ArrayType array;\n";
|
|
const char exp[] = "class Base<int> ; "
|
|
"static std :: vector < Base<int> > array ; "
|
|
"class Base<int> { "
|
|
"public: "
|
|
"} ;";
|
|
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template100() { // #8967
|
|
const char code[] = "enum class Device { I2C0, I2C1 };\n"
|
|
"template <Device D>\n"
|
|
"const char* deviceFile;\n"
|
|
"template <>\n"
|
|
"const char* deviceFile<Device::I2C0> = \"/tmp/i2c-0\";\n";
|
|
|
|
const char exp[] = "enum class Device { I2C0 , I2C1 } ; "
|
|
"template < Device D > "
|
|
"const char * deviceFile ; "
|
|
"const char * deviceFile<Device::I2C0> ; deviceFile<Device::I2C0> = \"/tmp/i2c-0\" ;";
|
|
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template101() { // #8968
|
|
const char code[] = "class A {\n"
|
|
"public:\n"
|
|
" using ArrayType = std::vector<int>;\n"
|
|
" void func(typename ArrayType::size_type i) {\n"
|
|
" }\n"
|
|
"};";
|
|
|
|
const char exp[] = "class A { "
|
|
"public: "
|
|
"void func ( std :: vector < int > :: size_type i ) { "
|
|
"} "
|
|
"} ;";
|
|
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template102() { // #9005
|
|
const char code[] = "namespace ns {\n"
|
|
"template <class T>\n"
|
|
"struct is_floating_point \n"
|
|
": std::integral_constant<bool, std::is_floating_point<T>::value || true>\n"
|
|
"{};\n"
|
|
"}\n"
|
|
"void f() {\n"
|
|
" if(std::is_floating_point<float>::value) {}\n"
|
|
"}";
|
|
const char exp[] = "namespace ns { "
|
|
"template < class T > "
|
|
"struct is_floating_point "
|
|
": std :: integral_constant < bool , std :: is_floating_point < T > :: value || true > "
|
|
"{ } ; "
|
|
"} "
|
|
"void f ( ) { "
|
|
"if ( std :: is_floating_point < float > :: value ) { } "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template103() {
|
|
const char code[] = "namespace sample {\n"
|
|
" template <typename T>\n"
|
|
" class Sample {\n"
|
|
" public:\n"
|
|
" T function(T t);\n"
|
|
" };\n"
|
|
" template <typename T>\n"
|
|
" T Sample<T>::function(T t) {\n"
|
|
" return t;\n"
|
|
" }\n"
|
|
"}\n"
|
|
"sample::Sample<int> s1;";
|
|
const char exp[] = "namespace sample { "
|
|
"class Sample<int> ; "
|
|
"} "
|
|
"sample :: Sample<int> s1 ; "
|
|
"class sample :: Sample<int> { "
|
|
"public: "
|
|
"int function ( int t ) ; "
|
|
"} ; "
|
|
"int sample :: Sample<int> :: function ( int t ) { "
|
|
"return t ; "
|
|
"}";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template104() { // #9021
|
|
const char code[] = "template < int i >\n"
|
|
"auto key ( ) { return hana :: test :: ct_eq < i > { } ; }\n"
|
|
"template < int i >\n"
|
|
"auto val ( ) { return hana :: test :: ct_eq < - i > { } ; }\n"
|
|
"template < int i , int j >\n"
|
|
"auto p ( ) { return :: minimal_product ( key < i > ( ) , val < j > ( ) ) ; }\n"
|
|
"int main ( ) {\n"
|
|
" BOOST_HANA_CONSTANT_CHECK ( hana :: equal (\n"
|
|
" hana :: at_key ( hana :: make_map ( p < 0 , 0 > ( ) ) , key < 0 > ( ) ) ,\n"
|
|
" val < 0 > ( ) ) ) ;\n"
|
|
"}";
|
|
const char exp[] = "auto key<0> ( ) ; "
|
|
"auto val<0> ( ) ; "
|
|
"auto p<0,0> ( ) ; "
|
|
"int main ( ) { "
|
|
"BOOST_HANA_CONSTANT_CHECK ( hana :: equal ( "
|
|
"hana :: at_key ( hana :: make_map ( p<0,0> ( ) ) , key<0> ( ) ) , "
|
|
"val<0> ( ) ) ) ; "
|
|
"} "
|
|
"auto p<0,0> ( ) { return :: minimal_product ( key<0> ( ) , val<0> ( ) ) ; } "
|
|
"auto val<0> ( ) { return hana :: test :: ct_eq < - 0 > { } ; } "
|
|
"auto key<0> ( ) { return hana :: test :: ct_eq < 0 > { } ; }";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template105() { // #9076
|
|
const char code[] = "template <template <typename> class TOUT> class ObjectCache;\n"
|
|
"template <template <typename> class TOUT>\n"
|
|
"class ObjectCache { };\n"
|
|
"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));
|
|
}
|
|
|
|
void template106() {
|
|
const char code[] = "template<class T, class U> class A {\n"
|
|
"public:\n"
|
|
" int x;\n"
|
|
"};\n"
|
|
"template<template<class T, class U> class V> class B {\n"
|
|
" V<char, char> i;\n"
|
|
"};\n"
|
|
"B<A> c;";
|
|
const char exp[] = "class A<char,char> ; "
|
|
"class B<A> ; "
|
|
"B<A> c ; "
|
|
"class B<A> { "
|
|
"A<char,char> i ; "
|
|
"} ; class A<char,char> { "
|
|
"public: "
|
|
"int x ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template107() { // #8663
|
|
const char code[] = "template <class T1, class T2>\n"
|
|
"void f() {\n"
|
|
" using T3 = typename T1::template T3<T2>;\n"
|
|
" T3 t;\n"
|
|
"}\n"
|
|
"struct C3 {\n"
|
|
" template <typename T>\n"
|
|
" class T3\n"
|
|
" {};\n"
|
|
"};\n"
|
|
"void foo() {\n"
|
|
" f<C3, long>();\n"
|
|
"}";
|
|
const char exp[] = "void f<C3,long> ( ) ; "
|
|
"struct C3 { "
|
|
"class T3<long> ; "
|
|
"} ; "
|
|
"void foo ( ) { "
|
|
"f<C3,long> ( ) ; "
|
|
"} "
|
|
"void f<C3,long> ( ) { "
|
|
"C3 :: T3<long> t ; "
|
|
"} "
|
|
"class C3 :: T3<long> { } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
|
const char code[] = "template <typename T> struct C {};\n"
|
|
"template <typename T> struct S {a};\n"
|
|
"template <typename T> struct S<C<T>> {b};\n"
|
|
"S<int> s;";
|
|
const char exp[] = "template < typename T > struct C { } ; struct S<int> ; template < typename T > struct S < C < T > > { b } ; S<int> s ; struct S<int> { a } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template_specialization_2() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
|
const char code[] = "template <typename T> struct C {};\n"
|
|
"template <typename T> struct S {a};\n"
|
|
"template <typename T> struct S<C<T>> {b};\n"
|
|
"S<C<int>> s;";
|
|
const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S { a } ; struct S<C<int>> ; S<C<int>> s ; struct S<C<int>> { b } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
|
|
void template_enum() {
|
|
const char code1[] = "template <class T>\n"
|
|
"struct Unconst {\n"
|
|
" typedef T type;\n"
|
|
"};\n"
|
|
"template <class T>\n"
|
|
"struct Unconst<const T> {\n"
|
|
" typedef T type;\n"
|
|
"};\n"
|
|
"template <class T>\n"
|
|
"struct Unconst<const T&> {\n"
|
|
" typedef T& type;\n"
|
|
"};\n"
|
|
"template <class T>\n"
|
|
"struct Unconst<T* const> {\n"
|
|
" typedef T* type;\n"
|
|
"};\n"
|
|
"template <class T1, class T2>\n"
|
|
"struct type_equal {\n"
|
|
" enum { value = 0 };\n"
|
|
"};\n"
|
|
"template <class T>\n"
|
|
"struct type_equal<T, T> {\n"
|
|
" enum { value = 1 };\n"
|
|
"};\n"
|
|
"template<class T>\n"
|
|
"struct template_is_const\n"
|
|
"{\n"
|
|
" enum {value = !type_equal<T, typename Unconst<T>::type>::value };\n"
|
|
"};";
|
|
const char exp1[] = "template < class T > struct Unconst { } ; "
|
|
"template < class T > struct Unconst < const T > { } ; "
|
|
"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 template_is_const { enum Anonymous2 { value = ! type_equal < T , Unconst < T > :: type > :: value } ; } ;";
|
|
ASSERT_EQUALS(exp1, tok(code1));
|
|
}
|
|
|
|
void template_default_parameter() {
|
|
{
|
|
const char code[] = "template <class T, int n=3>\n"
|
|
"class A\n"
|
|
"{ T ar[n]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int,2> a1;\n"
|
|
" A<int> a2;\n"
|
|
"}\n";
|
|
|
|
// The expected result..
|
|
const char expected[] = "class A<int,2> ; "
|
|
"class A<int,3> ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" A<int,2> a1 ;"
|
|
" A<int,3> a2 ; "
|
|
"} "
|
|
"class A<int,2> "
|
|
"{ int ar [ 2 ] ; } ; "
|
|
"class A<int,3> "
|
|
"{ int ar [ 3 ] ; } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <class T, int n1=3, int n2=2>\n"
|
|
"class A\n"
|
|
"{ T ar[n1+n2]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int> a1;\n"
|
|
" A<int,3> a2;\n"
|
|
"}\n";
|
|
|
|
// The expected result..
|
|
const char expected[] = "class A<int,3,2> ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" A<int,3,2> a1 ;"
|
|
" A<int,3,2> a2 ; "
|
|
"} "
|
|
"class A<int,3,2> "
|
|
"{ int ar [ 3 + 2 ] ; } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <class T, int n=3>\n"
|
|
"class A\n"
|
|
"{ T ar[n]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int,(int)2> a1;\n"
|
|
" A<int> a2;\n"
|
|
"}\n";
|
|
|
|
const char wanted[] = "template < class T , int n >"
|
|
" class A"
|
|
" { T ar [ n ] ; } ;"
|
|
" void f ( )"
|
|
" {"
|
|
" A<int,(int)2> a1 ;"
|
|
" A<int,3> a2 ;"
|
|
" }"
|
|
" class A<int,2>"
|
|
" { int ar [ 2 ] ; }"
|
|
" class A<int,3>"
|
|
" { int ar [ 3 ] ; }";
|
|
|
|
const char current[] = "class A<int,3> ; "
|
|
"void f ( ) "
|
|
"{ "
|
|
"A < int , ( int ) 2 > a1 ; "
|
|
"A<int,3> a2 ; "
|
|
"} "
|
|
"class A<int,3> "
|
|
"{ int ar [ 3 ] ; } ;";
|
|
TODO_ASSERT_EQUALS(wanted, current, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "class A { }; "
|
|
"template<class T> class B { }; "
|
|
"template<class T1, class T2 = B<T1>> class C { }; "
|
|
"template<class T1 = A, typename T2 = B<A>> class D { };";
|
|
ASSERT_EQUALS("class A { } ; "
|
|
"template < class T > class B { } ; "
|
|
"template < class T1 , class T2 = B < T1 > > class C { } ; "
|
|
"template < class T1 = A , typename T2 = B < A > > class D { } ;", tok(code));
|
|
}
|
|
{
|
|
// #7548
|
|
const char code[] = "template<class T, class U> class DefaultMemory {}; "
|
|
"template<class Key, class Val, class Mem=DefaultMemory<Key,Val> > class thv_table_c {}; "
|
|
"thv_table_c<void *,void *> id_table_m;";
|
|
const char exp [] = "template < class T , class U > class DefaultMemory { } ; "
|
|
"thv_table_c<void * , void * , DefaultMemory < void * , void *>> id_table_m ; "
|
|
"class thv_table_c<void * , void * , DefaultMemory < void * , void * >> { } ;";
|
|
const char curr[] = "template < class T , class U > class DefaultMemory { } ; "
|
|
"class thv_table_c<void*,void*,DefaultMemory<Key,Val>> ; "
|
|
"thv_table_c<void*,void*,DefaultMemory<Key,Val>> id_table_m ; "
|
|
"class thv_table_c<void*,void*,DefaultMemory<Key,Val>> { } ;";
|
|
TODO_ASSERT_EQUALS(exp, curr, tok(code));
|
|
}
|
|
}
|
|
|
|
void template_forward_declared_default_parameter() {
|
|
{
|
|
const char code[] = "template <class T, int n=3> class A;\n"
|
|
"template <class T, int n>\n"
|
|
"class A\n"
|
|
"{ T ar[n]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int,2> a1;\n"
|
|
" A<int> a2;\n"
|
|
"}\n";
|
|
|
|
const char exp[] = "class A<int,2> ; "
|
|
"class A<int,3> ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" A<int,2> a1 ;"
|
|
" A<int,3> a2 ; "
|
|
"} "
|
|
"class A<int,2> "
|
|
"{ int ar [ 2 ] ; } ; "
|
|
"class A<int,3> "
|
|
"{ int ar [ 3 ] ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <class, int = 3> class A;\n"
|
|
"template <class T, int n>\n"
|
|
"class A\n"
|
|
"{ T ar[n]; };\n"
|
|
"\n"
|
|
"void f()\n"
|
|
"{\n"
|
|
" A<int,2> a1;\n"
|
|
" A<int> a2;\n"
|
|
"}\n";
|
|
|
|
const char exp[] = "class A<int,2> ; "
|
|
"class A<int,3> ; "
|
|
"void f ( ) "
|
|
"{"
|
|
" A<int,2> a1 ;"
|
|
" A<int,3> a2 ; "
|
|
"} "
|
|
"class A<int,2> "
|
|
"{ int ar [ 2 ] ; } ; "
|
|
"class A<int,3> "
|
|
"{ int ar [ 3 ] ; } ;";
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<typename Lhs, int TriangularPart = (int(Lhs::Flags) & LowerTriangularBit)>\n"
|
|
"struct ei_solve_triangular_selector;\n"
|
|
"template<typename Lhs, int UpLo>\n"
|
|
"struct ei_solve_triangular_selector<Lhs,UpLo> {\n"
|
|
"};\n"
|
|
"template<typename Lhs, int TriangularPart>\n"
|
|
"struct ei_solve_triangular_selector { };";
|
|
|
|
const char exp[] = "template < typename Lhs , int TriangularPart = ( int ( Lhs :: Flags ) & LowerTriangularBit ) > "
|
|
"struct ei_solve_triangular_selector ; "
|
|
"template < typename Lhs , int UpLo > "
|
|
"struct ei_solve_triangular_selector < Lhs , UpLo > { "
|
|
"} ; "
|
|
"template < typename Lhs , int TriangularPart = ( int ( Lhs :: Flags ) & LowerTriangularBit ) > "
|
|
"struct ei_solve_triangular_selector { } ;";
|
|
|
|
ASSERT_EQUALS(exp, tok(code));
|
|
}
|
|
}
|
|
|
|
void template_default_type() {
|
|
const char code[] = "template <typename T, typename U=T>\n"
|
|
"class A\n"
|
|
"{\n"
|
|
"public:\n"
|
|
" void foo() {\n"
|
|
" int a;\n"
|
|
" a = static_cast<U>(a);\n"
|
|
" }\n"
|
|
"};\n"
|
|
"\n"
|
|
"template <typename T>\n"
|
|
"class B\n"
|
|
"{\n"
|
|
"protected:\n"
|
|
" A<int> a;\n"
|
|
"};\n"
|
|
"\n"
|
|
"class C\n"
|
|
" : public B<int>\n"
|
|
"{\n"
|
|
"};\n";
|
|
|
|
tok(code);
|
|
|
|
//ASSERT_EQUALS("[file1.cpp:15]: (error) Internal error: failed to instantiate template. The checking continues anyway.\n", errout.str());
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template_typename() {
|
|
{
|
|
const char code[] = "template <class T>\n"
|
|
"void foo(typename T::t *)\n"
|
|
"{ }";
|
|
|
|
// The expected result..
|
|
const char expected[] = "template < class T > void foo ( T :: t * ) { }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
{
|
|
const char code[] = "void f() {\n"
|
|
" x(sizeof typename);\n"
|
|
" type = 0;\n"
|
|
"}";
|
|
|
|
ASSERT_EQUALS("void f ( ) { x ( sizeof ( typename ) ) ; type = 0 ; }", tok(code));
|
|
}
|
|
}
|
|
|
|
void template_constructor() {
|
|
// #3152 - if template constructor is removed then there might be
|
|
// "no constructor" false positives
|
|
const char code[] = "class Fred {\n"
|
|
" template<class T> explicit Fred(T t) { }\n"
|
|
"}";
|
|
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 { template < class T > Fred ( T t ) { } }", tok(code2));
|
|
}
|
|
|
|
void syntax_error_templates_1() {
|
|
// ok code.. using ">" for a comparison
|
|
tok("x<y>z> xyz;\n");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// ok code
|
|
tok("template<class T> operator<(T a, T b) { }\n");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// ok code (ticket #1984)
|
|
tok("void f(a) int a;\n"
|
|
"{ ;x<y; }");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// ok code (ticket #1985)
|
|
tok("void f()\n"
|
|
"try { ;x<y; }");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// ok code (ticket #3183)
|
|
tok("MACRO(({ i < x }))");
|
|
ASSERT_EQUALS("", errout.str());
|
|
|
|
// bad code.. missing ">"
|
|
ASSERT_THROW(tok("x<y<int> xyz;\n"), InternalError);
|
|
|
|
// bad code
|
|
ASSERT_THROW(tok("typedef\n"
|
|
" typename boost::mpl::if_c<\n"
|
|
" _visitableIndex < boost::mpl::size< typename _Visitables::ConcreteVisitables >::value\n"
|
|
" , ConcreteVisitable\n"
|
|
" , Dummy< _visitableIndex >\n"
|
|
" >::type ConcreteVisitableOrDummy;\n"), InternalError);
|
|
|
|
// code is ok, don't show syntax error
|
|
tok("struct A {int a;int b};\n"
|
|
"class Fred {"
|
|
"public:\n"
|
|
" Fred() : a({1,2}) {\n"
|
|
" for (int i=0;i<6;i++);\n" // <- no syntax error
|
|
" }\n"
|
|
"private:\n"
|
|
" A a;\n"
|
|
"};\n");
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void template_member_ptr() { // Ticket #5786
|
|
tok("struct A {}; "
|
|
"struct B { "
|
|
"template <void (A::*)() const> struct BB {}; "
|
|
"template <bool BT> static bool foo(int) { return true; } "
|
|
"void bar() { bool b = foo<true>(0); }"
|
|
"};");
|
|
tok("struct A {}; "
|
|
"struct B { "
|
|
"template <void (A::*)() volatile> struct BB {}; "
|
|
"template <bool BT> static bool foo(int) { return true; } "
|
|
"void bar() { bool b = foo<true>(0); }"
|
|
"};");
|
|
tok("struct A {}; "
|
|
"struct B { "
|
|
"template <void (A::*)() const volatile> struct BB {}; "
|
|
"template <bool BT> static bool foo(int) { return true; } "
|
|
"void bar() { bool b = foo<true>(0); }"
|
|
"};");
|
|
tok("struct A {}; "
|
|
"struct B { "
|
|
"template <void (A::*)() volatile const> struct BB {}; "
|
|
"template <bool BT> static bool foo(int) { return true; } "
|
|
"void bar() { bool b = foo<true>(0); }"
|
|
"};");
|
|
}
|
|
|
|
void template_namespace_1() {
|
|
// #6570
|
|
const char code[] = "namespace {\n"
|
|
" template<class T> void Fred(T value) { }\n"
|
|
"}\n"
|
|
"Fred<int>(123);";
|
|
ASSERT_EQUALS("namespace { "
|
|
"void Fred<int> ( int value ) ; "
|
|
"} "
|
|
"Fred<int> ( 123 ) ; "
|
|
"void Fred<int> ( int value ) { }", tok(code));
|
|
}
|
|
|
|
void template_namespace_2() {
|
|
// #8283
|
|
const char code[] = "namespace X {\n"
|
|
" template<class T> struct S { };\n"
|
|
"}\n"
|
|
"X::S<int> s;";
|
|
ASSERT_EQUALS("namespace X { "
|
|
"struct S<int> ; "
|
|
"} "
|
|
"X :: S<int> s ; "
|
|
"struct X :: S<int> { } ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_3() {
|
|
const char code[] = "namespace test16 {\n"
|
|
" template <class T> struct foo {\n"
|
|
" static void *bar();\n"
|
|
" };\n"
|
|
" void *test() { return foo<int>::bar(); }\n"
|
|
"}";
|
|
ASSERT_EQUALS("namespace test16 {"
|
|
" struct foo<int> ;"
|
|
" void * test ( ) {"
|
|
" return foo<int> :: bar ( ) ;"
|
|
" } "
|
|
"} "
|
|
"struct test16 :: foo<int> {"
|
|
" static void * bar ( ) ; "
|
|
"} ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_4() {
|
|
const char code[] = "namespace foo {\n"
|
|
" template<class T> class A { void dostuff() {} };\n"
|
|
" struct S : public A<int> {\n"
|
|
" void f() {\n"
|
|
" A<int>::dostuff();\n"
|
|
" }\n"
|
|
" };\n"
|
|
"}";
|
|
ASSERT_EQUALS("namespace foo {"
|
|
" class A<int> ;"
|
|
" struct S : public A<int> {"
|
|
" void f ( ) {"
|
|
" A<int> :: dostuff ( ) ;"
|
|
" }"
|
|
" } ; "
|
|
"} "
|
|
"class foo :: A<int> { void dostuff ( ) { } } ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_5() {
|
|
const char code[] = "template<class C> struct S {};\n"
|
|
"namespace X { S<int> s; }";
|
|
ASSERT_EQUALS("struct S<int> ; "
|
|
"namespace X { S<int> s ; } "
|
|
"struct S<int> { } ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_6() {
|
|
const char code[] = "namespace NS {\n"
|
|
"template <typename T> union C {\n"
|
|
" char dummy[sizeof(T)];\n"
|
|
" T value;\n"
|
|
" C();\n"
|
|
" ~C();\n"
|
|
" C(const C &);\n"
|
|
" C & operator = (const C &);\n"
|
|
"};\n"
|
|
"}\n"
|
|
"NS::C<int> intC;\n"
|
|
"template <typename T> NS::C<T>::C() {}\n"
|
|
"template <typename T> NS::C<T>::~C() {}\n"
|
|
"template <typename T> NS::C<T>::C(const NS::C<T> &) {}\n"
|
|
"template <typename T> NS::C<T> & NS::C<T>::operator=(const NS::C<T> &) {}";
|
|
ASSERT_EQUALS("namespace NS { "
|
|
"union C<int> ; "
|
|
"} "
|
|
"NS :: C<int> intC ; union NS :: C<int> { "
|
|
"char dummy [ sizeof ( int ) ] ; "
|
|
"int value ; "
|
|
"C<int> ( ) ; "
|
|
"~ C<int> ( ) ; "
|
|
"C<int> ( const NS :: C<int> & ) ; "
|
|
"NS :: C<int> & operator= ( const NS :: C<int> & ) ; "
|
|
"} ; "
|
|
"NS :: C<int> :: C<int> ( ) { } "
|
|
"NS :: C<int> :: ~ C<int> ( ) { } "
|
|
"NS :: C<int> :: C<int> ( const NS :: C<int> & ) { } "
|
|
"NS :: C<int> & NS :: C<int> :: operator= ( const NS :: C<int> & ) { }", tok(code));
|
|
}
|
|
|
|
void template_namespace_7() { // #8768
|
|
const char code[] = "namespace N1 {\n"
|
|
"namespace N2 {\n"
|
|
" struct C { };\n"
|
|
" template <class T> struct CT { };\n"
|
|
" C c1;\n"
|
|
" CT<int> ct1;\n"
|
|
"}\n"
|
|
"N2::C c2;\n"
|
|
"N2::CT<int> ct2;\n"
|
|
"}\n"
|
|
"N1::N2::C c3;\n"
|
|
"N1::N2::CT<int> ct3;";
|
|
ASSERT_EQUALS("namespace N1 { "
|
|
"namespace N2 { "
|
|
"struct C { } ; "
|
|
"struct CT<int> ; "
|
|
"C c1 ; "
|
|
"CT<int> ct1 ; "
|
|
"} "
|
|
"N2 :: C c2 ; "
|
|
"N2 :: CT<int> ct2 ; "
|
|
"} "
|
|
"N1 :: N2 :: C c3 ; "
|
|
"N1 :: N2 :: CT<int> ct3 ; struct N1 :: N2 :: CT<int> { } ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_8() { // #8768
|
|
const char code[] = "namespace NS1 {\n"
|
|
"namespace NS2 {\n"
|
|
" template <typename T>\n"
|
|
" struct Fred {\n"
|
|
" Fred();\n"
|
|
" Fred(const Fred &);\n"
|
|
" Fred & operator = (const Fred &);\n"
|
|
" ~Fred();\n"
|
|
" };\n"
|
|
" template <typename T>\n"
|
|
" Fred<T>::Fred() { }\n"
|
|
" template <typename T>\n"
|
|
" Fred<T>::Fred(const Fred<T> & f) { }\n"
|
|
" template <typename T>\n"
|
|
" Fred<T> & Fred<T>::operator = (const Fred<T> & f) { }\n"
|
|
" template <typename T>\n"
|
|
" Fred<T>::~Fred() { }\n"
|
|
"}\n"
|
|
"}\n"
|
|
"NS1::NS2::Fred<int> fred;";
|
|
ASSERT_EQUALS("namespace NS1 { "
|
|
"namespace NS2 { "
|
|
"struct Fred<int> ; "
|
|
"} "
|
|
"} "
|
|
"NS1 :: NS2 :: Fred<int> fred ; struct NS1 :: NS2 :: Fred<int> { "
|
|
"Fred<int> ( ) ; "
|
|
"Fred<int> ( const NS1 :: NS2 :: Fred<int> & ) ; "
|
|
"NS1 :: NS2 :: Fred<int> & operator= ( const NS1 :: NS2 :: Fred<int> & ) ; "
|
|
"~ Fred<int> ( ) ; "
|
|
"} ; "
|
|
"NS1 :: NS2 :: Fred<int> :: Fred<int> ( ) { } "
|
|
"NS1 :: NS2 :: Fred<int> :: Fred<int> ( const NS1 :: NS2 :: Fred<int> & f ) { } "
|
|
"NS1 :: NS2 :: Fred<int> & NS1 :: NS2 :: Fred<int> :: operator= ( const NS1 :: NS2 :: Fred<int> & f ) { } "
|
|
"NS1 :: NS2 :: Fred<int> :: ~ Fred<int> ( ) { }", tok(code));
|
|
}
|
|
|
|
void template_namespace_9() {
|
|
const char code[] = "namespace NS {\n"
|
|
"template<int type> struct Barney;\n"
|
|
"template<> struct Barney<1> { };\n"
|
|
"template<int type>\n"
|
|
"class Fred {\n"
|
|
"public:\n"
|
|
" Fred();\n"
|
|
"private:\n"
|
|
" Barney<type> m_data;\n"
|
|
"};\n"
|
|
"template class Fred<1>;\n"
|
|
"}\n";
|
|
ASSERT_EQUALS("namespace NS { "
|
|
"template < int type > struct Barney ; "
|
|
"struct Barney<1> { } ; "
|
|
"class Fred<1> ; "
|
|
"} "
|
|
"class NS :: Fred<1> { "
|
|
"public: "
|
|
"Fred<1> ( ) ; "
|
|
"private: "
|
|
"Barney<1> m_data ; "
|
|
"} ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_10() {
|
|
const char code[] = "namespace NS1 {\n"
|
|
"namespace NS2 {\n"
|
|
"template<class T>\n"
|
|
"class Fred {\n"
|
|
" T * t;\n"
|
|
"public:\n"
|
|
" Fred<T>() : t(nullptr) {}\n"
|
|
"};\n"
|
|
"}\n"
|
|
"}\n"
|
|
"NS1::NS2::Fred<int> fred;";
|
|
ASSERT_EQUALS("namespace NS1 { "
|
|
"namespace NS2 { "
|
|
"class Fred<int> ; "
|
|
"} "
|
|
"} "
|
|
"NS1 :: NS2 :: Fred<int> fred ; class NS1 :: NS2 :: Fred<int> "
|
|
"{ "
|
|
"int * t ; "
|
|
"public: "
|
|
"Fred<int> ( ) : t ( nullptr ) { } "
|
|
"} ;", tok(code));
|
|
}
|
|
|
|
void template_namespace_11() {// #7145
|
|
const char code[] = "namespace MyNamespace {\n"
|
|
"class TestClass {\n"
|
|
"public:\n"
|
|
" TestClass() {\n"
|
|
" SomeFunction();\n"
|
|
" TemplatedMethod< int >( 0 );\n"
|
|
" }\n"
|
|
" void SomeFunction() { }\n"
|
|
"private:\n"
|
|
" template< typename T > T TemplatedMethod(T);\n"
|
|
"};\n"
|
|
"template< typename T > T TestClass::TemplatedMethod(T t) { return t; }\n"
|
|
"}";
|
|
ASSERT_EQUALS("namespace MyNamespace { "
|
|
"class TestClass { "
|
|
"public: "
|
|
"TestClass ( ) { "
|
|
"SomeFunction ( ) ; "
|
|
"TemplatedMethod<int> ( 0 ) ; "
|
|
"} "
|
|
"void SomeFunction ( ) { } "
|
|
"private: "
|
|
"int TemplatedMethod<int> ( int ) ; "
|
|
"} ; "
|
|
"} int MyNamespace :: TestClass :: TemplatedMethod<int> ( int t ) { return t ; }", tok(code));
|
|
}
|
|
|
|
unsigned int templateParameters(const char code[]) {
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
tokenizer.tokenize(istr, "test.cpp", "");
|
|
|
|
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
|
|
if (tok->str() == "var1")
|
|
(const_cast<Token *>(tok))->varId(1);
|
|
}
|
|
|
|
return TemplateSimplifier::templateParameters(tokenizer.tokens()->next());
|
|
}
|
|
|
|
void templateParameters() {
|
|
// Test that the function TemplateSimplifier::templateParameters works
|
|
ASSERT_EQUALS(1U, templateParameters("X<struct C> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<union C> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<const int> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<int const *> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<const struct C> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<len>>x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<typename> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<...> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<class T...> x;")); // Invalid syntax
|
|
ASSERT_EQUALS(1U, templateParameters("X<class... T> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<class, typename T...> x;")); // Invalid syntax
|
|
ASSERT_EQUALS(2U, templateParameters("X<class, typename... T> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("X<int(&)(), class> x;"));
|
|
ASSERT_EQUALS(3U, templateParameters("X<char, int(*)(), bool> x;"));
|
|
TODO_ASSERT_EQUALS(1U, 0U, templateParameters("X<int...> x;")); // Mishandled valid syntax
|
|
TODO_ASSERT_EQUALS(2U, 0U, templateParameters("X<class, typename...> x;")); // Mishandled valid syntax
|
|
ASSERT_EQUALS(2U, templateParameters("X<1, T> x;"));
|
|
ASSERT_EQUALS(1U, templateParameters("X<i == 0> x;"));
|
|
ASSERT_EQUALS(2U, templateParameters("X<int, i>=0> x;"));
|
|
ASSERT_EQUALS(3U, templateParameters("X<int, i>=0, i - 2> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("var1<1> x;"));
|
|
ASSERT_EQUALS(0U, templateParameters("X<1>2;"));
|
|
}
|
|
|
|
// Helper function to unit test TemplateSimplifier::getTemplateNamePosition
|
|
int templateNamePositionHelper(const char code[], unsigned offset = 0) {
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
tokenizer.tokenize(istr, "test.cpp", emptyString);
|
|
|
|
const Token *_tok = tokenizer.tokens();
|
|
for (unsigned i = 0 ; i < offset ; ++i)
|
|
_tok = _tok->next();
|
|
return tokenizer.mTemplateSimplifier->getTemplateNamePosition(_tok);
|
|
}
|
|
|
|
void templateNamePosition() {
|
|
// Template class
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> class A {};", 4));
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> struct A {};", 4));
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> class A : B {};", 4));
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> struct A : B {};", 4));
|
|
// Template function definitions
|
|
ASSERT_EQUALS(2, templateNamePositionHelper("template<class T> unsigned foo() { return 0; }", 4));
|
|
ASSERT_EQUALS(3, templateNamePositionHelper("template<class T> unsigned* foo() { return 0; }", 4));
|
|
ASSERT_EQUALS(4, templateNamePositionHelper("template<class T> unsigned** foo() { return 0; }", 4));
|
|
|
|
ASSERT_EQUALS(3, templateNamePositionHelper("template<class T> const unsigned foo() { return 0; }", 4));
|
|
ASSERT_EQUALS(4, templateNamePositionHelper("template<class T> const unsigned& foo() { return 0; }", 4));
|
|
ASSERT_EQUALS(5, templateNamePositionHelper("template<class T> const unsigned** foo() { return 0; }", 4));
|
|
|
|
ASSERT_EQUALS(4, templateNamePositionHelper("template<class T> std::string foo() { static str::string str; return str; }", 4));
|
|
ASSERT_EQUALS(5, templateNamePositionHelper("template<class T> std::string & foo() { static str::string str; return str; }", 4));
|
|
ASSERT_EQUALS(6, templateNamePositionHelper("template<class T> const std::string & foo() { static str::string str; return str; }", 4));
|
|
|
|
ASSERT_EQUALS(9, templateNamePositionHelper("template<class T> std::map<int, int> foo() { static std::map<int, int> m; return m; }", 4));
|
|
ASSERT_EQUALS(10, templateNamePositionHelper("template<class T> std::map<int, int> & foo() { static std::map<int, int> m; return m; }", 4));
|
|
ASSERT_EQUALS(11, templateNamePositionHelper("template<class T> const std::map<int, int> & foo() { static std::map<int, int> m; return m; }", 4));
|
|
// Class template members
|
|
ASSERT_EQUALS(4, templateNamePositionHelper(
|
|
"class A { template<class T> unsigned foo(); }; "
|
|
"template<class T> unsigned A::foo() { return 0; }", 19));
|
|
ASSERT_EQUALS(5, templateNamePositionHelper(
|
|
"class A { template<class T> const unsigned foo(); }; "
|
|
"template<class T> const unsigned A::foo() { return 0; }", 20));
|
|
ASSERT_EQUALS(7, templateNamePositionHelper(
|
|
"class A { class B { template<class T> const unsigned foo(); }; } ; "
|
|
"template<class T> const unsigned A::B::foo() { return 0; }", 25));
|
|
ASSERT_EQUALS(8, templateNamePositionHelper(
|
|
"class A { class B { template<class T> const unsigned * foo(); }; } ; "
|
|
"template<class T> const unsigned * A::B::foo() { return 0; }", 26));
|
|
ASSERT_EQUALS(9, templateNamePositionHelper(
|
|
"class A { class B { template<class T> const unsigned ** foo(); }; } ; "
|
|
"template<class T> const unsigned ** A::B::foo() { return 0; }", 27));
|
|
// Template class member
|
|
ASSERT_EQUALS(6, templateNamePositionHelper(
|
|
"template<class T> class A { A(); }; "
|
|
"template<class T> A<T>::A() {}", 18));
|
|
ASSERT_EQUALS(8, templateNamePositionHelper(
|
|
"template<class T, class U> class A { A(); }; "
|
|
"template<class T, class U> A<T, U>::A() {}", 24));
|
|
ASSERT_EQUALS(7, templateNamePositionHelper(
|
|
"template<class T> class A { unsigned foo(); }; "
|
|
"template<class T> unsigned A<T>::foo() { return 0; }", 19));
|
|
ASSERT_EQUALS(9, templateNamePositionHelper(
|
|
"template<class T, class U> class A { unsigned foo(); }; "
|
|
"template<class T, class U> unsigned A<T, U>::foo() { return 0; }", 25));
|
|
ASSERT_EQUALS(12, templateNamePositionHelper(
|
|
"template<> unsigned A<int, v<char> >::foo() { return 0; }", 2));
|
|
}
|
|
|
|
void expandSpecialized1() {
|
|
ASSERT_EQUALS("class A<int> { } ;", tok("template<> class A<int> {};"));
|
|
ASSERT_EQUALS("class A<int> : public B { } ;", tok("template<> class A<int> : public B {};"));
|
|
ASSERT_EQUALS("class A<int> { A<int> ( ) ; ~ A<int> ( ) ; } ;", tok("template<> class A<int> { A(); ~A(); };"));
|
|
ASSERT_EQUALS("class A<int> { A<int> ( ) { } ~ A<int> ( ) { } } ;", tok("template<> class A<int> { A() {} ~A() {} };"));
|
|
ASSERT_EQUALS("class A<int> { A<int> ( ) ; ~ A<int> ( ) ; } ; A<int> :: A<int> ( ) { } ~ A<int> :: A<int> ( ) { }",
|
|
tok("template<> class A<int> { A(); ~A(); }; A<int>::A() { } ~A<int>::A() {}"));
|
|
ASSERT_EQUALS("class A<int> { A<int> ( ) ; A<int> ( const A<int> & ) ; A<int> foo ( ) ; } ; A<int> :: A<int> ( ) { } A<int> :: A<int> ( const A<int> & ) { } A<int> A<int> :: foo ( ) { A<int> a ; return a ; }",
|
|
tok("template<> class A<int> { A(); A(const A &) ; A foo(); }; A<int>::A() { } A<int>::A(const A &) { } A<int> A<int>::foo() { A a; return a; }"));
|
|
}
|
|
|
|
void expandSpecialized2() {
|
|
{
|
|
const char code[] = "template <>\n"
|
|
"class C<float> {\n"
|
|
"public:\n"
|
|
" C() { }\n"
|
|
" C(const C &) { }\n"
|
|
" ~C() { }\n"
|
|
" C & operator=(const C &) { return *this; }\n"
|
|
"};\n"
|
|
"C<float> b;\n";
|
|
const char expected[] = "class C<float> { "
|
|
"public: "
|
|
"C<float> ( ) { } "
|
|
"C<float> ( const C<float> & ) { } "
|
|
"~ C<float> ( ) { } "
|
|
"C<float> & operator= ( const C<float> & ) { return * this ; } "
|
|
"} ; "
|
|
"C<float> b ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <>\n"
|
|
"class C<float> {\n"
|
|
"public:\n"
|
|
" C() { }\n"
|
|
" C(const C &) { }\n"
|
|
" ~C() { }\n"
|
|
" C & operator=(const C &) { return *this; }\n"
|
|
"};";
|
|
const char expected[] = "class C<float> { "
|
|
"public: "
|
|
"C<float> ( ) { } "
|
|
"C<float> ( const C<float> & ) { } "
|
|
"~ C<float> ( ) { } "
|
|
"C<float> & operator= ( const C<float> & ) { return * this ; } "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <>\n"
|
|
"class C<float> {\n"
|
|
"public:\n"
|
|
" C();\n"
|
|
" C(const C &);\n"
|
|
" ~C();\n"
|
|
" C & operator=(const C &);\n"
|
|
"};\n"
|
|
"C::C() { }\n"
|
|
"C::C(const C &) { }\n"
|
|
"C::~C() { }\n"
|
|
"C & C::operator=(const C &) { return *this; }\n"
|
|
"C<float> b;\n";
|
|
const char expected[] = "class C<float> { "
|
|
"public: "
|
|
"C<float> ( ) ; "
|
|
"C<float> ( const C<float> & ) ; "
|
|
"~ C<float> ( ) ; "
|
|
"C<float> & operator= ( const C<float> & ) ; "
|
|
"} ; "
|
|
"C<float> :: C<float> ( ) { } "
|
|
"C<float> :: C<float> ( const C<float> & ) { } "
|
|
"C<float> :: ~ C<float> ( ) { } "
|
|
"C<float> & C<float> :: operator= ( const C<float> & ) { return * this ; } "
|
|
"C<float> b ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template <>\n"
|
|
"class C<float> {\n"
|
|
"public:\n"
|
|
" C();\n"
|
|
" C(const C &);\n"
|
|
" ~C();\n"
|
|
" C & operator=(const C &);\n"
|
|
"};\n"
|
|
"C::C() { }\n"
|
|
"C::C(const C &) { }\n"
|
|
"C::~C() { }\n"
|
|
"C & C::operator=(const C &) { return *this; }";
|
|
const char expected[] = "class C<float> { "
|
|
"public: "
|
|
"C<float> ( ) ; "
|
|
"C<float> ( const C<float> & ) ; "
|
|
"~ C<float> ( ) ; "
|
|
"C<float> & operator= ( const C<float> & ) ; "
|
|
"} ; "
|
|
"C<float> :: C<float> ( ) { } "
|
|
"C<float> :: C<float> ( const C<float> & ) { } "
|
|
"C<float> :: ~ C<float> ( ) { } "
|
|
"C<float> & C<float> :: operator= ( const C<float> & ) { return * this ; }";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
}
|
|
|
|
void expandSpecialized3() { // #8671
|
|
const char code[] = "template <> struct OutputU16<unsigned char> final {\n"
|
|
" explicit OutputU16(std::basic_ostream<unsigned char> &t) : outputStream_(t) {}\n"
|
|
" void operator()(unsigned short) const;\n"
|
|
"private:\n"
|
|
" std::basic_ostream<unsigned char> &outputStream_;\n"
|
|
"};";
|
|
const char expected[] = "struct OutputU16<unsignedchar> final { "
|
|
"explicit OutputU16<unsignedchar> ( std :: basic_ostream < unsigned char > & t ) : outputStream_ ( t ) { } "
|
|
"void operator() ( unsigned short ) const ; "
|
|
"private: "
|
|
"std :: basic_ostream < unsigned char > & outputStream_ ; "
|
|
"} ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void expandSpecialized4() {
|
|
{
|
|
const char code[] = "template<> class C<char> { };\n"
|
|
"map<int> m;";
|
|
const char expected[] = "class C<char> { } ; "
|
|
"map < int > m ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<> class C<char> { };\n"
|
|
"map<int> m;\n"
|
|
"C<char> c;";
|
|
const char expected[] = "class C<char> { } ; "
|
|
"map < int > m ; "
|
|
"C<char> c ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<typename T> class C { };\n"
|
|
"template<> class C<char> { };\n"
|
|
"map<int> m;\n";
|
|
const char expected[] = "template < typename T > class C { } ; "
|
|
"class C<char> { } ; "
|
|
"map < int > m ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<typename T> class C { };\n"
|
|
"template<> class C<char> { };\n"
|
|
"map<int> m;\n"
|
|
"C<int> i;";
|
|
const char expected[] = "class C<int> ; "
|
|
"class C<char> { } ; "
|
|
"map < int > m ; "
|
|
"C<int> i ; "
|
|
"class C<int> { } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
{
|
|
const char code[] = "template<typename T> class C { };\n"
|
|
"template<> class C<char> { };\n"
|
|
"map<int> m;\n"
|
|
"C<int> i;\n"
|
|
"C<char> c;";
|
|
const char expected[] = "class C<int> ; "
|
|
"class C<char> { } ; "
|
|
"map < int > m ; "
|
|
"C<int> i ; "
|
|
"C<char> c ; "
|
|
"class C<int> { } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
}
|
|
|
|
void templateAlias1() {
|
|
const char code[] = "template<class T, int N> struct Foo {};\n"
|
|
"template<class T> using Bar = Foo<T,3>;\n"
|
|
"Bar<int> b;\n";
|
|
|
|
const char expected[] = "struct Foo<int,3> ; "
|
|
"Foo<int,3> b ; "
|
|
"struct Foo<int,3> { } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void templateAlias2() {
|
|
const char code[] = "namespace A { template<class T, int N> struct Foo {}; }\n"
|
|
"template<class T> using Bar = A::Foo<T,3>;\n"
|
|
"Bar<int> b;\n";
|
|
|
|
const char expected[] = "namespace A { struct Foo<int,3> ; } "
|
|
"; "
|
|
"A :: Foo<int,3> b ; "
|
|
"struct A :: Foo<int,3> { } ;";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void templateAlias3() { // #8315
|
|
const char code[] = "template <int> struct Tag {};\n"
|
|
"template <int ID> using SPtr = std::shared_ptr<void(Tag<ID>)>;\n"
|
|
"SPtr<0> s;";
|
|
const char expected[] = "struct Tag<0> ; "
|
|
"std :: shared_ptr < void ( Tag<0> ) > s ; "
|
|
"struct Tag<0> { } ;";
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
}
|
|
|
|
void templateAlias4() { // #9070
|
|
const char code[] = "template <class T>\n"
|
|
"using IntrusivePtr = boost::intrusive_ptr<T>;\n"
|
|
"template <class T> class Vertex { };\n"
|
|
"IntrusivePtr<Vertex<int>> p;";
|
|
const char expected[] = "; "
|
|
"class Vertex<int> ; "
|
|
"boost :: intrusive_ptr < Vertex<int> > p ;"
|
|
"class Vertex<int> { } ;";
|
|
const char actual[] = "; "
|
|
"template < class T > class Vertex { } ; "
|
|
"boost :: intrusive_ptr < T > p ;";
|
|
TODO_ASSERT_EQUALS(expected, actual, tok(code));
|
|
}
|
|
|
|
unsigned int instantiateMatch(const char code[], const std::size_t numberOfArguments, const char patternAfter[]) {
|
|
Tokenizer tokenizer(&settings, this);
|
|
|
|
std::istringstream istr(code);
|
|
tokenizer.tokenize(istr, "test.cpp", "");
|
|
|
|
return TemplateSimplifier::instantiateMatch(tokenizer.tokens(), numberOfArguments, patternAfter);
|
|
}
|
|
|
|
void instantiateMatch() {
|
|
// Ticket #8175
|
|
ASSERT_EQUALS(false,
|
|
instantiateMatch("ConvertHelper < From, To > c ;",
|
|
2, ":: %name% ("));
|
|
ASSERT_EQUALS(true,
|
|
instantiateMatch("ConvertHelper < From, To > :: Create ( ) ;",
|
|
2, ":: %name% ("));
|
|
ASSERT_EQUALS(false,
|
|
instantiateMatch("integral_constant < bool, sizeof ( ConvertHelper < From, To > :: Create ( ) ) > ;",
|
|
2, ":: %name% ("));
|
|
ASSERT_EQUALS(false,
|
|
instantiateMatch("integral_constant < bool, sizeof ( ns :: ConvertHelper < From, To > :: Create ( ) ) > ;",
|
|
2, ":: %name% ("));
|
|
}
|
|
|
|
void templateParameterWithoutName() {
|
|
ASSERT_EQUALS(1U, templateParameters("template<typename = void> struct s;"));
|
|
ASSERT_EQUALS(1U, templateParameters("template<template<typename = float> typename T> struct A {\n"
|
|
" void f();\n"
|
|
" void g();\n"
|
|
"};n"));
|
|
}
|
|
|
|
void templateTypeDeduction1() { // #8962
|
|
const char code[] = "template<typename T>\n"
|
|
"void f(T n) { (void)n; }\n"
|
|
"static void func() {\n"
|
|
" f(0);\n"
|
|
" f(0u);\n"
|
|
" f(0U);\n"
|
|
" f(0l);\n"
|
|
" f(0L);\n"
|
|
" f(0ul);\n"
|
|
" f(0UL);\n"
|
|
" f(0ll);\n"
|
|
" f(0LL);\n"
|
|
" f(0ull);\n"
|
|
" f(0ULL);\n"
|
|
" f(0.0);\n"
|
|
" f(0.0f);\n"
|
|
" f(0.0F);\n"
|
|
" f(0.0l);\n"
|
|
" f(0.0L);\n"
|
|
" f('c');\n"
|
|
" f(L'c');\n"
|
|
" f(\"string\");\n"
|
|
" f(L\"string\");\n"
|
|
" f(true);\n"
|
|
" f(false);\n"
|
|
"}";
|
|
const char expected[] = "void f<int> ( int n ) ; "
|
|
"void f<unsignedint> ( unsigned int n ) ; "
|
|
"void f<long> ( long n ) ; "
|
|
"void f<unsignedlong> ( unsigned long n ) ; "
|
|
"void f<longlong> ( long long n ) ; "
|
|
"void f<unsignedlonglong> ( unsigned long long n ) ; "
|
|
"void f<double> ( double n ) ; "
|
|
"void f<float> ( float n ) ; "
|
|
"void f<longdouble> ( long double n ) ; "
|
|
"void f<char> ( char n ) ; "
|
|
"void f<wchar_t> ( wchar_t n ) ; "
|
|
"void f<constchar*> ( const char * n ) ; "
|
|
"void f<constwchar_t*> ( const wchar_t * n ) ; "
|
|
"void f<bool> ( bool n ) ; "
|
|
"static void func ( ) { "
|
|
"f<int> ( 0 ) ; "
|
|
"f<unsignedint> ( 0u ) ; "
|
|
"f<unsignedint> ( 0U ) ; "
|
|
"f<long> ( 0l ) ; "
|
|
"f<long> ( 0L ) ; "
|
|
"f<unsignedlong> ( 0ul ) ; "
|
|
"f<unsignedlong> ( 0UL ) ; "
|
|
"f<longlong> ( 0ll ) ; "
|
|
"f<longlong> ( 0LL ) ; "
|
|
"f<unsignedlonglong> ( 0ull ) ; "
|
|
"f<unsignedlonglong> ( 0ULL ) ; "
|
|
"f<double> ( 0.0 ) ; "
|
|
"f<float> ( 0.0f ) ; "
|
|
"f<float> ( 0.0F ) ; "
|
|
"f<longdouble> ( 0.0l ) ; "
|
|
"f<longdouble> ( 0.0L ) ; "
|
|
"f<char> ( 'c' ) ; "
|
|
"f<wchar_t> ( L'c' ) ; "
|
|
"f<constchar*> ( \"string\" ) ; "
|
|
"f<constwchar_t*> ( L\"string\" ) ; "
|
|
"f<bool> ( true ) ; "
|
|
"f<bool> ( false ) ; "
|
|
"} "
|
|
"void f<int> ( int n ) { ( void ) n ; } "
|
|
"void f<unsignedint> ( unsigned int n ) { ( void ) n ; } "
|
|
"void f<long> ( long n ) { ( void ) n ; } "
|
|
"void f<unsignedlong> ( unsigned long n ) { ( void ) n ; } "
|
|
"void f<longlong> ( long long n ) { ( void ) n ; } "
|
|
"void f<unsignedlonglong> ( unsigned long long n ) { ( void ) n ; } "
|
|
"void f<double> ( double n ) { ( void ) n ; } "
|
|
"void f<float> ( float n ) { ( void ) n ; } "
|
|
"void f<longdouble> ( long double n ) { ( void ) n ; } "
|
|
"void f<char> ( char n ) { ( void ) n ; } "
|
|
"void f<wchar_t> ( wchar_t n ) { ( void ) n ; } "
|
|
"void f<constchar*> ( const char * n ) { ( void ) n ; } "
|
|
"void f<constwchar_t*> ( const wchar_t * n ) { ( void ) n ; } "
|
|
"void f<bool> ( bool n ) { ( void ) n ; }";
|
|
|
|
ASSERT_EQUALS(expected, tok(code));
|
|
ASSERT_EQUALS("", errout.str());
|
|
}
|
|
|
|
void templateTypeDeduction2() {
|
|
const char code[] = "template<typename T, typename U>\n"
|
|
"void f(T t, U u) { }\n"
|
|
"static void func() {\n"
|
|
" f(0, 0.0);\n"
|
|
" f(0.0, 0);\n"
|
|
"}";
|
|
|
|
const char expected[] = "void f<int,double> ( int t , double u ) ; "
|
|
"void f<double,int> ( double t , int u ) ; "
|
|
"static void func ( ) { "
|
|
"f<int,double> ( 0 , 0.0 ) ; "
|
|
"f<double,int> ( 0.0, 0 ) ; "
|
|
"void f<int,double> ( int t , double u ) { } "
|
|
"void f<double,int> ( double t , int u ) { } ";
|
|
|
|
const char actual[] = "template < typename T , typename U > "
|
|
"void f ( T t , U u ) { } "
|
|
"static void func ( ) { "
|
|
"f ( 0 , 0.0 ) ; "
|
|
"f ( 0.0 , 0 ) ; "
|
|
"}";
|
|
|
|
TODO_ASSERT_EQUALS(expected, actual, tok(code));
|
|
}
|
|
|
|
void simplifyTemplateArgs() {
|
|
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < ( 2 ) >;"));
|
|
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < 1 + 1 >;"));
|
|
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < ( 1 + 1 ) >;"));
|
|
|
|
ASSERT_EQUALS("foo<2,2> = 4 ; foo<2,2> ;", tok("template<int N, int M> foo = N * M; foo < ( 2 ), ( 2 ) >;"));
|
|
ASSERT_EQUALS("foo<2,2> = 4 ; foo<2,2> ;", tok("template<int N, int M> foo = N * M; foo < 1 + 1, 1 + 1 >;"));
|
|
ASSERT_EQUALS("foo<2,2> = 4 ; foo<2,2> ;", tok("template<int N, int M> foo = N * M; foo < ( 1 + 1 ), ( 1 + 1 ) >;"));
|
|
|
|
ASSERT_EQUALS("foo<true> = true ; foo<true> ;", tok("template<bool N> foo = N; foo < true ? true : false >;"));
|
|
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < false ? true : false >;"));
|
|
ASSERT_EQUALS("foo<true> = true ; foo<true> ;", tok("template<bool N> foo = N; foo < 1 ? true : false >;"));
|
|
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < 0 ? true : false >;"));
|
|
ASSERT_EQUALS("foo<true> = true ; foo<true> ;", tok("template<bool N> foo = N; foo < (1 + 1 ) ? true : false >;"));
|
|
ASSERT_EQUALS("foo<false> = false ; foo<false> ;", tok("template<bool N> foo = N; foo < ( 1 - 1) ? true : false >;"));
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_TEST(TestSimplifyTemplate)
|