parent
54d6625ffb
commit
7875555b03
|
@ -497,6 +497,9 @@ bool TemplateSimplifier::getTemplateDeclarations()
|
|||
tok2 = tok2->link();
|
||||
else if (tok2->str() == ")")
|
||||
break;
|
||||
// skip decltype(...)
|
||||
else if (Token::Match(tok2, "decltype ("))
|
||||
tok2 = tok2->linkAt(1);
|
||||
// Declaration => add to mTemplateForwardDeclarations
|
||||
else if (tok2->str() == ";") {
|
||||
const int namepos = getTemplateNamePosition(parmEnd, true);
|
||||
|
@ -891,7 +894,14 @@ bool TemplateSimplifier::getTemplateNamePositionTemplateFunction(const Token *to
|
|||
while (tok && tok->next()) {
|
||||
if (Token::Match(tok->next(), ";|{"))
|
||||
return false;
|
||||
else if (Token::Match(tok->next(), "%type% <")) {
|
||||
// skip decltype(...)
|
||||
else if (Token::Match(tok, "decltype (")) {
|
||||
const Token * end = tok->linkAt(1);
|
||||
while (tok && tok != end) {
|
||||
tok = tok->next();
|
||||
namepos++;
|
||||
}
|
||||
} else if (Token::Match(tok->next(), "%type% <")) {
|
||||
const Token *closing = tok->tokAt(2)->findClosingBracket();
|
||||
if (closing) {
|
||||
if (closing->strAt(1) == "(" && mTokenizer->isFunctionHead(closing->tokAt(2), ";|{|:"))
|
||||
|
@ -984,15 +994,19 @@ void TemplateSimplifier::expandTemplate(
|
|||
const Token *endOfTemplateDefinition = nullptr;
|
||||
const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken));
|
||||
const bool isClass = Token::Match(templateDeclarationToken->next(), "class|struct|union %name% <|{|:");
|
||||
const bool isFunction = templateDeclarationNameToken->strAt(1) == "(";
|
||||
const bool isFunction = templateDeclarationNameToken->strAt(1) == "(" ||
|
||||
(templateDeclarationNameToken->strAt(1) == "<" && templateDeclarationNameToken->next()->findClosingBracket()->strAt(1) == "(");
|
||||
const bool isSpecialization = Token::Match(templateDeclaration.token, "template < >");
|
||||
|
||||
// add forward declarations
|
||||
if (copy && isClass) {
|
||||
templateDeclaration.token->insertToken(templateDeclarationToken->strAt(1), "", true);
|
||||
templateDeclaration.token->insertToken(newName, "", true);
|
||||
templateDeclaration.token->insertToken(";", "", true);
|
||||
} else if (copy && isFunction) {
|
||||
} else if (isFunction && (copy || (!copy && isSpecialization))) {
|
||||
Token * dst = templateDeclaration.token;
|
||||
bool isStatic = false;
|
||||
std::string scope;
|
||||
Token * start;
|
||||
Token * end;
|
||||
auto it = mTemplateForwardDeclarationsMap.find(dst);
|
||||
|
@ -1003,8 +1017,21 @@ void TemplateSimplifier::expandTemplate(
|
|||
start = temp1->next();
|
||||
end = temp2->linkAt(1)->next();
|
||||
} else {
|
||||
auto it2 = mTemplateUserSpecializationMap.find(dst);
|
||||
if (it2 != mTemplateUserSpecializationMap.end()) {
|
||||
dst = it2->second;
|
||||
isStatic = dst->next()->findClosingBracket()->strAt(1) == "static";
|
||||
const Token * temp = templateDeclarationNameToken;
|
||||
while (Token::Match(temp->tokAt(-2), "%name% ::")) {
|
||||
scope.insert(0, temp->strAt(-2) + " :: ");
|
||||
temp = temp->tokAt(-2);
|
||||
}
|
||||
}
|
||||
start = templateDeclarationToken->next();
|
||||
end = templateDeclarationNameToken->linkAt(1)->next();
|
||||
if (templateDeclarationNameToken->strAt(1) == "(")
|
||||
end = templateDeclarationNameToken->linkAt(1)->next();
|
||||
else
|
||||
end = templateDeclarationNameToken->next()->findClosingBracket()->linkAt(1)->next();
|
||||
}
|
||||
unsigned int typeindentlevel = 0;
|
||||
while (!(typeindentlevel == 0 && Token::Match(end, ";|{|:"))) {
|
||||
|
@ -1015,6 +1042,9 @@ void TemplateSimplifier::expandTemplate(
|
|||
end = end->next();
|
||||
}
|
||||
|
||||
if (isStatic)
|
||||
dst->insertToken("static", "", true);
|
||||
|
||||
std::map<const Token *, Token *> links;
|
||||
while (start && start != end) {
|
||||
unsigned int itype = 0;
|
||||
|
@ -1041,7 +1071,11 @@ void TemplateSimplifier::expandTemplate(
|
|||
dst->previous()->isLong(typetok->isLong());
|
||||
}
|
||||
} else {
|
||||
if (start->str() == templateDeclarationNameToken->str()) {
|
||||
if (isSpecialization && !copy && !scope.empty() && Token::Match(start, (scope + templateDeclarationNameToken->str()).c_str())) {
|
||||
// skip scope
|
||||
while (start->strAt(1) != templateDeclarationNameToken->str())
|
||||
start = start->next();
|
||||
} else if (start->str() == templateDeclarationNameToken->str()) {
|
||||
dst->insertToken(newName, "", true);
|
||||
if (start->strAt(1) == "<")
|
||||
start = start->next()->findClosingBracket();
|
||||
|
@ -1133,6 +1167,8 @@ void TemplateSimplifier::expandTemplate(
|
|||
// Start of template..
|
||||
if (tok3 == templateDeclarationToken) {
|
||||
tok3 = tok3->next();
|
||||
if (tok3->str() == "static")
|
||||
tok3 = tok3->next();
|
||||
}
|
||||
|
||||
// member function implemented outside class definition
|
||||
|
@ -1907,23 +1943,12 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
|||
return false;
|
||||
|
||||
// already simplified
|
||||
if (!Token::Match(startToken, "%name% <"))
|
||||
if (!Token::Match(tok2, "%name% <"))
|
||||
return false;
|
||||
|
||||
if (templateDeclaration.scope.empty()) {
|
||||
if (startToken->str() != templateDeclaration.name)
|
||||
return false;
|
||||
} else {
|
||||
std::string name = templateDeclaration.scope + " :: " + startToken->str();
|
||||
if (name != templateDeclaration.name)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!matchSpecialization(tok->tokAt(namepos), startToken, specializations))
|
||||
if (!matchSpecialization(tok->tokAt(namepos), tok2, specializations))
|
||||
return false;
|
||||
|
||||
tok2 = startToken;
|
||||
|
||||
// New type..
|
||||
mTypesUsedInTemplateInstantiation.clear();
|
||||
std::list<std::string> typeStringsUsedInTemplateInstantiation;
|
||||
|
@ -2051,6 +2076,61 @@ void TemplateSimplifier::replaceTemplateUsage(
|
|||
}
|
||||
}
|
||||
|
||||
static std::string getPathName(const TemplateSimplifier::TokenAndName & decl)
|
||||
{
|
||||
std::string name = decl.scope;
|
||||
if (!name.empty())
|
||||
name += " :: ";
|
||||
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) {
|
||||
name += (start->str() + " ");
|
||||
start = start->next();
|
||||
}
|
||||
}
|
||||
name += decl.name;
|
||||
return name;
|
||||
}
|
||||
|
||||
void TemplateSimplifier::getUserDefinedSpecializations()
|
||||
{
|
||||
// try to locate a matching declaration for each user defined specialization
|
||||
for (auto & spec : mTemplateDeclarations) {
|
||||
if (Token::Match(spec.token, "template < >")) {
|
||||
std::string specName = getPathName(spec);
|
||||
|
||||
bool found = false;
|
||||
for (auto & decl : mTemplateDeclarations) {
|
||||
if (Token::Match(decl.token, "template < >"))
|
||||
continue;
|
||||
std::string declName = getPathName(decl);
|
||||
|
||||
// make sure the scopes and names match
|
||||
if (specName == declName) {
|
||||
// @todo make sure function parameters also match
|
||||
mTemplateUserSpecializationMap[spec.token] = decl.token;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
for (auto & decl : mTemplateForwardDeclarations) {
|
||||
std::string declName = getPathName(decl);
|
||||
|
||||
// make sure the scopes and names match
|
||||
if (specName == declName) {
|
||||
// @todo make sure function parameters also match
|
||||
mTemplateUserSpecializationMap[spec.token] = decl.token;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
|
||||
{
|
||||
// try to locate a matching declaration for each forward declaration
|
||||
|
@ -2066,26 +2146,8 @@ void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
|
|||
|
||||
// make sure the number of arguments match
|
||||
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;
|
||||
std::string declName = getPathName(decl);
|
||||
std::string forwardDeclName = getPathName(forwardDecl);
|
||||
|
||||
// make sure the scopes and names match
|
||||
if (forwardDeclName == declName) {
|
||||
|
@ -2124,6 +2186,7 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
mTemplateDeclarations.clear();
|
||||
mTemplateForwardDeclarations.clear();
|
||||
mTemplateForwardDeclarationsMap.clear();
|
||||
mTemplateUserSpecializationMap.clear();
|
||||
mTemplateInstantiations.clear();
|
||||
mInstantiatedTemplates.clear();
|
||||
mExplicitInstantiationsToDelete.clear();
|
||||
|
@ -2157,6 +2220,9 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
// Copy default argument values from forward declaration to declaration
|
||||
fixForwardDeclaredDefaultArgumentValues();
|
||||
|
||||
// Locate user defined specializations.
|
||||
getUserDefinedSpecializations();
|
||||
|
||||
// Locate possible instantiations of templates..
|
||||
getTemplateInstantiations();
|
||||
|
||||
|
|
|
@ -156,6 +156,12 @@ private:
|
|||
*/
|
||||
void useDefaultArgumentValues();
|
||||
|
||||
/**
|
||||
* Try to locate a matching declaration for each user defined
|
||||
* specialization.
|
||||
*/
|
||||
void getUserDefinedSpecializations();
|
||||
|
||||
/**
|
||||
* simplify template aliases
|
||||
*/
|
||||
|
@ -278,6 +284,7 @@ private:
|
|||
std::list<TokenAndName> mTemplateDeclarations;
|
||||
std::list<TokenAndName> mTemplateForwardDeclarations;
|
||||
std::map<Token *, Token *> mTemplateForwardDeclarationsMap;
|
||||
std::map<Token *, Token *> mTemplateUserSpecializationMap;
|
||||
std::list<TokenAndName> mTemplateInstantiations;
|
||||
std::list<TokenAndName> mInstantiatedTemplates;
|
||||
std::list<TokenAndName> mMemberFunctionsToDelete;
|
||||
|
|
|
@ -125,6 +125,9 @@ private:
|
|||
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(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)
|
||||
|
@ -479,7 +482,8 @@ private:
|
|||
"}\n";
|
||||
|
||||
// The expected result..
|
||||
const char expected[] = "void foo<int*> ( ) "
|
||||
const char expected[] = "void foo<int*> ( ) ; "
|
||||
"void foo<int*> ( ) "
|
||||
"{ x ( ) ; } "
|
||||
"int main ( ) "
|
||||
"{ foo<int*> ( ) ; }";
|
||||
|
@ -505,6 +509,7 @@ private:
|
|||
// The expected result..
|
||||
const char expected[] = "void a<2> ( ) ; "
|
||||
"void a<1> ( ) ; "
|
||||
"void a<0> ( ) ; "
|
||||
"void a<0> ( ) { } "
|
||||
"int main ( ) "
|
||||
"{ a<2> ( ) ; return 0 ; } "
|
||||
|
@ -1664,6 +1669,92 @@ private:
|
|||
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<char> ( ) ; "
|
||||
"static void foo<float> ( ) ; "
|
||||
"static void foo<bool> ( ) ; "
|
||||
"static void foo<int> ( ) ; "
|
||||
"} ; "
|
||||
"void Fred :: foo<char> ( ) { } "
|
||||
"void Fred :: foo<float> ( ) { } "
|
||||
"void Fred :: foo<bool> ( ) { } "
|
||||
"void Fred :: foo<int> ( ) { }";
|
||||
const char act[] = "struct Fred { "
|
||||
"static void foo<char> ( ) ; "
|
||||
"static void foo<float> ( ) ; "
|
||||
"} ; "
|
||||
"void Fred :: foo<bool> ( ) ; "
|
||||
"void Fred :: foo<bool> ( ) { } "
|
||||
"void Fred :: foo<int> ( ) ; "
|
||||
"void Fred :: foo<int> ( ) { } "
|
||||
"void Fred :: foo<char> ( ) { } "
|
||||
"void Fred :: foo<float> ( ) { }";
|
||||
TODO_ASSERT_EQUALS(exp, act, 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 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"
|
||||
|
|
|
@ -80,6 +80,8 @@ private:
|
|||
TEST_CASE(hierarchie_loop); // ticket 5590
|
||||
|
||||
TEST_CASE(staticVariable); //ticket #5566
|
||||
|
||||
TEST_CASE(templateSimplification); //ticket #6183
|
||||
}
|
||||
|
||||
|
||||
|
@ -794,6 +796,29 @@ private:
|
|||
"int i = F();");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (style) Unused private function: 'Foo::F'\n", errout.str());
|
||||
}
|
||||
|
||||
void templateSimplification() { //ticket #6183
|
||||
check("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"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestUnusedPrivateFunction)
|
||||
|
|
Loading…
Reference in New Issue