Copy template default argument values from forward declaration to declaration. (#1447)
It is possible to define default template parameter values in forward declarations and not define any in the actual declaration. Cppcheck ignores forward declarations and only uses the default values in the actual declaration so default values in forward declarations are copied to the actual declaration when necessary.
This commit is contained in:
parent
be1ff268c0
commit
0763fdbfad
|
@ -488,7 +488,7 @@ static void setScopeInfo(const Token *tok, std::list<ScopeInfo2> *scopeInfo)
|
|||
}
|
||||
}
|
||||
|
||||
std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDeclarations(bool &codeWithTemplates)
|
||||
std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDeclarations(bool &codeWithTemplates, bool forward)
|
||||
{
|
||||
std::list<ScopeInfo2> scopeInfo;
|
||||
std::list<TokenAndName> declarations;
|
||||
|
@ -513,13 +513,21 @@ std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDecla
|
|||
else if (tok2->str() == ")")
|
||||
break;
|
||||
// Just a declaration => ignore this
|
||||
else if (tok2->str() == ";")
|
||||
break;
|
||||
// Implementation => add to "templates"
|
||||
else if (tok2->str() == "{") {
|
||||
const int namepos = getTemplateNamePosition(parmEnd);
|
||||
else if (tok2->str() == ";") {
|
||||
if (forward) {
|
||||
const int namepos = getTemplateNamePosition(parmEnd, forward);
|
||||
if (namepos > 0)
|
||||
declarations.emplace_back(tok, getScopeName(scopeInfo), getFullName(scopeInfo, parmEnd->strAt(namepos)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Implementation => add to "templates"
|
||||
else if (tok2->str() == "{") {
|
||||
if (!forward) {
|
||||
const int namepos = getTemplateNamePosition(parmEnd, forward);
|
||||
if (namepos > 0)
|
||||
declarations.emplace_back(tok, getScopeName(scopeInfo), getFullName(scopeInfo, parmEnd->strAt(namepos)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -915,11 +923,12 @@ static bool getTemplateNamePositionTemplateMember(const Token *tok, int &namepos
|
|||
return false;
|
||||
}
|
||||
|
||||
int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
|
||||
int TemplateSimplifier::getTemplateNamePosition(const Token *tok, bool forward)
|
||||
{
|
||||
// get the position of the template name
|
||||
int namepos = 0, starAmpPossiblePosition = 0;
|
||||
if (Token::Match(tok, "> class|struct|union %type% {|:|<"))
|
||||
if ((forward && Token::Match(tok, "> class|struct|union %type% :|<|;")) ||
|
||||
(!forward && Token::Match(tok, "> class|struct|union %type% {|:|<")))
|
||||
namepos = 2;
|
||||
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
||||
namepos = 2;
|
||||
|
@ -1482,7 +1491,7 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
|
|||
{
|
||||
typeParametersInDeclaration.clear();
|
||||
for (; tok && tok->str() != ">"; tok = tok->next()) {
|
||||
if (Token::Match(tok, "%name% ,|>"))
|
||||
if (Token::Match(tok, "%name% ,|>|="))
|
||||
typeParametersInDeclaration.push_back(tok);
|
||||
}
|
||||
return tok;
|
||||
|
@ -1887,6 +1896,39 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
|
|||
}
|
||||
}
|
||||
|
||||
void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
|
||||
{
|
||||
// get all forward declarations
|
||||
bool dummy;
|
||||
std::list<TokenAndName> forwardTemplateDeclarations = getTemplateDeclarations(dummy, true);
|
||||
|
||||
// try to locate a matching declaration for each forward declaration
|
||||
for (const auto & forwardDecl : forwardTemplateDeclarations) {
|
||||
std::vector<const Token *> params1;
|
||||
|
||||
getTemplateParametersInDeclaration(forwardDecl.token, params1);
|
||||
|
||||
for (auto & decl : mTemplateDeclarations) {
|
||||
std::vector<const Token *> params2;
|
||||
|
||||
getTemplateParametersInDeclaration(decl.token, params2);
|
||||
|
||||
// make sure the number of arguments match
|
||||
if (params1.size() == params2.size()) {
|
||||
// make sure the scopes and names match
|
||||
if (forwardDecl.scope == decl.scope && forwardDecl.name == decl.name) {
|
||||
for (size_t k = 0; k < params1.size(); k++) {
|
||||
// copy default value to declaration if not present
|
||||
if (params1[k]->strAt(1) == "=" && params2[k]->strAt(1) != "=") {
|
||||
const_cast<Token *>(params2[k])->insertToken(params1[k]->strAt(2));
|
||||
const_cast<Token *>(params2[k])->insertToken(params1[k]->strAt(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateSimplifier::simplifyTemplates(
|
||||
const std::time_t maxtime,
|
||||
|
@ -1929,6 +1971,9 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
|
||||
mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates);
|
||||
|
||||
// Copy default argument values from forward declaration to declaration
|
||||
fixForwardDeclaredDefaultArgumentValues();
|
||||
|
||||
// Locate possible instantiations of templates..
|
||||
getTemplateInstantiations();
|
||||
|
||||
|
|
|
@ -89,10 +89,11 @@ public:
|
|||
/**
|
||||
* Match template declaration/instantiation
|
||||
* @param tok The ">" token e.g. before "class"
|
||||
* @param forward declaration or forward declaration
|
||||
* @return -1 to bail out or positive integer to identity the position
|
||||
* of the template name.
|
||||
*/
|
||||
static int getTemplateNamePosition(const Token *tok);
|
||||
static int getTemplateNamePosition(const Token *tok, bool forward = false);
|
||||
|
||||
/**
|
||||
* Simplify templates
|
||||
|
@ -122,15 +123,23 @@ public:
|
|||
private:
|
||||
/**
|
||||
* Get template declarations
|
||||
* @param codeWithTemplates set to true if code has templates
|
||||
* @param forward declaration or forward declaration
|
||||
* @return list of template declarations
|
||||
*/
|
||||
std::list<TokenAndName> getTemplateDeclarations(bool &codeWithTemplates);
|
||||
std::list<TokenAndName> getTemplateDeclarations(bool &codeWithTemplates, bool forward = false);
|
||||
|
||||
/**
|
||||
* Get template instantiations
|
||||
*/
|
||||
void getTemplateInstantiations();
|
||||
|
||||
/**
|
||||
* Fix forward declared default argument values by copying them
|
||||
* when they are not present in the declaration.
|
||||
*/
|
||||
void fixForwardDeclaredDefaultArgumentValues();
|
||||
|
||||
/**
|
||||
* simplify template instantiations (use default argument values)
|
||||
*/
|
||||
|
|
|
@ -111,6 +111,7 @@ private:
|
|||
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
|
||||
|
@ -1412,6 +1413,75 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
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 wanted[] = "void f ( ) "
|
||||
"{"
|
||||
" A<int,2> a1 ;"
|
||||
" A<int,3> a2 ; "
|
||||
"} "
|
||||
"class A<int,2> "
|
||||
"{ int ar [ 2 ] ; } ; "
|
||||
"class A<int,3> "
|
||||
"{ int ar [ 3 ] ; } ;";
|
||||
const char current[] = "template < class T , int n = 3 > class A ; "
|
||||
"void f ( ) "
|
||||
"{"
|
||||
" A<int,2> a1 ;"
|
||||
" A<int,3> a2 ; "
|
||||
"} "
|
||||
"class A<int,2> "
|
||||
"{ int ar [ 2 ] ; } ; "
|
||||
"class A<int,3> "
|
||||
"{ int ar [ 3 ] ; } ;";
|
||||
TODO_ASSERT_EQUALS(wanted, current, 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 wanted[] = "void f ( ) "
|
||||
"{"
|
||||
" A<int,2> a1 ;"
|
||||
" A<int,3> a2 ; "
|
||||
"} "
|
||||
"class A<int,2> "
|
||||
"{ int ar [ 2 ] ; } ; "
|
||||
"class A<int,3> "
|
||||
"{ int ar [ 3 ] ; } ;";
|
||||
const char current[] = "template < class , int = 3 > class A ; "
|
||||
"void f ( ) "
|
||||
"{"
|
||||
" A<int,2> a1 ;"
|
||||
" A<int,3> a2 ; "
|
||||
"} "
|
||||
"class A<int,2> "
|
||||
"{ int ar [ 2 ] ; } ; "
|
||||
"class A<int,3> "
|
||||
"{ int ar [ 3 ] ; } ;";
|
||||
TODO_ASSERT_EQUALS(wanted, current, tok(code));
|
||||
}
|
||||
}
|
||||
|
||||
void template_default_type() {
|
||||
const char code[] = "template <typename T, typename U=T>\n"
|
||||
"class A\n"
|
||||
|
|
Loading…
Reference in New Issue