template simplifier: add support for using namespace when instantiating templates (#1615)
This commit is contained in:
parent
3975913637
commit
ec8bc785a2
|
@ -483,6 +483,7 @@ namespace {
|
||||||
ScopeInfo2(const std::string &name_, const Token *bodyEnd_) : name(name_), bodyEnd(bodyEnd_) {}
|
ScopeInfo2(const std::string &name_, const Token *bodyEnd_) : name(name_), bodyEnd(bodyEnd_) {}
|
||||||
const std::string name;
|
const std::string name;
|
||||||
const Token * const bodyEnd;
|
const Token * const bodyEnd;
|
||||||
|
std::set<std::string> usingNamespaces;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
|
static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
|
||||||
|
@ -498,8 +499,20 @@ static void setScopeInfo(Token *tok, std::list<ScopeInfo2> *scopeInfo)
|
||||||
while (tok->str() == "}" && !scopeInfo->empty() && tok == scopeInfo->back().bodyEnd)
|
while (tok->str() == "}" && !scopeInfo->empty() && tok == scopeInfo->back().bodyEnd)
|
||||||
scopeInfo->pop_back();
|
scopeInfo->pop_back();
|
||||||
if (!Token::Match(tok, "namespace|class|struct|union %name% {|:|::")) {
|
if (!Token::Match(tok, "namespace|class|struct|union %name% {|:|::")) {
|
||||||
|
// check for using namespace
|
||||||
|
if (Token::Match(tok, "using namespace %name% ;|::")) {
|
||||||
|
const Token * tok1 = tok->tokAt(2);
|
||||||
|
std::string nameSpace;
|
||||||
|
while (tok1 && tok1->str() != ";") {
|
||||||
|
if (!nameSpace.empty())
|
||||||
|
nameSpace += " ";
|
||||||
|
nameSpace += tok1->str();
|
||||||
|
tok1 = tok1->next();
|
||||||
|
}
|
||||||
|
scopeInfo->back().usingNamespaces.insert(nameSpace);
|
||||||
|
}
|
||||||
// check for member function
|
// check for member function
|
||||||
if (tok->str() == "{") {
|
else if (tok->str() == "{") {
|
||||||
Token *tok1 = tok;
|
Token *tok1 = tok;
|
||||||
while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
|
while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
|
||||||
tok1 = tok1->previous();
|
tok1 = tok1->previous();
|
||||||
|
@ -600,8 +613,11 @@ void TemplateSimplifier::getTemplateInstantiations()
|
||||||
std::list<ScopeInfo2> scopeList;
|
std::list<ScopeInfo2> scopeList;
|
||||||
const Token *skip = nullptr;
|
const Token *skip = nullptr;
|
||||||
|
|
||||||
|
scopeList.emplace_back("", nullptr);
|
||||||
|
|
||||||
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
||||||
if (Token::Match(tok, "{|}|namespace|class|struct|union")) {
|
if (Token::Match(tok, "{|}|namespace|class|struct|union") ||
|
||||||
|
Token::Match(tok, "using namespace %name% ;|::")) {
|
||||||
setScopeInfo(tok, &scopeList);
|
setScopeInfo(tok, &scopeList);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -632,8 +648,12 @@ void TemplateSimplifier::getTemplateInstantiations()
|
||||||
Token::Match(tok->previous(), "%type% %name% ::|<") ||
|
Token::Match(tok->previous(), "%type% %name% ::|<") ||
|
||||||
Token::Match(tok->tokAt(-2), "[,:] private|protected|public %name% ::|<")) {
|
Token::Match(tok->tokAt(-2), "[,:] private|protected|public %name% ::|<")) {
|
||||||
std::string scopeName = getScopeName(scopeList);
|
std::string scopeName = getScopeName(scopeList);
|
||||||
|
std::string qualification;
|
||||||
|
Token * qualificationTok = tok;
|
||||||
while (Token::Match(tok, "%name% :: %name%")) {
|
while (Token::Match(tok, "%name% :: %name%")) {
|
||||||
scopeName += (scopeName.empty() ? "" : " :: ") + tok->str();
|
// ignore redundant namespaces
|
||||||
|
if (scopeName.find(tok->str()) == std::string::npos)
|
||||||
|
qualification += (qualification.empty() ? "" : " :: ") + tok->str();
|
||||||
tok = tok->tokAt(2);
|
tok = tok->tokAt(2);
|
||||||
}
|
}
|
||||||
if (!Token::Match(tok, "%name% <") ||
|
if (!Token::Match(tok, "%name% <") ||
|
||||||
|
@ -663,12 +683,39 @@ void TemplateSimplifier::getTemplateInstantiations()
|
||||||
if (templateParameters(tok->next())) {
|
if (templateParameters(tok->next())) {
|
||||||
const std::string scopeName1(scopeName);
|
const std::string scopeName1(scopeName);
|
||||||
while (true) {
|
while (true) {
|
||||||
const std::string fullName = scopeName + (scopeName.empty()?"":" :: ") + tok->str();
|
const std::string fullName = scopeName + (scopeName.empty()?"":" :: ") +
|
||||||
|
qualification + (qualification.empty()?"":" :: ") + tok->str();
|
||||||
const std::list<TokenAndName>::const_iterator it = std::find_if(mTemplateDeclarations.begin(), mTemplateDeclarations.end(), FindFullName(fullName));
|
const std::list<TokenAndName>::const_iterator it = std::find_if(mTemplateDeclarations.begin(), mTemplateDeclarations.end(), FindFullName(fullName));
|
||||||
if (it != mTemplateDeclarations.end()) {
|
if (it != mTemplateDeclarations.end()) {
|
||||||
mTemplateInstantiations.emplace_back(tok, scopeName);
|
// full name matches
|
||||||
|
mTemplateInstantiations.emplace_back(tok, it->scope);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
// full name doesn't match so try with using namespaces if available
|
||||||
|
bool found = false;
|
||||||
|
for (const auto & nameSpace : scopeList.back().usingNamespaces) {
|
||||||
|
std::string fullNameSpace = scopeName + (scopeName.empty()?"":" :: ") +
|
||||||
|
nameSpace + (qualification.empty()?"":" :: ") + qualification;
|
||||||
|
std::string newFullName = fullNameSpace + " :: " + tok->str();
|
||||||
|
const std::list<TokenAndName>::const_iterator it1 = std::find_if(mTemplateDeclarations.begin(), mTemplateDeclarations.end(), FindFullName(newFullName));
|
||||||
|
if (it1 != mTemplateDeclarations.end()) {
|
||||||
|
// insert using namespace into token stream
|
||||||
|
std::string::size_type offset = 0;
|
||||||
|
std::string::size_type pos = 0;
|
||||||
|
while ((pos = nameSpace.substr(offset).find(' ')) != std::string::npos) {
|
||||||
|
qualificationTok->insertToken(nameSpace.substr(offset, pos), "", true);
|
||||||
|
offset = offset + pos + 1;
|
||||||
|
}
|
||||||
|
qualificationTok->insertToken(nameSpace.substr(offset), "", true);
|
||||||
|
qualificationTok->insertToken("::", "", true);
|
||||||
|
mTemplateInstantiations.emplace_back(tok, it1->scope);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
|
break;
|
||||||
|
|
||||||
if (scopeName.empty()) {
|
if (scopeName.empty()) {
|
||||||
mTemplateInstantiations.emplace_back(tok, getScopeName(scopeList));
|
mTemplateInstantiations.emplace_back(tok, getScopeName(scopeList));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -134,6 +134,7 @@ private:
|
||||||
TEST_CASE(template94); // #8927 crash
|
TEST_CASE(template94); // #8927 crash
|
||||||
TEST_CASE(template95); // #7417
|
TEST_CASE(template95); // #7417
|
||||||
TEST_CASE(template96); // #7854
|
TEST_CASE(template96); // #7854
|
||||||
|
TEST_CASE(template97);
|
||||||
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
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_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)
|
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||||
|
@ -1600,9 +1601,9 @@ private:
|
||||||
"void foo ( ) { "
|
"void foo ( ) { "
|
||||||
"using namespace swizzle ; "
|
"using namespace swizzle ; "
|
||||||
"tvec2<f16> tt2 ; "
|
"tvec2<f16> tt2 ; "
|
||||||
"swizzle<1> ( tt2 ) ; "
|
"swizzle :: swizzle<1> ( tt2 ) ; "
|
||||||
"tvec3<f16> tt3 ; "
|
"tvec3<f16> tt3 ; "
|
||||||
"swizzle<2,3> ( tt3 ) ; "
|
"swizzle :: swizzle<2,3> ( tt3 ) ; "
|
||||||
"} "
|
"} "
|
||||||
"void swizzle :: swizzle<2,3> ( tvec3<f16> v ) { } "
|
"void swizzle :: swizzle<2,3> ( tvec3<f16> v ) { } "
|
||||||
"void swizzle :: swizzle<1> ( tvec2<f16> v ) { } "
|
"void swizzle :: swizzle<1> ( tvec2<f16> v ) { } "
|
||||||
|
@ -1950,6 +1951,106 @@ private:
|
||||||
TODO_ASSERT_EQUALS(exp, act, tok(code, false));
|
TODO_ASSERT_EQUALS(exp, act, tok(code, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template97() {
|
||||||
|
const char code[] ="namespace NS1 {\n"
|
||||||
|
" namespace NS2 {\n"
|
||||||
|
" namespace NS3 {\n"
|
||||||
|
" namespace NS4 {\n"
|
||||||
|
" template<class T>\n"
|
||||||
|
" class Fred {\n"
|
||||||
|
" T * t;\n"
|
||||||
|
" public:\n"
|
||||||
|
" Fred<T>() : t(nullptr) {}\n"
|
||||||
|
" };\n"
|
||||||
|
" }\n"
|
||||||
|
" using namespace NS4;\n"
|
||||||
|
" Fred<bool> fred_bool;\n"
|
||||||
|
" NS4::Fred<char> fred_char;\n"
|
||||||
|
" }\n"
|
||||||
|
" using namespace NS3;\n"
|
||||||
|
" NS4::Fred<short> fred_short;\n"
|
||||||
|
" using namespace NS3::NS4;\n"
|
||||||
|
" Fred<int> fred_int;\n"
|
||||||
|
" NS3::NS4::Fred<long> fred_long;\n"
|
||||||
|
" NS2::NS3::NS4::Fred<float> fred_float;\n"
|
||||||
|
" NS1::NS2::NS3::NS4::Fred<double> fred_double;\n"
|
||||||
|
" }\n"
|
||||||
|
" using namespace NS2;\n"
|
||||||
|
" NS3::NS4::Fred<float> fred_float1;\n"
|
||||||
|
" NS2::NS3::NS4::Fred<double> fred_double1;\n"
|
||||||
|
"}\n"
|
||||||
|
"using namespace NS1::NS2::NS3::NS4;\n"
|
||||||
|
"Fred<bool> fred_bool1;\n"
|
||||||
|
"NS1::NS2::NS3::NS4::Fred<int> fred_int1;";
|
||||||
|
const char exp[] = "namespace NS1 { "
|
||||||
|
"namespace NS2 { "
|
||||||
|
"namespace NS3 { "
|
||||||
|
"namespace NS4 { "
|
||||||
|
"class Fred<bool> ; "
|
||||||
|
"class Fred<char> ; "
|
||||||
|
"class Fred<short> ; "
|
||||||
|
"class Fred<int> ; "
|
||||||
|
"class Fred<long> ; "
|
||||||
|
"class Fred<float> ; "
|
||||||
|
"class Fred<double> ; "
|
||||||
|
"} "
|
||||||
|
"using namespace NS4 ; "
|
||||||
|
"NS4 :: Fred<bool> fred_bool ; "
|
||||||
|
"NS4 :: Fred<char> fred_char ; "
|
||||||
|
"} "
|
||||||
|
"using namespace NS3 ; "
|
||||||
|
"NS3 :: NS4 :: Fred<short> fred_short ; "
|
||||||
|
"using namespace NS3 :: NS4 ; "
|
||||||
|
"NS3 :: NS4 :: Fred<int> fred_int ; "
|
||||||
|
"NS3 :: NS4 :: Fred<long> fred_long ; "
|
||||||
|
"NS2 :: NS3 :: NS4 :: Fred<float> fred_float ; "
|
||||||
|
"NS1 :: NS2 :: NS3 :: NS4 :: Fred<double> fred_double ; "
|
||||||
|
"} "
|
||||||
|
"using namespace NS2 ; "
|
||||||
|
"NS2 :: NS3 :: NS4 :: Fred<float> fred_float1 ; "
|
||||||
|
"NS2 :: NS3 :: NS4 :: Fred<double> fred_double1 ; "
|
||||||
|
"} "
|
||||||
|
"using namespace NS1 :: NS2 :: NS3 :: NS4 ; "
|
||||||
|
"NS1 :: NS2 :: NS3 :: NS4 :: Fred<bool> fred_bool1 ; "
|
||||||
|
"NS1 :: NS2 :: NS3 :: NS4 :: Fred<int> fred_int1 ; "
|
||||||
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<bool> { "
|
||||||
|
"bool * t ; "
|
||||||
|
"public: "
|
||||||
|
"Fred<bool> ( ) : t ( nullptr ) { } "
|
||||||
|
"} ; "
|
||||||
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<char> { "
|
||||||
|
"char * t ; "
|
||||||
|
"public: "
|
||||||
|
"Fred<char> ( ) : t ( nullptr ) { } "
|
||||||
|
"} ; "
|
||||||
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<short> { "
|
||||||
|
"short * t ; "
|
||||||
|
"public: "
|
||||||
|
"Fred<short> ( ) : t ( nullptr ) { } "
|
||||||
|
"} ; "
|
||||||
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<int> { "
|
||||||
|
"int * t ; "
|
||||||
|
"public: "
|
||||||
|
"Fred<int> ( ) : t ( nullptr ) { } "
|
||||||
|
"} ; "
|
||||||
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<long> { "
|
||||||
|
"long * t ; "
|
||||||
|
"public: "
|
||||||
|
"Fred<long> ( ) : t ( nullptr ) { } "
|
||||||
|
"} ; "
|
||||||
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<float> { "
|
||||||
|
"float * t ; "
|
||||||
|
"public: "
|
||||||
|
"Fred<float> ( ) : t ( nullptr ) { } "
|
||||||
|
"} ; "
|
||||||
|
"class NS1 :: NS2 :: NS3 :: NS4 :: Fred<double> { "
|
||||||
|
"double * t ; "
|
||||||
|
"public: "
|
||||||
|
"Fred<double> ( ) : t ( nullptr ) { } "
|
||||||
|
"} ;";
|
||||||
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||||
const char code[] = "template <typename T> struct C {};\n"
|
const char code[] = "template <typename T> struct C {};\n"
|
||||||
"template <typename T> struct S {a};\n"
|
"template <typename T> struct S {a};\n"
|
||||||
|
|
Loading…
Reference in New Issue