Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 62 additions & 47 deletions lib/templatesimplifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,10 +485,10 @@ static void setScopeInfo(const Token *tok, std::list<ScopeInfo2> *scopeInfo)
}
}

std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDeclarations(bool &codeWithTemplates, bool forward)
bool TemplateSimplifier::getTemplateDeclarations()
{
bool codeWithTemplates = false;
std::list<ScopeInfo2> scopeInfo;
std::list<TokenAndName> declarations;
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "}|namespace|class|struct|union")) {
setScopeInfo(tok, &scopeInfo);
Expand All @@ -509,27 +509,23 @@ std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDecla
tok2 = tok2->link();
else if (tok2->str() == ")")
break;
// Just a declaration => ignore this
// Declaration => add to mTemplateForwardDeclarations
else if (tok2->str() == ";") {
if (forward) {
const int namepos = getTemplateNamePosition(parmEnd, forward);
if (namepos > 0)
declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
}
const int namepos = getTemplateNamePosition(parmEnd, true);
if (namepos > 0)
mTemplateForwardDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
break;
}
// Implementation => add to "templates"
// Implementation => add to mTemplateDeclarations
else if (tok2->str() == "{") {
if (!forward) {
const int namepos = getTemplateNamePosition(parmEnd, forward);
if (namepos > 0)
declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
}
const int namepos = getTemplateNamePosition(parmEnd, false);
if (namepos > 0)
mTemplateDeclarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
break;
}
}
}
return declarations;
return codeWithTemplates;
}


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

void TemplateSimplifier::addNamespace(const TokenAndName &templateDeclaration, const Token *tok)
{
// find start of qualification
const Token * tokStart = tok;
int offset = 0;
while (Token::Match(tokStart->tokAt(-2), "%name% ::")) {
tokStart = tokStart->tokAt(-2);
offset -= 2;
}
// decide if namespace needs to be inserted in or appended to token list
const bool insert = tokStart != tok;

std::string::size_type start = 0;
std::string::size_type end = 0;
while ((end = templateDeclaration.scope.find(" ", start)) != std::string::npos) {
std::string token = templateDeclaration.scope.substr(start, end - start);
mTokenList.addtoken(token, tok->linenr(), tok->fileIndex());
if (insert)
mTokenList.back()->tokAt(offset)->insertToken(token, "");
else
mTokenList.addtoken(token, tok->linenr(), tok->fileIndex());
start = end + 1;
}
mTokenList.addtoken(templateDeclaration.scope.substr(start), tok->linenr(), tok->fileIndex());
mTokenList.addtoken("::", tok->linenr(), tok->fileIndex());
if (insert) {
mTokenList.back()->tokAt(offset)->insertToken(templateDeclaration.scope.substr(start), "");
mTokenList.back()->tokAt(offset)->insertToken("::", "");
} else {
mTokenList.addtoken(templateDeclaration.scope.substr(start), tok->linenr(), tok->fileIndex());
mTokenList.addtoken("::", tok->linenr(), tok->fileIndex());
}
}

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

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) {
for (const auto & forwardDecl : mTemplateForwardDeclarations) {
std::vector<const Token *> params1;

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

void TemplateSimplifier::simplifyTemplates(
const std::time_t maxtime,
bool &codeWithTemplates
)
bool &codeWithTemplates)
{
std::set<std::string> expandedtemplates;

if (getTemplateDeclarations(codeWithTemplates).empty())
return;

// There are templates..
// Remove "typename" unless used in template arguments..
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
if (tok->str() == "typename")
tok->deleteThis();

if (Token::simpleMatch(tok, "template <")) {
while (tok && tok->str() != ">")
tok = tok->next();
if (!tok)
break;
}
}

// expand templates
// TODO: 2 is not the ideal number of loops.
// We should loop until the number of declarations is 0 but we can't
// do that until we instantiate unintstantiated templates with their symbolic types.
Expand All @@ -2027,12 +2016,36 @@ void TemplateSimplifier::simplifyTemplates(
// is fixed.
for (int i = 0; i < 2; ++i) {
if (i) {
expandedtemplates.clear();
mTemplateDeclarations.clear();
mTemplateForwardDeclarations.clear();
mTemplateInstantiations.clear();
mInstantiatedTemplates.clear();
}

mTemplateDeclarations = getTemplateDeclarations(codeWithTemplates);
bool hasTemplates = getTemplateDeclarations();

if (i == 0) {
codeWithTemplates = hasTemplates;
if (hasTemplates) {
// There are templates..
// Remove "typename" unless used in template arguments..
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
if (tok->str() == "typename")
tok->deleteThis();

if (Token::simpleMatch(tok, "template <")) {
while (tok && tok->str() != ">")
tok = tok->next();
if (!tok)
break;
}
}
}
}

// Make sure there is something to simplify.
if (mTemplateDeclarations.empty())
return;

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

simplifyTemplateAliases();

std::set<std::string> expandedtemplates;

for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
// get specializations..
std::list<const Token *> specializations;
Expand Down
7 changes: 3 additions & 4 deletions lib/templatesimplifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,9 @@ class CPPCHECKLIB TemplateSimplifier {
private:
/**
* Get template declarations
* @param codeWithTemplates set to true if code has templates
* @param forward declaration or forward declaration
* @return list of template declarations
* @return true if code has templates.
*/
std::list<TokenAndName> getTemplateDeclarations(bool &codeWithTemplates, bool forward = false);
bool getTemplateDeclarations();

/**
* Get template instantiations
Expand Down Expand Up @@ -264,6 +262,7 @@ class CPPCHECKLIB TemplateSimplifier {
ErrorLogger *mErrorLogger;

std::list<TokenAndName> mTemplateDeclarations;
std::list<TokenAndName> mTemplateForwardDeclarations;
std::list<TokenAndName> mTemplateInstantiations;
std::list<TokenAndName> mInstantiatedTemplates;
std::list<TokenAndName> mMemberFunctionsToDelete;
Expand Down
29 changes: 29 additions & 0 deletions test/testsimplifytemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class TestSimplifyTemplate : public TestFixture {
TEST_CASE(template_namespace_8);
TEST_CASE(template_namespace_9);
TEST_CASE(template_namespace_10);
TEST_CASE(template_namespace_11); // #7145

// Test TemplateSimplifier::templateParameters
TEST_CASE(templateParameters);
Expand Down Expand Up @@ -1974,6 +1975,34 @@ class TestSimplifyTemplate : public TestFixture {
"} ;", tok(code));
}

void template_namespace_11() {// #7145
const char code[] = "namespace MyNamespace {\n"
"class TestClass {\n"
"public:\n"
" TestClass() {\n"
" SomeFunction();\n"
" TemplatedMethod< int >();\n"
" }\n"
" void SomeFunction() { }\n"
"private:\n"
" template< typename T > void TemplatedMethod();\n"
"};\n"
"template< typename T > void TestClass::TemplatedMethod() { }\n"
"}";
ASSERT_EQUALS("namespace MyNamespace { "
"class TestClass { "
"public: "
"TestClass ( ) { "
"SomeFunction ( ) ; "
"TemplatedMethod<int> ( ) ; "
"} "
"void SomeFunction ( ) { } "
"private: "
"template < typename T > void TemplatedMethod ( ) ; "
"} ; "
"} void MyNamespace :: TestClass :: TemplatedMethod<int> ( ) { }", tok(code));
}

unsigned int templateParameters(const char code[]) {
Tokenizer tokenizer(&settings, this);

Expand Down