Fixed #8798 (template simplifier: wrong simpifications for namespaces) (#1452)

This commit is contained in:
IOBYTE 2018-10-26 08:20:13 -04:00 committed by Daniel Marjamäki
parent ab08801dc4
commit adbbadec7f
4 changed files with 219 additions and 67 deletions

View File

@ -461,11 +461,6 @@ static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
ret += (ret.empty() ? "" : " :: ") + i.name;
return ret;
}
static std::string getFullName(const std::list<ScopeInfo2> &scopeInfo, const std::string &name)
{
const std::string &scopeName = getScopeName(scopeInfo);
return scopeName + (scopeName.empty() ? "" : " :: ") + name;
}
static void setScopeInfo(const Token *tok, std::list<ScopeInfo2> *scopeInfo)
{
@ -517,7 +512,7 @@ std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDecla
if (forward) {
const int namepos = getTemplateNamePosition(parmEnd, forward);
if (namepos > 0)
declarations.emplace_back(tok, getScopeName(scopeInfo), getFullName(scopeInfo, parmEnd->strAt(namepos)));
declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
}
break;
}
@ -526,7 +521,7 @@ std::list<TemplateSimplifier::TokenAndName> TemplateSimplifier::getTemplateDecla
if (!forward) {
const int namepos = getTemplateNamePosition(parmEnd, forward);
if (namepos > 0)
declarations.emplace_back(tok, getScopeName(scopeInfo), getFullName(scopeInfo, parmEnd->strAt(namepos)));
declarations.emplace_back(tok, getScopeName(scopeInfo), parmEnd->strAt(namepos));
}
break;
}
@ -577,7 +572,7 @@ void TemplateSimplifier::getTemplateInstantiations()
for (; tok2 && tok2 != tok; tok2 = tok2->previous()) {
if (Token::Match(tok2, ", %name% <") &&
templateParameters(tok2->tokAt(2))) {
mTemplateInstantiations.emplace_back(tok2->next(), getScopeName(scopeList), getFullName(scopeList, tok2->strAt(1)));
mTemplateInstantiations.emplace_back(tok2->next(), getScopeName(scopeList), tok2->strAt(1));
}
}
@ -812,6 +807,11 @@ void TemplateSimplifier::simplifyTemplateAliases()
// Replace template alias code..
aliasUsage.name = templateAlias.name;
if (aliasUsage.name.find(' ') == std::string::npos) {
const Token *temp = aliasToken1;
while (temp && temp != templateAlias.token) {
aliasUsage.token->insertToken(temp->str(), "", true);
temp = temp->next();
}
aliasUsage.token->str(templateAlias.token->str());
} else {
tok2 = TokenList::copyTokens(aliasUsage.token, aliasToken1, templateAlias.token, true);
@ -957,8 +957,9 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok, bool forward)
void TemplateSimplifier::expandTemplate(
const TokenAndName &templateDeclaration,
const Token *templateDeclarationToken,
const std::string &fullName,
const TokenAndName &templateInstantiation,
const std::vector<const Token *> &typeParametersInDeclaration,
const std::string &newName,
bool copy)
@ -968,6 +969,15 @@ void TemplateSimplifier::expandTemplate(
const Token *startOfTemplateDeclaration = nullptr;
const Token *endOfTemplateDefinition = nullptr;
const Token * const templateDeclarationNameToken = templateDeclarationToken->tokAt(getTemplateNamePosition(templateDeclarationToken));
const bool isClass = Token::Match(templateDeclarationToken->next(), "class|struct|union %name% <|{|:");
// add forward declaration for classes
if (copy && isClass) {
templateDeclaration.token->insertToken(templateDeclarationToken->strAt(1), "", true);
templateDeclaration.token->insertToken(newName, "", true);
templateDeclaration.token->insertToken(";", "", true);
}
for (Token *tok3 = mTokenList.front(); tok3; tok3 = tok3 ? tok3->next() : nullptr) {
if (Token::Match(tok3, "}|namespace|class|struct|union")) {
setScopeInfo(tok3, &scopeInfo);
@ -1006,7 +1016,7 @@ void TemplateSimplifier::expandTemplate(
// member function implemented outside class definition
else if (inTemplateDefinition &&
Token::Match(tok3, "%name% <") &&
fullName == getFullName(scopeInfo, tok3->str()) &&
templateInstantiation.name == tok3->str() &&
instantiateMatch(tok3, typeParametersInDeclaration.size(), ":: ~| %name% (")) {
// there must be template..
bool istemplate = false;
@ -1033,7 +1043,7 @@ void TemplateSimplifier::expandTemplate(
// copy return type
while (tok5 && tok5 != tok3) {
// replace name if found
if (Token::Match(tok5, "%name% <") && tok5->str() == fullName) {
if (Token::Match(tok5, "%name% <") && tok5->str() == templateInstantiation.name) {
if (copy) {
mTokenList.addtoken(newName, tok5->linenr(), tok5->fileIndex());
tok5 = tok5->next()->findClosingBracket();
@ -1048,6 +1058,7 @@ void TemplateSimplifier::expandTemplate(
}
if (copy)
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
while (tok3 && tok3->str() != "::")
tok3 = tok3->next();
@ -1065,7 +1076,8 @@ void TemplateSimplifier::expandTemplate(
std::stack<Token *> brackets; // holds "(", "[" and "{" tokens
// FIXME use full name matching somehow
const std::string lastName = (fullName.find(' ') != std::string::npos) ? fullName.substr(fullName.rfind(' ')+1) : fullName;
const std::string lastName = (templateInstantiation.name.find(' ') != std::string::npos) ? templateInstantiation.name.substr(templateInstantiation.name.rfind(' ')+1) : templateInstantiation.name;
for (; tok3; tok3 = tok3->next()) {
if (tok3->isName()) {
@ -1099,22 +1111,39 @@ void TemplateSimplifier::expandTemplate(
// replace name..
if (tok3->str() == lastName) {
if (!Token::simpleMatch(tok3->next(), "<")) {
if (copy)
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
else if (tok3->strAt(1) != ":")
tok3->str(newName);
else
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
continue;
} else if (tok3 == templateDeclarationNameToken) {
if (copy) {
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
tok3 = tok3->next()->findClosingBracket();
} else {
tok3->str(newName);
eraseTokens(tok3, tok3->next()->findClosingBracket()->next());
if (Token::simpleMatch(tok3->next(), "<")) {
// replace multi token name with single token name
if (tok3 == templateDeclarationNameToken || Token::Match(tok3, newName.c_str())) {
Token *closingBracket = tok3->next()->findClosingBracket();
if (closingBracket) {
if (copy) {
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
tok3 = closingBracket;
} else {
tok3->str(newName);
eraseTokens(tok3, closingBracket->next());
}
continue;
}
}
} 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());
}
mTokenList.addtoken(newName, tok3->linenr(), tok3->fileIndex());
} else if (!Token::Match(tok3->next(), ":|{"))
tok3->str(newName);
continue;
}
}
@ -1142,7 +1171,7 @@ void TemplateSimplifier::expandTemplate(
std::string name = tok3->str();
for (const Token *prev = tok3->tokAt(-2); Token::Match(prev, "%name% ::"); prev = prev->tokAt(-2))
name = prev->str() + " :: " + name;
mTemplateInstantiations.emplace_back(mTokenList.back(), getScopeName(scopeInfo), getFullName(scopeInfo, name));
mTemplateInstantiations.emplace_back(mTokenList.back(), getScopeName(scopeInfo), name);
}
// link() newly tokens manually
@ -1704,7 +1733,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
expandedtemplates.insert(newName);
expandTemplate(tok, instantiation.name, typeParametersInDeclaration, newName, !specialized);
expandTemplate(templateDeclaration, tok, instantiation, typeParametersInDeclaration, newName, !specialized);
instantiated = true;
}
@ -1785,7 +1814,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
const std::string newName(templateDeclaration.name + " < " + typeForNewName + " >");
if (expandedtemplates.find(newName) == expandedtemplates.end()) {
expandedtemplates.insert(newName);
expandTemplate(tok, templateDeclaration.name, typeParametersInDeclaration, newName, !specialized);
expandTemplate(templateDeclaration, tok, templateDeclaration, typeParametersInDeclaration, newName, !specialized);
instantiated = true;
}
@ -1808,10 +1837,11 @@ static bool matchTemplateParameters(const Token *nameTok, const std::list<std::s
return it == strings.end() && tok && tok->str() == ">";
}
void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
const std::string &templateName,
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
const std::string &newName)
void TemplateSimplifier::replaceTemplateUsage(
Token * const instantiationToken,
const std::string &templateName,
const std::list<std::string> &typeStringsUsedInTemplateInstantiation,
const std::string &newName)
{
std::list<ScopeInfo2> scopeInfo;
std::list< std::pair<Token *, Token *> > removeTokens;
@ -1867,8 +1897,6 @@ void TemplateSimplifier::replaceTemplateUsage(Token * const instantiationToken,
// Foo < int > => Foo<int>
if (tok2->str() == ">" && typeCountInInstantiation == mTypesUsedInTemplateInstantiation.size()) {
const Token * const nameTok1 = nameTok;
while (Token::Match(nameTok->tokAt(-2), "%name% :: %name%"))
nameTok = nameTok->tokAt(-2);
nameTok->str(newName);
for (std::list<TokenAndName>::iterator it = mTemplateInstantiations.begin(); it != mTemplateInstantiations.end(); ++it) {
if (it->token == nameTok1)

View File

@ -167,14 +167,17 @@ private:
/**
* Expand a template. Create "expanded" class/function at end of tokenlist.
* @param fullName Full name of template
* @param templateDeclaration Template declaration information
* @param templateDeclarationToken Template declaration token
* @param templateInstantiation Full name of template
* @param typeParametersInDeclaration The type parameters of the template
* @param newName New name of class/function.
* @param copy copy or expand in place
*/
void expandTemplate(
const TokenAndName &templateDeclaration,
const Token *templateDeclarationToken,
const std::string &fullName,
const TokenAndName &templateInstantiation,
const std::vector<const Token *> &typeParametersInDeclaration,
const std::string &newName,
bool copy);

View File

@ -106,6 +106,8 @@ private:
TEST_CASE(template66); // #8725
TEST_CASE(template67); // #8122
TEST_CASE(template68); // union
TEST_CASE(template69); // #8791
TEST_CASE(template70); // #5289
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
@ -122,6 +124,8 @@ private:
TEST_CASE(template_namespace_3);
TEST_CASE(template_namespace_4);
TEST_CASE(template_namespace_5);
TEST_CASE(template_namespace_6);
TEST_CASE(template_namespace_7); // #8768
// Test TemplateSimplifier::templateParameters
TEST_CASE(templateParameters);
@ -648,7 +652,8 @@ private:
"{};\n"
"\n"
"bitset<1> z;";
const char expected[] = "bitset<1> z ; "
const char expected[] = "class bitset<1> ; "
"bitset<1> z ; "
"class bitset<1> : B<4> { } ; "
"struct B<4> { int a [ 4 ] ; } ;";
ASSERT_EQUALS(expected, tok(code));
@ -666,15 +671,16 @@ private:
"bitset<1> z;";
const char actual[] = "template < int n > struct B { int a [ n ] ; } ; "
"class bitset<1> ; "
"bitset<1> z ; "
"class bitset<1> : B < 4 > { } ;";
const char expected[] = "bitset<1> z ; "
const char expected[] = "class bitset<1> ; "
"bitset<1> z ; "
"class bitset<1> : B < 4 > { } ; "
"struct B < 4 > { int a [ 4 ] ; } ;";
TODO_ASSERT_EQUALS(expected, actual, tok(code));
}
void template26() {
@ -687,7 +693,7 @@ private:
"\n"
"C<2> a;\n";
// TODO: expand A also
ASSERT_EQUALS("template < class T > class A { public: T x ; } ; C<2> a ; class C<2> : public A < char [ 2 ] > { } ;", tok(code));
ASSERT_EQUALS("template < class T > class A { public: T x ; } ; class C<2> ; C<2> a ; class C<2> : public A < char [ 2 ] > { } ;", tok(code));
}
void template27() {
@ -732,6 +738,7 @@ private:
"\n"
"B<int> b;\n";
ASSERT_EQUALS("template < class T1 , class T2 , class T3 , class T4 > struct A { } ; "
"struct B<int> ; "
"B<int> b ; "
"struct B<int> { public: A < int , Pair < int , int > , int > a ; } ;", tok(code));
}
@ -743,7 +750,9 @@ private:
"template<class T> struct B { };\n"
"template<class T> struct C { A<B<X<T> > > ab; };\n"
"C<int> c;";
ASSERT_EQUALS("C<int> c ; "
ASSERT_EQUALS("struct B<X<int>> ; "
"struct C<int> ; "
"C<int> c ; "
"struct C<int> { A<B<X<int>>> ab ; } ; "
"struct B<X<int>> { } ; " // <- redundant.. but nevermind
"struct A<B<X<int>>> { } ;", tok(code));
@ -757,7 +766,9 @@ private:
"C< B<A> > c;";
ASSERT_EQUALS("struct A { } ; "
"template < class T > struct B { } ; " // <- redundant.. but nevermind
"C<B<A>> c ; struct C<B<A>> { } ;",
"struct C<B<A>> ; "
"C<B<A>> c ; "
"struct C<B<A>> { } ;",
tok(code));
}
}
@ -768,10 +779,7 @@ private:
"template <typename T> struct X { void f(X<T> &x) {} };\n"
"}\n"
"template <> int X<int>::Y(0);";
ASSERT_EQUALS("namespace abc { "
"template < typename T > struct X { void f ( X < T > & x ) { } } ; "
"} "
"template < > int X < int > :: Y ( 0 ) ;", tok(code));
tok(code);
}
void template35() { // #4074 - "A<'x'> a;" is not recognized as template instantiation
@ -784,7 +792,8 @@ private:
const char code[] = "template <class T> struct X { T t; };\n"
"template <class C> struct Y { Foo < X< Bar<C> > > _foo; };\n" // <- Bar is unknown
"Y<int> bar;";
ASSERT_EQUALS("Y<int> bar ; "
ASSERT_EQUALS("struct Y<int> ; "
"Y<int> bar ; "
"struct Y<int> { Foo < X<Bar<int>> > _foo ; } ; "
"struct X<Bar<int>> { Bar < int > t ; } ;",
tok(code));
@ -796,7 +805,7 @@ private:
"template<class T> class B {};\n"
"B<class A> b1;\n"
"B<A> b2;";
ASSERT_EQUALS("class A { } ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
ASSERT_EQUALS("class A { } ; class B<A> ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
tok(code));
}
{
@ -804,7 +813,7 @@ private:
"template<class T> class B {};\n"
"B<struct A> b1;\n"
"B<A> b2;";
ASSERT_EQUALS("struct A { } ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
ASSERT_EQUALS("struct A { } ; class B<A> ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
tok(code));
}
{
@ -812,7 +821,7 @@ private:
"template<class T> class B {};\n"
"B<enum A> b1;\n"
"B<A> b2;";
ASSERT_EQUALS("enum A { } ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
ASSERT_EQUALS("enum A { } ; class B<A> ; B<A> b1 ; B<A> b2 ; class B<A> { } ;",
tok(code));
}
}
@ -1128,7 +1137,8 @@ private:
" Foo<Bar<T>> f2() { }\n"
"};\n"
"Bar<int> c;";
const char exp[] = "Bar<int> c ; "
const char exp[] = "struct Bar<int> ; "
"Bar<int> c ; "
"struct Bar<int> {"
" void f1 ( Bar<int> x ) { }"
" Foo<Bar<int>> f2 ( ) { } "
@ -1144,6 +1154,7 @@ private:
"template <class T, unsigned S> C3<T, S>::C3(const C3<T, S> &v) { C1<T *> c1; }\n"
"C3<int,6> c3;";
const char exp[] = "template < class T > void f ( ) { x = y ? ( C1 < int > :: allocate ( 1 ) ) : 0 ; } "
"class C3<int,6> ; "
"C3<int,6> c3 ; "
"class C3<int,6> { } ; "
"C3<int,6> :: C3<int,6> ( const C3<int,6> & v ) { C1<int*> c1 ; } "
@ -1252,12 +1263,45 @@ private:
ASSERT_EQUALS(exp, tok(code));
}
void template69() { // #8791
const char code[] = "class Test {\n"
" int test;\n"
" template <class T> T lookup() { return test; }\n"
" int Fun() { return lookup<int>(); }\n"
"};";
const char exp [] = "class Test { "
"int test ; "
"int Fun ( ) { return lookup<int> ( ) ; } "
"} ; "
"int Test :: lookup<int> ( ) { return test ; }";
ASSERT_EQUALS(exp, tok(code));
}
void template70() { // #5289
const char code[] = "template<typename T, typename V, int KeySize = 0> class Bar;\n"
"template<>\n"
"class Bar<void, void> {\n"
"};\n"
"template<typename K, typename V, int KeySize>\n"
"class Bar : private Bar<void, void> {\n"
" void foo() { }\n"
"};";
const char exp [] = "template < typename T , typename V , int KeySize = 0 > class Bar ; "
"class Bar<void,void> { "
"} ; "
"template < typename K , typename V , int KeySize = 0 > "
"class Bar : private Bar<void,void> { "
"void foo ( ) { } "
"} ;";
ASSERT_EQUALS(exp, tok(code));
}
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
const char code[] = "template <typename T> struct C {};\n"
"template <typename T> struct S {a};\n"
"template <typename T> struct S<C<T>> {b};\n"
"S<int> s;";
const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S < C < T > > { b } ; S<int> s ; struct S<int> { a } ;";
const char exp[] = "template < typename T > struct C { } ; struct S<int> ; template < typename T > struct S < C < T > > { b } ; S<int> s ; struct S<int> { a } ;";
ASSERT_EQUALS(exp, tok(code));
}
@ -1266,7 +1310,7 @@ private:
"template <typename T> struct S {a};\n"
"template <typename T> struct S<C<T>> {b};\n"
"S<C<int>> s;";
const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S { a } ; S<C<int>> s ; struct S<C<int>> { b } ;";
const char exp[] = "template < typename T > struct C { } ; template < typename T > struct S { a } ; struct S<C<int>> ; S<C<int>> s ; struct S<C<int>> { b } ;";
ASSERT_EQUALS(exp, tok(code));
}
@ -1407,6 +1451,7 @@ private:
"thv_table_c<void * , void * , DefaultMemory < void * , void *>> id_table_m ; "
"class thv_table_c<void * , void * , DefaultMemory < void * , void * >> { } ;";
const char curr[] = "template < class T , class U > class DefaultMemory { } ; "
"class thv_table_c<void*,void*,DefaultMemory<Key,Val>> ; "
"thv_table_c<void*,void*,DefaultMemory<Key,Val>> id_table_m ; "
"class thv_table_c<void*,void*,DefaultMemory<Key,Val>> { } ;";
TODO_ASSERT_EQUALS(exp, curr, tok(code));
@ -1426,7 +1471,9 @@ private:
" A<int> a2;\n"
"}\n";
const char wanted[] = "void f ( ) "
const char wanted[] = "class A<int,2> ; "
"class A<int,3> ; "
"void f ( ) "
"{"
" A<int,2> a1 ;"
" A<int,3> a2 ; "
@ -1436,6 +1483,8 @@ private:
"class A<int,3> "
"{ int ar [ 3 ] ; } ;";
const char current[] = "template < class T , int n = 3 > class A ; "
"class A<int,2> ; "
"class A<int,3> ; "
"void f ( ) "
"{"
" A<int,2> a1 ;"
@ -1459,7 +1508,9 @@ private:
" A<int> a2;\n"
"}\n";
const char wanted[] = "void f ( ) "
const char wanted[] = "class A<int,2> ; "
"class A<int,3> ; "
"void f ( ) "
"{"
" A<int,2> a1 ;"
" A<int,3> a2 ; "
@ -1469,6 +1520,8 @@ private:
"class A<int,3> "
"{ int ar [ 3 ] ; } ;";
const char current[] = "template < class , int = 3 > class A ; "
"class A<int,2> ; "
"class A<int,3> ; "
"void f ( ) "
"{"
" A<int,2> a1 ;"
@ -1638,8 +1691,11 @@ private:
" template<class T> struct S { };\n"
"}\n"
"X::S<int> s;";
ASSERT_EQUALS("X::S<int> s ; "
"struct X::S<int> { } ;", tok(code));
ASSERT_EQUALS("namespace X { "
"struct S<int> ; "
"} "
"X :: S<int> s ; "
"struct X :: S<int> { } ;", tok(code));
}
void template_namespace_3() {
@ -1650,11 +1706,12 @@ private:
" void *test() { return foo<int>::bar(); }\n"
"}";
ASSERT_EQUALS("namespace test16 {"
" struct foo<int> ;"
" void * test ( ) {"
" return test16::foo<int> :: bar ( ) ;"
" return foo<int> :: bar ( ) ;"
" } "
"} "
"struct test16::foo<int> {"
"struct test16 :: foo<int> {"
" static void * bar ( ) ; "
"} ;", tok(code));
}
@ -1669,13 +1726,14 @@ private:
" };\n"
"}";
ASSERT_EQUALS("namespace foo {"
" struct S : public foo::A<int> {"
" class A<int> ;"
" struct S : public A<int> {"
" void f ( ) {"
" foo::A<int> :: dostuff ( ) ;"
" A<int> :: dostuff ( ) ;"
" }"
" } ; "
"} "
"class foo::A<int> { void dostuff ( ) { } } ;", tok(code));
"class foo :: A<int> { void dostuff ( ) { } } ;", tok(code));
}
void template_namespace_5() {
@ -1684,6 +1742,66 @@ private:
ASSERT_EQUALS("namespace X { S<int> s ; } struct S<int> { } ;", tok(code));
}
void template_namespace_6() {
const char code[] = "namespace NS {\n"
"template <typename T> union C {\n"
" char dummy[sizeof(T)];\n"
" T value;\n"
" C();\n"
" ~C();\n"
" C(const C &);\n"
" C & operator = (const C &);\n"
"};\n"
"}\n"
"NS::C<int> intC;\n"
"template <typename T> NS::C<T>::C() {}\n"
"template <typename T> NS::C<T>::~C() {}\n"
"template <typename T> NS::C<T>::C(const NS::C<T> &) {}\n"
"template <typename T> NS::C<T> & NS::C<T>::operator=(const NS::C<T> &) {}";
ASSERT_EQUALS("namespace NS { "
"union C<int> ; "
"} "
"NS :: C<int> intC ; union NS :: C<int> { "
"char dummy [ 4 ] ; "
"int value ; "
"C<int> ( ) ; "
"~ C<int> ( ) ; "
"C<int> ( const NS :: C<int> & ) ; "
"NS :: C<int> & operator= ( const NS :: C<int> & ) ; "
"} ; "
"NS :: C<int> :: C<int> ( ) { } "
"NS :: C<int> :: ~ C<int> ( ) { } "
"NS :: C<int> :: C<int> ( const NS :: C<int> & ) { } "
"NS :: C<int> & NS :: C<int> :: operator= ( const NS :: C<int> & ) { }", tok(code));
}
void template_namespace_7() { // #8768
const char code[] = "namespace N1 {\n"
"namespace N2 {\n"
" struct C { };\n"
" template <class T> struct CT { };\n"
" C c1;\n"
" CT<int> ct1;\n"
"}\n"
"N2::C c2;\n"
"N2::CT<int> ct2;\n"
"}\n"
"N1::N2::C c3;\n"
"N1::N2::CT<int> ct3;";
ASSERT_EQUALS("namespace N1 { "
"namespace N2 { "
"struct C { } ; "
"struct CT<int> ; "
"C c1 ; "
"CT<int> ct1 ; "
"} "
"N2 :: C c2 ; "
"N2 :: CT<int> ct2 ; "
"} "
"N1 :: N2 :: C c3 ; "
"N1 :: N2 :: CT<int> ct3 ; struct N1 :: N2 :: CT<int> { } ;", tok(code));
}
unsigned int templateParameters(const char code[]) {
Tokenizer tokenizer(&settings, this);
@ -1956,7 +2074,10 @@ private:
"template<class T> using Bar = A::Foo<T,3>;\n"
"Bar<int> b;\n";
const char expected[] = "; A::Foo<int,3> b ; struct A::Foo<int,3> { } ;";
const char expected[] = "namespace A { struct Foo<int,3> ; } "
"; "
"A :: Foo<int,3> b ; "
"struct A :: Foo<int,3> { } ;";
ASSERT_EQUALS(expected, tok(code));
}

View File

@ -4408,8 +4408,8 @@ private:
" void foo() {\n"
" }\n"
"};");
ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false));
if (db)
ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.empty() && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false));
if (db && db->findScopeByName("Bar"))
ASSERT_EQUALS(1, db->findScopeByName("Bar")->functionList.size());
}