Fix template simplifier namespace support. (#1464)
This commit is contained in:
parent
d62ed420d8
commit
9b67e680ae
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue