Skip to content

Commit 69e6e11

Browse files
IOBYTEdanmar
authored andcommitted
Fix a template simplifier namespace bug in #7145 (#1473)
* Fix a template simplifier namespace bug in #7145 * Refactor template simplifier to only call getTemplateDeclarations once per loop.
1 parent 1ffcc6b commit 69e6e11

File tree

3 files changed

+94
-51
lines changed

3 files changed

+94
-51
lines changed

lib/templatesimplifier.cpp

Lines changed: 62 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -485,10 +485,10 @@ static void setScopeInfo(const Token *tok, std::list<ScopeInfo2> *scopeInfo)
485485
}
486486
}
487487

488-
std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDeclarations(bool &codeWithTemplates, bool forward)
488+
bool TemplateSimplifier::getTemplateDeclarations()
489489
{
490+
bool codeWithTemplates = false;
490491
std::list<ScopeInfo2> scopeInfo;
491-
std::list<TokenAndName> declarations;
492492
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
493493
if (Token::Match(tok, "}|namespace|class|struct|union")) {
494494
setScopeInfo(tok, &scopeInfo);
@@ -509,27 +509,23 @@ std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDecla
509509
tok2 = tok2->link();
510510
else if (tok2->str() == ")")
511511
break;
512-
// Just a declaration => ignore this
512+
// Declaration => add to mTemplateForwardDeclarations
513513
else if (tok2->str() == ";") {
514-
if (forward) {
515-
const int namepos = getTemplateNamePosition(parmEnd, forward);
516-
if (namepos > 0)
517-
declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
518-
}
514+
const int namepos = getTemplateNamePosition(parmEnd, true);
515+
if (namepos > 0)
516+
mTemplateForwardDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
519517
break;
520518
}
521-
// Implementation => add to "templates"
519+
// Implementation => add to mTemplateDeclarations
522520
else if (tok2->str() == "{") {
523-
if (!forward) {
524-
const int namepos = getTemplateNamePosition(parmEnd, forward);
525-
if (namepos > 0)
526-
declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
527-
}
521+
const int namepos = getTemplateNamePosition(parmEnd, false);
522+
if (namepos > 0)
523+
mTemplateDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
528524
break;
529525
}
530526
}
531527
}
532-
return declarations;
528+
return codeWithTemplates;
533529
}
534530

535531

@@ -961,15 +957,33 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok, bool forward)
961957

962958
void TemplateSimplifier::addNamespace(const TokenAndName &templateDeclaration, const Token *tok)
963959
{
960+
// find start of qualification
961+
const Token * tokStart = tok;
962+
int offset = 0;
963+
while (Token::Match(tokStart->tokAt(-2), "%name% ::")) {
964+
tokStart = tokStart->tokAt(-2);
965+
offset -= 2;
966+
}
967+
// decide if namespace needs to be inserted in or appended to token list
968+
const bool insert = tokStart != tok;
969+
964970
std::string::size_type start = 0;
965971
std::string::size_type end = 0;
966972
while ((end = templateDeclaration.scope.find(" ", start)) != std::string::npos) {
967973
std::string token = templateDeclaration.scope.substr(start, end - start);
968-
mTokenList.addtoken(token, tok->linenr(), tok->fileIndex());
974+
if (insert)
975+
mTokenList.back()->tokAt(offset)->insertToken(token, "");
976+
else
977+
mTokenList.addtoken(token, tok->linenr(), tok->fileIndex());
969978
start = end + 1;
970979
}
971-
mTokenList.addtoken(templateDeclaration.scope.substr(start), tok->linenr(), tok->fileIndex());
972-
mTokenList.addtoken("::", tok->linenr(), tok->fileIndex());
980+
if (insert) {
981+
mTokenList.back()->tokAt(offset)->insertToken(templateDeclaration.scope.substr(start), "");
982+
mTokenList.back()->tokAt(offset)->insertToken("::", "");
983+
} else {
984+
mTokenList.addtoken(templateDeclaration.scope.substr(start), tok->linenr(), tok->fileIndex());
985+
mTokenList.addtoken("::", tok->linenr(), tok->fileIndex());
986+
}
973987
}
974988

