Modify template simplifier to add forward declarations of some templa… (#1489)

* Modify template simplifier to add forward declarations of some template functions so symbol database can make sense of the expanded templates.

* Fix travis.
This commit is contained in:
IOBYTE 2018-11-23 05:36:09 -05:00 committed by Daniel Marjamäki
parent ef05be2600
commit 358f0c473d
4 changed files with 272 additions and 33 deletions

View File

@ -53,8 +53,8 @@ namespace {
}; };
} }
TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s, const std::string &n) : TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s, const std::string &n, const Token *nt) :
token(tok), scope(s), name(n) token(tok), scope(s), name(n), nameToken(nt)
{ {
token->hasTemplateSimplifierPointer(true); token->hasTemplateSimplifierPointer(true);
} }
@ -513,14 +513,14 @@ bool TemplateSimplifier::getTemplateDeclarations()
else if (tok2->str() == ";") { else if (tok2->str() == ";") {
const int namepos = getTemplateNamePosition(parmEnd, true); const int namepos = getTemplateNamePosition(parmEnd, true);
if (namepos > 0) if (namepos > 0)
mTemplateForwardDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos)); mTemplateForwardDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos), parmEnd->tokAt(namepos));
break; break;
} }
// Implementation => add to mTemplateDeclarations // Implementation => add to mTemplateDeclarations
else if (tok2->str() == "{") { else if (tok2->str() == "{") {
const int namepos = getTemplateNamePosition(parmEnd, false); const int namepos = getTemplateNamePosition(parmEnd, false);
if (namepos > 0) if (namepos > 0)
mTemplateDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos)); mTemplateDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos), parmEnd->tokAt(namepos));
break; break;
} }
} }
@ -549,7 +549,7 @@ void TemplateSimplifier::getTemplateInstantiations()
const Token *tok2 = Token::findmatch(tok, "{|;"); const Token *tok2 = Token::findmatch(tok, "{|;");
if (tok2 && tok2->str() == "{") if (tok2 && tok2->str() == "{")
tok = tok2->link(); tok = tok2->link();
} else if (Token::Match(tok->previous(), "[({};=] %name% ::|<") || } else if (Token::Match(tok->previous(), "(|{|}|;|=|>|<<|:|. %name% ::|<") ||
Token::Match(tok->previous(), "%type% %name% ::|<") || Token::Match(tok->previous(), "%type% %name% ::|<") ||
Token::Match(tok->tokAt(-2), "[,:] private|protected|public %name% ::|<")) { Token::Match(tok->tokAt(-2), "[,:] private|protected|public %name% ::|<")) {
@ -570,7 +570,7 @@ void TemplateSimplifier::getTemplateInstantiations()
for (; tok2 && tok2 != tok; tok2 = tok2->previous()) { for (; tok2 && tok2 != tok; tok2 = tok2->previous()) {
if (Token::Match(tok2, ", %name% <") && if (Token::Match(tok2, ", %name% <") &&
templateParameters(tok2->tokAt(2))) { templateParameters(tok2->tokAt(2))) {
mTemplateInstantiations.emplace_back(tok2->next(), getScopeName(scopeList), tok2->strAt(1)); mTemplateInstantiations.emplace_back(tok2->next(), getScopeName(scopeList), tok2->strAt(1), tok2->tokAt(1));
} else if (Token::Match(tok2->next(), "class|struct")) } else if (Token::Match(tok2->next(), "class|struct"))
const_cast<Token *>(tok2)->deleteNext(); const_cast<Token *>(tok2)->deleteNext();
@ -583,11 +583,11 @@ void TemplateSimplifier::getTemplateInstantiations()
const std::string fullName = scopeName + (scopeName.empty()?"":" :: ") + tok->str(); const std::string fullName = scopeName + (scopeName.empty()?"":" :: ") + tok->str();
const std::list<TokenAndName>::const_iterator it = std::find_if(mTemplateDeclarations.begin(), mTemplateDeclarations.end(), FindName(fullName)); const std::list<TokenAndName>::const_iterator it = std::find_if(mTemplateDeclarations.begin(), mTemplateDeclarations.end(), FindName(fullName));
if (it != mTemplateDeclarations.end()) { if (it != mTemplateDeclarations.end()) {
mTemplateInstantiations.emplace_back(tok, getScopeName(scopeList), fullName); mTemplateInstantiations.emplace_back(tok, getScopeName(scopeList), fullName, tok);
break; break;
} else { } else {
if (scopeName.empty()) { if (scopeName.empty()) {
mTemplateInstantiations.emplace_back(tok, getScopeName(scopeList), scopeName1 + (scopeName1.empty()?"":" :: ") + tok->str()); mTemplateInstantiations.emplace_back(tok, getScopeName(scopeList), scopeName1 + (scopeName1.empty()?"":" :: ") + tok->str(), tok);
break; break;
} }
const std::string::size_type pos = scopeName.rfind(" :: "); const std::string::size_type pos = scopeName.rfind(" :: ");
@ -831,7 +831,7 @@ void TemplateSimplifier::simplifyTemplateAliases()
mTemplateInstantiations.end(), mTemplateInstantiations.end(),
FindToken(tok1)); FindToken(tok1));
if (it != mTemplateInstantiations.end()) if (it != mTemplateInstantiations.end())
mTemplateInstantiations.emplace_back(tok2, it->scope, it->name); mTemplateInstantiations.emplace_back(tok2, it->scope, it->name, it->nameToken);
} }
continue; continue;
} }
@ -1016,12 +1016,66 @@ void TemplateSimplifier::expandTemplate(
const Token *endOfTemplateDefinition = nullptr; const Token *endOfTemplateDefinition = nullptr;
const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken)); const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken));
const bool isClass = Token::Match(templateDeclarationToken->next(), "class|struct|union %name% <|{|:"); const bool isClass = Token::Match(templateDeclarationToken->next(), "class|struct|union %name% <|{|:");
const bool isFunction = templateDeclarationNameToken->strAt(1) == "(";
// add forward declaration for classes // add forward declarations
if (copy && isClass) { if (copy && isClass) {
templateDeclaration.token->insertToken(templateDeclarationToken->strAt(1), "", true); templateDeclaration.token->insertToken(templateDeclarationToken->strAt(1), "", true);
templateDeclaration.token->insertToken(newName, "", true); templateDeclaration.token->insertToken(newName, "", true);
templateDeclaration.token->insertToken(";", "", true); templateDeclaration.token->insertToken(";", "", true);
} else if (copy && isFunction) {
// check if this is an explicit instantiation
Token * temp = templateInstantiation.token;
while (temp && !Token::Match(temp->previous(), "}|;"))
temp = temp->previous();
if (Token::Match(temp, "template !!<")) {
// just delete "template"
deleteToken(temp);
} else {
// add forward declaration
Token * dst = templateDeclaration.token;
Token * start;
Token * end;
auto it = mTemplateForwardDeclarationsMap.find(dst);
if (it != mTemplateForwardDeclarationsMap.end()) {
dst = it->second;
const Token * temp1 = dst->tokAt(1)->findClosingBracket();
const Token * temp2 = temp1->tokAt(getTemplateNamePosition(temp1));
start = temp1->next();
end = temp2->linkAt(1)->next();
} else {
start = templateDeclarationToken->next();
end = templateDeclarationNameToken->linkAt(1)->next();
}
std::map<const Token *, Token *> links;
while (start && start != end) {
unsigned int itype = 0;
while (itype < typeParametersInDeclaration.size() && typeParametersInDeclaration[itype]->str() != start->str())
++itype;
if (itype < typeParametersInDeclaration.size()) {
dst->insertToken(mTypesUsedInTemplateInstantiation[itype]->str(), "", true);
dst->previous()->isTemplateArg(true);
} else {
if (start->str() == templateDeclarationNameToken->str())
dst->insertToken(newName, "", true);
else
dst->insertToken(start->str(), "", true);
if (start->link()) {
if (Token::Match(start, "[|{|(")) {
links[start->link()] = dst->previous();
} else if (Token::Match(start, "]|}|)")) {
Token::createMutualLinks(links[start], dst->previous());
links.erase(start);
}
}
}
start = start->next();
}
dst->insertToken(";", "", true);
}
} }
for (Token *tok3 = mTokenList.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) { for (Token *tok3 = mTokenList.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
@ -1220,7 +1274,7 @@ void TemplateSimplifier::expandTemplate(
std::string name = tok3->str(); std::string name = tok3->str();
for (const Token *prev = tok3->tokAt(-2); Token::Match(prev, "%name% ::"); prev = prev->tokAt(-2)) for (const Token *prev = tok3->tokAt(-2); Token::Match(prev, "%name% ::"); prev = prev->tokAt(-2))
name = prev->str() + " :: " + name; name = prev->str() + " :: " + name;
mTemplateInstantiations.emplace_back(mTokenList.back(), getScopeName(scopeInfo), name); mTemplateInstantiations.emplace_back(mTokenList.back(), getScopeName(scopeInfo), name, tok3);
} }
// link() newly tokens manually // link() newly tokens manually
@ -1757,8 +1811,8 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
startToken = startToken->tokAt(-2); startToken = startToken->tokAt(-2);
} }
if (Token::Match(startToken->previous(), "[;{}=]") && if (Token::Match(startToken->previous(), ";|{|}|=|const") &&
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%"))) (!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*|&| %name%")))
continue; continue;
// New type.. // New type..
@ -1823,8 +1877,8 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
startToken = startToken->tokAt(-2); startToken = startToken->tokAt(-2);
} }
if (Token::Match(startToken->previous(), "[;{}=]") && if (Token::Match(startToken->previous(), ";|{|}|=|const") &&
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*| %name%"))) (!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : "*|&| %name%")))
return false; return false;
// already simplified // already simplified
@ -1988,8 +2042,35 @@ void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
// make sure the number of arguments match // make sure the number of arguments match
if (params1.size() == params2.size()) { if (params1.size() == params2.size()) {
std::string declName = decl.scope;
if (!declName.empty())
declName += " :: ";
if (decl.nameToken->strAt(-1) == "::") {
const Token * start = decl.nameToken;
while (Token::Match(start->tokAt(-2), "%name% ::"))
start = start->tokAt(-2);
while (start != decl.nameToken) {
declName += (start->str() + " ");
start = start->next();
}
}
declName += decl.name;
std::string forwardDeclName = forwardDecl.scope;
if (!forwardDeclName.empty())
forwardDeclName += " :: ";
forwardDeclName += forwardDecl.name;
// make sure the scopes and names match // make sure the scopes and names match
if (forwardDecl.scope == decl.scope && forwardDecl.name == decl.name) { if (forwardDeclName == declName) {
// save forward declaration for lookup later
if ((decl.nameToken->strAt(1) == "(" && forwardDecl.nameToken->strAt(1) == "(") ||
(decl.nameToken->strAt(1) == "{" && forwardDecl.nameToken->strAt(1) == ";")) {
mTemplateForwardDeclarationsMap[decl.token] = forwardDecl.token;
}
for (size_t k = 0; k < params1.size(); k++) { for (size_t k = 0; k < params1.size(); k++) {
// copy default value to declaration if not present // copy default value to declaration if not present
if (params1[k]->strAt(1) == "=" && params2[k]->strAt(1) != "=") { if (params1[k]->strAt(1) == "=" && params2[k]->strAt(1) != "=") {
@ -2018,6 +2099,7 @@ void TemplateSimplifier::simplifyTemplates(
if (i) { if (i) {
mTemplateDeclarations.clear(); mTemplateDeclarations.clear();
mTemplateForwardDeclarations.clear(); mTemplateForwardDeclarations.clear();
mTemplateForwardDeclarationsMap.clear();
mTemplateInstantiations.clear(); mTemplateInstantiations.clear();
mInstantiatedTemplates.clear(); mInstantiatedTemplates.clear();
} }

View File

@ -26,6 +26,7 @@
#include <ctime> #include <ctime>
#include <list> #include <list>
#include <map>
#include <set> #include <set>
#include <string> #include <string>
#include <vector> #include <vector>
@ -68,13 +69,14 @@ public:
* Token and its full scopename * Token and its full scopename
*/ */
struct TokenAndName { struct TokenAndName {
TokenAndName(Token *tok, const std::string &s, const std::string &n); TokenAndName(Token *tok, const std::string &s, const std::string &n, const Token *nt);
bool operator == (const TokenAndName & rhs) const { bool operator == (const TokenAndName & rhs) const {
return token == rhs.token && scope == rhs.scope && name == rhs.name; return token == rhs.token && scope == rhs.scope && name == rhs.name && nameToken == rhs.nameToken;
} }
Token *token; Token *token;
std::string scope; std::string scope;
std::string name; std::string name;
const Token *nameToken;
}; };
/** /**
@ -263,6 +265,7 @@ private:
std::list<TokenAndName> mTemplateDeclarations; std::list<TokenAndName> mTemplateDeclarations;
std::list<TokenAndName> mTemplateForwardDeclarations; std::list<TokenAndName> mTemplateForwardDeclarations;
std::map<Token *, Token *> mTemplateForwardDeclarationsMap;
std::list<TokenAndName> mTemplateInstantiations; std::list<TokenAndName> mTemplateInstantiations;
std::list<TokenAndName> mInstantiatedTemplates; std::list<TokenAndName> mInstantiatedTemplates;
std::list<TokenAndName> mMemberFunctionsToDelete; std::list<TokenAndName> mMemberFunctionsToDelete;

View File

@ -109,6 +109,14 @@ private:
TEST_CASE(template69); // #8791 TEST_CASE(template69); // #8791
TEST_CASE(template70); // #5289 TEST_CASE(template70); // #5289
TEST_CASE(template71); // #8821 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(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..}; 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_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_enum); // #6299 Syntax error in complex enum declaration (including template)
@ -184,7 +192,8 @@ private:
const char code[] = "template <class T> void f(T val) { T a; }\n" const char code[] = "template <class T> void f(T val) { T a; }\n"
"f<int>(10);"; "f<int>(10);";
const char expected[] = "f<int> ( 10 ) ; " const char expected[] = "void f<int> ( int val ) ; "
"f<int> ( 10 ) ; "
"void f<int> ( int val ) { }"; "void f<int> ( int val ) { }";
ASSERT_EQUALS(expected, tok(code)); ASSERT_EQUALS(expected, tok(code));
@ -374,7 +383,8 @@ private:
"}\n"; "}\n";
// The expected result.. // The expected result..
const char expected[] = "void f ( ) " const char expected[] = "int * foo<3,int> ( ) ; "
"void f ( ) "
"{" "{"
" foo<3,int> ( ) ; " " foo<3,int> ( ) ; "
"} " "} "
@ -392,7 +402,8 @@ private:
"}\n"; "}\n";
// The expected result.. // The expected result..
const char expected[] = "void f ( ) " const char expected[] = "char * foo<3,char> ( ) ; "
"void f ( ) "
"{" "{"
" char * p ; p = foo<3,char> ( ) ; " " char * p ; p = foo<3,char> ( ) ; "
"} " "} "
@ -484,7 +495,9 @@ private:
"}\n"; "}\n";
// The expected result.. // The expected result..
const char expected[] = "void a<0> ( ) { } " const char expected[] = "void a<2> ( ) ; "
"void a<1> ( ) ; "
"void a<0> ( ) { } "
"int main ( ) " "int main ( ) "
"{ a<2> ( ) ; return 0 ; } " "{ a<2> ( ) ; return 0 ; } "
"void a<2> ( ) { a<1> ( ) ; } " "void a<2> ( ) { a<1> ( ) ; } "
@ -522,7 +535,9 @@ private:
" return 0;\n" " return 0;\n"
"}\n"; "}\n";
const char expected[] = "int main ( ) { b<2> ( ) ; return 0 ; } " const char expected[] = "void a<2> ( ) ; "
"void b<2> ( ) ; "
"int main ( ) { b<2> ( ) ; return 0 ; } "
"void b<2> ( ) { a<2> ( ) ; } " "void b<2> ( ) { a<2> ( ) ; } "
"void a<2> ( ) { }"; "void a<2> ( ) { }";
@ -566,7 +581,8 @@ private:
"}\n"; "}\n";
// The expected result.. // The expected result..
const char expected[] = "void f ( ) " const char expected[] = "char & foo<char> ( ) ; "
"void f ( ) "
"{" "{"
" char p ; p = foo<char> ( ) ; " " char p ; p = foo<char> ( ) ; "
"} " "} "
@ -653,7 +669,8 @@ private:
" std::cout << (foo<double>());\n" " std::cout << (foo<double>());\n"
"}"; "}";
const char expected[] = "void bar ( ) {" const char expected[] = "void foo<double> ( ) ; "
"void bar ( ) {"
" std :: cout << ( foo<double> ( ) ) ; " " std :: cout << ( foo<double> ( ) ) ; "
"} " "} "
"void foo<double> ( ) { }"; "void foo<double> ( ) { }";
@ -906,7 +923,9 @@ private:
const char code2[] = "template<class T> T f(T t) { return t; }\n" const char code2[] = "template<class T> T f(T t) { return t; }\n"
"int x() { return f<int>(123); }"; "int x() { return f<int>(123); }";
ASSERT_EQUALS("int x ( ) { return f<int> ( 123 ) ; } int f<int> ( int t ) { return t ; }", tok(code2)); 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 cpcheck aborts in ext-blocks.cpp (clang testcode) void template42() { // #4878 cpcheck aborts in ext-blocks.cpp (clang testcode)
@ -1123,7 +1142,8 @@ private:
"void foo() {\n" "void foo() {\n"
" TestArithmetic<int>();\n" " TestArithmetic<int>();\n"
"}"; "}";
const char exp[] = "void foo ( ) {" const char exp[] = "void TestArithmetic<int> ( ) ; "
"void foo ( ) {"
" TestArithmetic<int> ( ) ; " " TestArithmetic<int> ( ) ; "
"} " "} "
"void TestArithmetic<int> ( ) {" "void TestArithmetic<int> ( ) {"
@ -1153,6 +1173,7 @@ private:
"struct Factorial<2> ; " "struct Factorial<2> ; "
"struct Factorial<1> ; " "struct Factorial<1> ; "
"struct Factorial<0> { enum FacHelper { value = 1 } ; } ; " "struct Factorial<0> { enum FacHelper { value = 1 } ; } ; "
"int diagonalGroupTest<4> ( ) ; "
"int main ( ) { return diagonalGroupTest<4> ( ) ; } " "int main ( ) { return diagonalGroupTest<4> ( ) ; } "
"int diagonalGroupTest<4> ( ) { return Factorial<4> :: value ; } " "int diagonalGroupTest<4> ( ) { return Factorial<4> :: value ; } "
"struct Factorial<4> { enum FacHelper { value = 4 * Factorial<3> :: value } ; } ; " "struct Factorial<4> { enum FacHelper { value = 4 * Factorial<3> :: value } ; } ; "
@ -1170,6 +1191,7 @@ private:
"void j() { h<int>(); }"; "void j() { h<int>(); }";
const char exp[] = "struct S<int> ; " const char exp[] = "struct S<int> ; "
"template < typename T > void f ( ) { } " // <- TODO: This template is not expanded "template < typename T > void f ( ) { } " // <- TODO: This template is not expanded
"void h<int> ( ) ; "
"void j ( ) { h<int> ( ) ; } " "void j ( ) { h<int> ( ) ; } "
"void h<int> ( ) { f < S<int> :: type ( 0 ) > ( ) ; } " "void h<int> ( ) { f < S<int> :: type ( 0 ) > ( ) ; } "
"struct S<int> { } ;"; "struct S<int> { } ;";
@ -1327,6 +1349,7 @@ private:
"};"; "};";
const char exp [] = "class Test { " const char exp [] = "class Test { "
"int test ; " "int test ; "
"int lookup<int> ( ) ; "
"int Fun ( ) { return lookup<int> ( ) ; } " "int Fun ( ) { return lookup<int> ( ) ; } "
"} ; " "} ; "
"int Test :: lookup<int> ( ) { return test ; }"; "int Test :: lookup<int> ( ) { return test ; }";
@ -1373,6 +1396,127 @@ private:
ASSERT_EQUALS(exp, tok(code)); 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 & v , const float l , const float u ) ; "
"void keep_range<int> ( int & v , const int l , const int u ) ; "
"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 > > & v ) ; "
"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 > > & v ) ; "
"} "
"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 template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..}; void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
const char code[] = "template <typename T> struct C {};\n" const char code[] = "template <typename T> struct C {};\n"
"template <typename T> struct S {a};\n" "template <typename T> struct S {a};\n"
@ -1761,7 +1905,9 @@ private:
" template<class T> void Fred(T value) { }\n" " template<class T> void Fred(T value) { }\n"
"}\n" "}\n"
"Fred<int>(123);"; "Fred<int>(123);";
ASSERT_EQUALS("namespace { } " ASSERT_EQUALS("namespace { "
"void Fred<int> ( int value ) ; "
"} "
"Fred<int> ( 123 ) ; " "Fred<int> ( 123 ) ; "
"void Fred<int> ( int value ) { }", tok(code)); "void Fred<int> ( int value ) { }", tok(code));
} }
@ -1985,9 +2131,9 @@ private:
" }\n" " }\n"
" void SomeFunction() { }\n" " void SomeFunction() { }\n"
"private:\n" "private:\n"
" template< typename T > void TemplatedMethod();\n" " template< typename T > T TemplatedMethod(T);\n"
"};\n" "};\n"
"template< typename T > void TestClass::TemplatedMethod() { }\n" "template< typename T > T TestClass::TemplatedMethod(T t) { return t; }\n"
"}"; "}";
ASSERT_EQUALS("namespace MyNamespace { " ASSERT_EQUALS("namespace MyNamespace { "
"class TestClass { " "class TestClass { "
@ -1998,9 +2144,10 @@ private:
"} " "} "
"void SomeFunction ( ) { } " "void SomeFunction ( ) { } "
"private: " "private: "
"template < typename T > void TemplatedMethod ( ) ; " "int TemplatedMethod<int> ( int ) ; "
"template < typename T > T TemplatedMethod ( T ) ; " // this should be removed
"} ; " "} ; "
"} void MyNamespace :: TestClass :: TemplatedMethod<int> ( ) { }", tok(code)); "} int MyNamespace :: TestClass :: TemplatedMethod<int> ( int t ) { return t ; }", tok(code));
} }
unsigned int templateParameters(const char code[]) { unsigned int templateParameters(const char code[]) {

View File

@ -5041,7 +5041,14 @@ private:
"{\n" "{\n"
" fn2<int>();\n" " fn2<int>();\n"
"}\n"; "}\n";
ASSERT_EQUALS("int main ( )\n{\nfn2<int> ( ) ;\n} void fn2<int> ( int t = [ ] { return 1 ; } ( ) )\n{ }", tokenizeAndStringify(code)); ASSERT_EQUALS("void fn2<int> ( int t = [ ] { return 1 ; } ( ) ) ;\n"
"\n"
"\n"
"int main ( )\n"
"{\n"
"fn2<int> ( ) ;\n"
"} void fn2<int> ( int t = [ ] { return 1 ; } ( ) )\n"
"{ }", tokenizeAndStringify(code));
} }
void cpp0xtemplate2() { void cpp0xtemplate2() {