Fix template simplifier namespace support. (#1464)

This commit is contained in:
IOBYTE 2018-11-05 13:55:21 -05:00 committed by Daniel Marjamäki
parent d62ed420d8
commit 9b67e680ae
3 changed files with 124 additions and 13 deletions

View File

@ -959,6 +959,34 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok, bool forward)
return namepos;
}
void TemplateSimplifier::addNamespace(const TokenAndName &templateDeclaration, const Token *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());
start = end + 1;
}
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
{
std::string scope = templateDeclaration.scope;
// get the length in tokens of the namespace
std::string::size_type pos = 0;
int offset = -2;
while ((pos = scope.find("::", pos)) != std::string::npos) {
offset -= 2;
pos += 2;
}
return Token::simpleMatch(tok->tokAt(offset), scope.c_str()) ;
}
void TemplateSimplifier::expandTemplate(
const TokenAndName &templateDeclaration,
@ -1049,6 +1077,8 @@ void TemplateSimplifier::expandTemplate(
// replace name if found
if (Token::Match(tok5, "%name% <") && tok5->str() == templateInstantiation.name) {
if (copy) {
if (!templateDeclaration.scope.empty() && tok5->strAt(-1) != "::")
addNamespace(templateDeclaration, tok5);
mTokenList.addtoken(newName, tok5->linenr(), tok5->fileIndex());
tok5 = tok5->next()->findClosingBracket();
} else {
@ -1060,8 +1090,11 @@ void TemplateSimplifier::expandTemplate(
tok5 = tok5->next();
}
if (copy)
if (copy) {
if (!templateDeclaration.scope.empty() && tok3->strAt(-1) != "::")
addNamespace(templateDeclaration, tok3);
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
}
while (tok3 && tok3->str() != "::")
tok3 = tok3->next();
@ -1129,21 +1162,17 @@ void TemplateSimplifier::expandTemplate(
}
continue;
}
} else if (!templateDeclaration.scope.empty() &&
!alreadyHasNamespace(templateDeclaration, tok3)) {
if (copy)
addNamespace(templateDeclaration, tok3);
}
} else {
if (copy) {
// add namespace if necessary
if (!templateDeclaration.scope.empty() && (isClass ? tok3->strAt(1) != "(" : true)) {
std::string::size_type start = 0;
std::string::size_type end = 0;
std::string temp;
while ((end = templateDeclaration.scope.find(" ", start)) != std::string::npos) {
std::string token = templateDeclaration.scope.substr(start, end - start);
mTokenList.addtoken(token, tok3->linenr(), tok3->fileIndex());
start = end + 1;
}
mTokenList.addtoken(templateDeclaration.scope.substr(start), tok3->linenr(), tok3->fileIndex());
mTokenList.addtoken("::", tok3->linenr(), tok3->fileIndex());
if (!templateDeclaration.scope.empty() &&
(isClass ? tok3->strAt(1) != "(" : true)) {
addNamespace(templateDeclaration, tok3);
}
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
} else if (!Token::Match(tok3->next(), ":|{"))
@ -1818,7 +1847,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
const std::string newName(templateDeclaration.name + " < " + typeForNewName + " >");
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
expandedtemplates.insert(newName);
expandTemplate(templateDeclaration, tok, templateDeclaration, typeParametersInDeclaration, newName, !specialized);
expandTemplate(templateDeclaration, tok, templateDeclaration, typeParametersInDeclaration, newName, false);
instantiated = true;
}

View File

@ -165,6 +165,21 @@ private:
const std::time_t maxtime,
std::set<std::string> &expandedtemplates);
/**
* Simplify templates : add namespace to template name
* @param templateDeclaration template declaration
* @param tok place to insert namespace
*/
void addNamespace(const TokenAndName &templateDeclaration, const Token *tok);
/**
* Simplify templates : check if namespace already present
* @param templateDeclaration template declaration
* @param tok place to start looking for namespace
* @return true if namespace already present
*/
bool alreadyHasNamespace(const TokenAndName &templateDeclaration, const Token *tok) const;
/**
* Expand a template. Create "expanded" class/function at end of tokenlist.
* @param templateDeclaration Template declaration information

View File

@ -127,6 +127,8 @@ private:
TEST_CASE(template_namespace_5);
TEST_CASE(template_namespace_6);
TEST_CASE(template_namespace_7); // #8768
TEST_CASE(template_namespace_8);
TEST_CASE(template_namespace_9);
// Test TemplateSimplifier::templateParameters
TEST_CASE(templateParameters);
@ -1824,6 +1826,71 @@ private:
"N1 :: N2 :: CT<int> ct3 ; struct N1 :: N2 :: CT<int> { } ;", tok(code));
}
void template_namespace_8() { // #8768
const char code[] = "namespace NS1 {\n"
"namespace NS2 {\n"
" template <typename T>\n"
" struct Fred {\n"
" Fred();\n"
" Fred(const Fred &);\n"
" Fred & operator = (const Fred &);\n"
" ~Fred();\n"
" };\n"
" template <typename T>\n"
" Fred<T>::Fred() { }\n"
" template <typename T>\n"
" Fred<T>::Fred(const Fred<T> & f) { }\n"
" template <typename T>\n"
" Fred<T> & Fred<T>::operator = (const Fred<T> & f) { }\n"
" template <typename T>\n"
" Fred<T>::~Fred() { }\n"
"}\n"
"}\n"
"NS1::NS2::Fred<int> fred;";
ASSERT_EQUALS("namespace NS1 { "
"namespace NS2 { "
"struct Fred<int> ; "
"} "
"} "
"NS1 :: NS2 :: Fred<int> fred ; struct NS1 :: NS2 :: Fred<int> { "
"Fred<int> ( ) ; "
"Fred<int> ( const NS1 :: NS2 :: Fred<int> & ) ; "
"NS1 :: NS2 :: Fred<int> & operator= ( const NS1 :: NS2 :: Fred<int> & ) ; "
"~ Fred<int> ( ) ; "
"} ; "
"NS1 :: NS2 :: Fred<int> :: Fred<int> ( ) { } "
"NS1 :: NS2 :: Fred<int> :: Fred<int> ( const NS1 :: NS2 :: Fred<int> & f ) { } "
"NS1 :: NS2 :: Fred<int> & NS1 :: NS2 :: Fred<int> :: operator= ( const NS1 :: NS2 :: Fred<int> & f ) { } "
"NS1 :: NS2 :: Fred<int> :: ~ Fred<int> ( ) { }", tok(code));
}
void template_namespace_9() {
const char code[] = "namespace NS {\n"
"template<int type> struct Barney;\n"
"template<> struct Barney<1> { };\n"
"template<int type>\n"
"class Fred {\n"
"public:\n"
" Fred();\n"
"private:\n"
" Barney<type> m_data;\n"
"};\n"
"template class Fred<1>;\n"
"}\n";
ASSERT_EQUALS("namespace NS { "
"template < int type > struct Barney ; "
"struct Barney<1> { } ; "
"class Fred<1> ; "
"template class Fred<1> ; "
"} "
"class NS :: Fred<1> { "
"public: "
"Fred<1> ( ) ; "
"private: "
"Barney<1> m_data ; "
"} ;", tok(code));
}
unsigned int templateParameters(const char code[]) {
Tokenizer tokenizer(&settings, this);