975989
bool TemplateSimplifier::alreadyHasNamespace(const TokenAndName &templateDeclaration, const Token *tok) const
@@ -1961,12 +1975,8 @@ void TemplateSimplifier::replaceTemplateUsage(
19611975

19621976
void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
19631977
{
1964-
// get all forward declarations
1965-
bool dummy;
1966-
std::list<TokenAndName> forwardTemplateDeclarations = getTemplateDeclarations(dummy, true);
1967-
19681978
// try to locate a matching declaration for each forward declaration
1969-
for (const auto & forwardDecl : forwardTemplateDeclarations) {
1979+
for (const auto & forwardDecl : mTemplateForwardDeclarations) {
19701980
std::vector<const Token *> params1;
19711981

19721982
getTemplateParametersInDeclaration(forwardDecl.token, params1);
@@ -1995,29 +2005,8 @@ void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
19952005

19962006
void TemplateSimplifier::simplifyTemplates(
19972007
const std::time_t maxtime,
1998-
bool &codeWithTemplates
1999-
)
2008+
bool &codeWithTemplates)
20002009
{
2001-
std::set<std::string> expandedtemplates;
2002-
2003-
if (getTemplateDeclarations(codeWithTemplates).empty())
2004-
return;
2005-
2006-
// There are templates..
2007-
// Remove "typename" unless used in template arguments..
2008-
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
2009-
if (tok->str() == "typename")
2010-
tok->deleteThis();
2011-
2012-
if (Token::simpleMatch(tok, "template <")) {
2013-
while (tok && tok->str() != ">")
2014-
tok = tok->next();
2015-
if (!tok)
2016-
break;
2017-
}
2018-
}
2019-
2020-
// expand templates
20212010
// TODO: 2 is not the ideal number of loops.
20222011
// We should loop until the number of declarations is 0 but we can't
20232012
// do that until we instantiate unintstantiated templates with their symbolic types.
@@ -2027,12 +2016,36 @@ void TemplateSimplifier::simplifyTemplates(
20272016
// is fixed.
20282017
for (int i = 0; i < 2; ++i) {
20292018
if (i) {
2030-
expandedtemplates.clear();
2019+
mTemplateDeclarations.clear();
2020+
mTemplateForwardDeclarations.clear();
20312021
mTemplateInstantiations.clear();
20322022
mInstantiatedTemplates.clear();
20332023
}
20342024

2035-
mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates);
2025+
bool hasTemplates = getTemplateDeclarations();
2026+
2027+
if (i == 0) {
2028+
codeWithTemplates = hasTemplates;
2029+
if (hasTemplates) {
2030+
// There are templates..
2031+
// Remove "typename" unless used in template arguments..
2032+
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
2033+
if (tok->str() == "typename")
2034+
tok->deleteThis();
2035+
2036+
if (Token::simpleMatch(tok, "template <")) {
2037+
while (tok && tok->str() != ">")
2038+
tok = tok->next();
2039+
if (!tok)
2040+
break;
2041+
}
2042+
}
2043+
}
2044+
}
2045+
2046+
// Make sure there is something to simplify.
2047+
if (mTemplateDeclarations.empty())
2048+
return;
20362049

20372050
// Copy default argument values from forward declaration to declaration
20382051
fixForwardDeclaredDefaultArgumentValues();
@@ -2045,6 +2058,8 @@ void TemplateSimplifier::simplifyTemplates(
20452058

20462059
simplifyTemplateAliases();
20472060

2061+
std::set<std::string> expandedtemplates;
2062+
20482063
for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
20492064
// get specializations..
20502065
std::list<const Token *> specializations;

lib/templatesimplifier.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,9 @@ class CPPCHECKLIB TemplateSimplifier {
123123
private:
124124
/**
125125
* Get template declarations
126-
* @param codeWithTemplates set to true if code has templates
127-
* @param forward declaration or forward declaration
128-
* @return list of template declarations
126+
* @return true if code has templates.
129127
*/
130-
std::list<TokenAndName> getTemplateDeclarations(bool &codeWithTemplates, bool forward = false);
128+
bool getTemplateDeclarations();
131129

132130
/**
133131
* Get template instantiations
@@ -264,6 +262,7 @@ class CPPCHECKLIB TemplateSimplifier {
264262
ErrorLogger *mErrorLogger;
265263

266264
std::list<TokenAndName> mTemplateDeclarations;
265+
std::list<TokenAndName> mTemplateForwardDeclarations;
267266
std::list<TokenAndName> mTemplateInstantiations;
268267
std::list<TokenAndName> mInstantiatedTemplates;
269268
std::list<TokenAndName> mMemberFunctionsToDelete;

test/testsimplifytemplate.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class TestSimplifyTemplate : public TestFixture {
130130
TEST_CASE(template_namespace_8);
131131
TEST_CASE(template_namespace_9);
132132
TEST_CASE(template_namespace_10);
133+
TEST_CASE(template_namespace_11); // #7145
133134

134135
// Test TemplateSimplifier::templateParameters
135136
TEST_CASE(templateParameters);
@@ -1974,6 +1975,34 @@ class TestSimplifyTemplate : public TestFixture {
19741975
"} ;", tok(code));
19751976
}
19761977

1978+
void template_namespace_11() {// #7145
1979+
const char code[] = "namespace MyNamespace {\n"
1980+
"class TestClass {\n"
1981+
"public:\n"
1982+
" TestClass() {\n"
1983+
" SomeFunction();\n"
1984+
" TemplatedMethod< int >();\n"
1985+
" }\n"
1986+
" void SomeFunction() { }\n"
1987+
"private:\n"
1988+
" template< typename T > void TemplatedMethod();\n"
1989+
"};\n"
1990+
"template< typename T > void TestClass::TemplatedMethod() { }\n"
1991+
"}";
1992+
ASSERT_EQUALS("namespace MyNamespace { "
1993+
"class TestClass { "
1994+
"public: "
1995+
"TestClass ( ) { "
1996+
"SomeFunction ( ) ; "
1997+
"TemplatedMethod<int> ( ) ; "
1998+
"} "
1999+
"void SomeFunction ( ) { } "
2000+
"private: "
2001+
"template < typename T > void TemplatedMethod ( ) ; "
2002+
"} ; "
2003+
"} void MyNamespace :: TestClass :: TemplatedMethod<int> ( ) { }", tok(code));
2004+
}
2005+
19772006
unsigned int templateParameters(const char code[]) {
19782007
Tokenizer tokenizer(&settings, this);
19792008

0 commit comments

Comments
 (0)