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<ScopeInfo2> scopeInfo;
|
||||||
std::list<TokenAndName> declarations;
|
std::list<TokenAndName> declarations;
|
||||||
|
@ -513,13 +513,21 @@ std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDecla
|
||||||
else if (tok2->str() == ")")
|
else if (tok2->str() == ")")
|
||||||
break;
|
break;
|
||||||
// Just a declaration => ignore this
|
// Just a declaration => ignore this
|
||||||
else if (tok2->str() == ";")
|
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;
|
break;
|
||||||
|
}
|
||||||
// Implementation => add to "templates"
|
// Implementation => add to "templates"
|
||||||
else if (tok2->str() == "{") {
|
else if (tok2->str() == "{") {
|
||||||
const int namepos = getTemplateNamePosition(parmEnd);
|
if (!forward) {
|
||||||
if (namepos > 0)
|
const int namepos = getTemplateNamePosition(parmEnd, forward);
|
||||||
declarations.emplace_back(tok, getScopeName(scopeInfo), getFullName(scopeInfo, parmEnd->strAt(namepos)));
|
if (namepos > 0)
|
||||||
|
declarations.emplace_back(tok, getScopeName(scopeInfo), getFullName(scopeInfo, parmEnd->strAt(namepos)));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -915,11 +923,12 @@ static bool getTemplateNamePositionTemplateMember(const Token *tok, int &namepos
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
|
int TemplateSimplifier::getTemplateNamePosition(const Token *tok, bool forward)
|
||||||
{
|
{
|
||||||
// get the position of the template name
|
// get the position of the template name
|
||||||
int namepos = 0, starAmpPossiblePosition = 0;
|
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;
|
namepos = 2;
|
||||||
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
else if (Token::Match(tok, "> %type% *|&| %type% ("))
|
||||||
namepos = 2;
|
namepos = 2;
|
||||||
|
@ -1482,7 +1491,7 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
|
||||||
{
|
{
|
||||||
typeParametersInDeclaration.clear();
|
typeParametersInDeclaration.clear();
|
||||||
for (; tok && tok->str() != ">"; tok = tok->next()) {
|
for (; tok && tok->str() != ">"; tok = tok->next()) {
|
||||||
if (Token::Match(tok, "%name% ,|>"))
|
if (Token::Match(tok, "%name% ,|>|="))
|
||||||
typeParametersInDeclaration.push_back(tok);
|
typeParametersInDeclaration.push_back(tok);
|
||||||
}
|
}
|
||||||
return 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(
|
void TemplateSimplifier::simplifyTemplates(
|
||||||
const std::time_t maxtime,
|
const std::time_t maxtime,
|
||||||
|
@ -1929,6 +1971,9 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
|
|
||||||
mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates);
|
mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates);
|
||||||
|
|
||||||
|
// Copy default argument values from forward declaration to declaration
|
||||||
|
fixForwardDeclaredDefaultArgumentValues();
|
||||||
|
|
||||||
// Locate possible instantiations of templates..
|
// Locate possible instantiations of templates..
|
||||||
getTemplateInstantiations();
|
getTemplateInstantiations();
|
||||||
|
|
||||||
|
|
|
@ -89,10 +89,11 @@ public:
|
||||||
/**
|
/**
|
||||||
* Match template declaration/instantiation
|
* Match template declaration/instantiation
|
||||||
* @param tok The ">" token e.g. before "class"
|
* @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
|
* @return -1 to bail out or positive integer to identity the position
|
||||||
* of the template name.
|
* of the template name.
|
||||||
*/
|
*/
|
||||||
static int getTemplateNamePosition(const Token *tok);
|
static int getTemplateNamePosition(const Token *tok, bool forward = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplify templates
|
* Simplify templates
|
||||||
|
@ -122,15 +123,23 @@ public:
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Get template declarations
|
* Get template declarations
|
||||||
|
* @param codeWithTemplates set to true if code has templates
|
||||||
|
* @param forward declaration or forward declaration
|
||||||
* @return list of template declarations
|
* @return list of template declarations
|
||||||
*/
|
*/
|
||||||
std::list<TokenAndName> getTemplateDeclarations(bool &codeWithTemplates);
|
std::list<TokenAndName> getTemplateDeclarations(bool &codeWithTemplates, bool forward = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get template instantiations
|
* Get template instantiations
|
||||||
*/
|
*/
|
||||||
void getTemplateInstantiations();
|
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)
|
* 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_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||||
TEST_CASE(template_unhandled);
|
TEST_CASE(template_unhandled);
|
||||||
TEST_CASE(template_default_parameter);
|
TEST_CASE(template_default_parameter);
|
||||||
|
TEST_CASE(template_forward_declared_default_parameter);
|
||||||
TEST_CASE(template_default_type);
|
TEST_CASE(template_default_type);
|
||||||
TEST_CASE(template_typename);
|
TEST_CASE(template_typename);
|
||||||
TEST_CASE(template_constructor); // #3152 - template constructor is removed
|
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() {
|
void template_default_type() {
|
||||||
const char code[] = "template <typename T, typename U=T>\n"
|
const char code[] = "template <typename T, typename U=T>\n"
|
||||||
"class A\n"
|
"class A\n"
|
||||||
|
|
Loading…
Reference in New Issue