This commit is contained in:
parent
cb9efcb100
commit
277da763aa
|
@ -3690,7 +3690,7 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
if (mTemplateDeclarations.empty() && mTemplateForwardDeclarations.empty())
|
||||
return;
|
||||
|
||||
if (passCount != 0 && mSettings->debugtemplate && mSettings->debugnormal) {
|
||||
if (mSettings->debugtemplate && mSettings->debugnormal) {
|
||||
std::string title("Template Simplifier pass " + std::to_string(passCount + 1));
|
||||
mTokenList.front()->printOut(title.c_str(), mTokenList.getFiles());
|
||||
}
|
||||
|
|
|
@ -1702,6 +1702,7 @@ namespace {
|
|||
const Token * const bodyStart;
|
||||
const Token * const bodyEnd;
|
||||
std::set<std::string> usingNamespaces;
|
||||
std::set<std::string> recordTypes;
|
||||
};
|
||||
|
||||
std::string getScopeName(const std::list<ScopeInfo3> &scopeInfo)
|
||||
|
@ -1778,12 +1779,16 @@ namespace {
|
|||
return;
|
||||
}
|
||||
|
||||
const bool record = Token::Match(tok, "class|struct|union %name%");
|
||||
tok = tok->next();
|
||||
std::string classname = tok->str();
|
||||
while (Token::Match(tok, "%name% :: %name%")) {
|
||||
tok = tok->tokAt(2);
|
||||
classname += " :: " + tok->str();
|
||||
}
|
||||
// add record type to scope info
|
||||
if (record)
|
||||
scopeInfo->back().recordTypes.insert(classname);
|
||||
tok = tok->next();
|
||||
if (tok && tok->str() == ":") {
|
||||
while (tok && !Token::Match(tok, ";|{"))
|
||||
|
@ -1968,6 +1973,11 @@ bool Tokenizer::simplifyUsing()
|
|||
|
||||
// skip template declarations
|
||||
if (Token::Match(tok, "template < !!>")) {
|
||||
// add template record type to scope info
|
||||
const Token *end = tok->next()->findClosingBracket();
|
||||
if (end && Token::Match(end->next(), "class|struct|union %name%"))
|
||||
scopeList.back().recordTypes.insert(end->strAt(2));
|
||||
|
||||
Token *endToken = TemplateSimplifier::findTemplateDeclarationEnd(tok);
|
||||
if (endToken)
|
||||
tok = endToken;
|
||||
|
@ -2088,7 +2098,9 @@ bool Tokenizer::simplifyUsing()
|
|||
|
||||
// remove the qualification
|
||||
std::string fullScope = scope;
|
||||
std::string removed;
|
||||
while (tok1->strAt(-1) == "::") {
|
||||
removed = (tok1->strAt(-2) + " :: ") + removed;
|
||||
if (fullScope == tok1->strAt(-2)) {
|
||||
tok1->deletePrevious();
|
||||
tok1->deletePrevious();
|
||||
|
@ -2220,6 +2232,32 @@ bool Tokenizer::simplifyUsing()
|
|||
substitute = true;
|
||||
}
|
||||
} else {
|
||||
// add some qualification back if needed
|
||||
std::string removed1 = removed;
|
||||
std::string::size_type idx = removed1.rfind(" ::");
|
||||
if (idx != std::string::npos)
|
||||
removed1.resize(idx);
|
||||
if (removed1 == scope && !removed1.empty()) {
|
||||
for (std::list<ScopeInfo3>::const_reverse_iterator it = scopeList.crbegin(); it != scopeList.crend(); ++it) {
|
||||
if (it->recordTypes.find(start->str()) != it->recordTypes.end()) {
|
||||
std::string::size_type spaceIdx = 0;
|
||||
std::string::size_type startIdx = 0;
|
||||
while ((spaceIdx = removed1.find(" ", startIdx)) != std::string::npos) {
|
||||
tok1->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx).c_str());
|
||||
startIdx = spaceIdx + 1;
|
||||
}
|
||||
tok1->previous()->insertToken(removed1.substr(startIdx).c_str());
|
||||
tok1->previous()->insertToken("::");
|
||||
break;
|
||||
}
|
||||
idx = removed1.rfind(" ::");
|
||||
if (idx == std::string::npos)
|
||||
break;
|
||||
|
||||
removed1.resize(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// just replace simple type aliases
|
||||
TokenList::copyTokens(tok1, start, usingEnd->previous());
|
||||
tok1->deleteThis();
|
||||
|
|
|
@ -207,7 +207,7 @@ private:
|
|||
TEST_CASE(template162);
|
||||
TEST_CASE(template163); // #9685 syntax error
|
||||
TEST_CASE(template164); // #9394
|
||||
TEST_CASE(template162); // #10032 syntax error
|
||||
TEST_CASE(template165); // #10032 syntax error
|
||||
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)
|
||||
|
|
|
@ -76,6 +76,7 @@ private:
|
|||
TEST_CASE(simplifyUsing9518);
|
||||
TEST_CASE(simplifyUsing9757);
|
||||
TEST_CASE(simplifyUsing10008);
|
||||
TEST_CASE(simplifyUsing10054);
|
||||
}
|
||||
|
||||
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Native, bool debugwarnings = true) {
|
||||
|
@ -663,6 +664,205 @@ private:
|
|||
"}";
|
||||
ASSERT_EQUALS(exp, tok(code, false));
|
||||
}
|
||||
|
||||
void simplifyUsing10054() { // debug: Executable scope 'x' with unknown function.
|
||||
{
|
||||
// original example: using "namespace external::ns1;" but redundant qualification
|
||||
const char code[] = "namespace external {\n"
|
||||
" namespace ns1 {\n"
|
||||
" template <int size> struct B { };\n"
|
||||
" using V = B<sizeof(bool)>;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"namespace ns {\n"
|
||||
" struct A {\n"
|
||||
" void f(external::ns1::V);\n"
|
||||
" };\n"
|
||||
"}\n"
|
||||
"using namespace external::ns1;\n"
|
||||
"namespace ns {\n"
|
||||
" void A::f(external::ns1::V) {}\n"
|
||||
"}";
|
||||
const char exp[] = "namespace external { "
|
||||
"namespace ns1 { "
|
||||
"struct B<1> ; "
|
||||
"} "
|
||||
"} "
|
||||
"namespace ns { "
|
||||
"struct A { "
|
||||
"void f ( external :: ns1 :: B<1> ) ; "
|
||||
"} ; "
|
||||
"} "
|
||||
"using namespace external :: ns1 ; "
|
||||
"namespace ns { "
|
||||
"void A :: f ( external :: ns1 :: B<1> ) { } "
|
||||
"} "
|
||||
"struct external :: ns1 :: B<1> { } ;";
|
||||
ASSERT_EQUALS(exp, tok(code, true));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
{
|
||||
// no using "namespace external::ns1;"
|
||||
const char code[] = "namespace external {\n"
|
||||
" namespace ns1 {\n"
|
||||
" template <int size> struct B { };\n"
|
||||
" using V = B<sizeof(bool)>;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"namespace ns {\n"
|
||||
" struct A {\n"
|
||||
" void f(external::ns1::V);\n"
|
||||
" };\n"
|
||||
"}\n"
|
||||
"namespace ns {\n"
|
||||
" void A::f(external::ns1::V) {}\n"
|
||||
"}";
|
||||
const char exp[] = "namespace external { "
|
||||
"namespace ns1 { "
|
||||
"struct B<1> ; "
|
||||
"} "
|
||||
"} "
|
||||
"namespace ns { "
|
||||
"struct A { "
|
||||
"void f ( external :: ns1 :: B<1> ) ; "
|
||||
"} ; "
|
||||
"} "
|
||||
"namespace ns { "
|
||||
"void A :: f ( external :: ns1 :: B<1> ) { } "
|
||||
"} "
|
||||
"struct external :: ns1 :: B<1> { } ;";
|
||||
ASSERT_EQUALS(exp, tok(code, true));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
{
|
||||
// using "namespace external::ns1;" without redundant qualification
|
||||
const char code[] = "namespace external {\n"
|
||||
" namespace ns1 {\n"
|
||||
" template <int size> struct B { };\n"
|
||||
" using V = B<sizeof(bool)>;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"namespace ns {\n"
|
||||
" struct A {\n"
|
||||
" void f(external::ns1::V);\n"
|
||||
" };\n"
|
||||
"}\n"
|
||||
"using namespace external::ns1;\n"
|
||||
"namespace ns {\n"
|
||||
" void A::f(V) {}\n"
|
||||
"}";
|
||||
const char exp[] = "namespace external { "
|
||||
"namespace ns1 { "
|
||||
"struct B<1> ; "
|
||||
"} "
|
||||
"} "
|
||||
"namespace ns { "
|
||||
"struct A { "
|
||||
"void f ( external :: ns1 :: B<1> ) ; "
|
||||
"} ; "
|
||||
"} "
|
||||
"using namespace external :: ns1 ; "
|
||||
"namespace ns { "
|
||||
"void A :: f ( external :: ns1 :: B<1> ) { } "
|
||||
"} "
|
||||
"struct external :: ns1 :: B<1> { } ;";
|
||||
ASSERT_EQUALS(exp, tok(code, true));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
{
|
||||
// using "namespace external::ns1;" without redundant qualification on declaration and definition
|
||||
const char code[] = "namespace external {\n"
|
||||
" namespace ns1 {\n"
|
||||
" template <int size> struct B { };\n"
|
||||
" using V = B<sizeof(bool)>;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"using namespace external::ns1;\n"
|
||||
"namespace ns {\n"
|
||||
" struct A {\n"
|
||||
" void f(V);\n"
|
||||
" };\n"
|
||||
"}\n"
|
||||
"namespace ns {\n"
|
||||
" void A::f(V) {}\n"
|
||||
"}";
|
||||
const char exp[] = "namespace external { "
|
||||
"namespace ns1 { "
|
||||
"struct B<1> ; "
|
||||
"} "
|
||||
"} "
|
||||
"using namespace external :: ns1 ; "
|
||||
"namespace ns { "
|
||||
"struct A { "
|
||||
"void f ( external :: ns1 :: B<1> ) ; "
|
||||
"} ; "
|
||||
"} "
|
||||
"namespace ns { "
|
||||
"void A :: f ( external :: ns1 :: B<1> ) { } "
|
||||
"} "
|
||||
"struct external :: ns1 :: B<1> { } ;";
|
||||
ASSERT_EQUALS(exp, tok(code, true));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
{
|
||||
const char code[] = "namespace external {\n"
|
||||
" template <int size> struct B { };\n"
|
||||
" namespace ns1 {\n"
|
||||
" using V = B<sizeof(bool)>;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"namespace ns {\n"
|
||||
" struct A {\n"
|
||||
" void f(external::ns1::V);\n"
|
||||
" };\n"
|
||||
"}\n"
|
||||
"namespace ns {\n"
|
||||
" void A::f(external::ns1::V) {}\n"
|
||||
"}";
|
||||
const char exp[] = "namespace external { "
|
||||
"struct B<1> ; "
|
||||
"} "
|
||||
"namespace ns { "
|
||||
"struct A { "
|
||||
"void f ( external :: B<1> ) ; "
|
||||
"} ; "
|
||||
"} "
|
||||
"namespace ns { "
|
||||
"void A :: f ( external :: B<1> ) { } "
|
||||
"} "
|
||||
"struct external :: B<1> { } ;";
|
||||
ASSERT_EQUALS(exp, tok(code, true));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
{
|
||||
const char code[] = "template <int size> struct B { };\n"
|
||||
"namespace external {\n"
|
||||
" namespace ns1 {\n"
|
||||
" using V = B<sizeof(bool)>;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"namespace ns {\n"
|
||||
" struct A {\n"
|
||||
" void f(external::ns1::V);\n"
|
||||
" };\n"
|
||||
"}\n"
|
||||
"namespace ns {\n"
|
||||
" void A::f(external::ns1::V) {}\n"
|
||||
"}";
|
||||
const char exp[] = "struct B<1> ; "
|
||||
"namespace ns { "
|
||||
"struct A { "
|
||||
"void f ( B<1> ) ; "
|
||||
"} ; "
|
||||
"} "
|
||||
"namespace ns { "
|
||||
"void A :: f ( B<1> ) { } "
|
||||
"} "
|
||||
"struct B<1> { } ;";
|
||||
ASSERT_EQUALS(exp, tok(code, true));
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestSimplifyUsing)
|
||||
|
|
Loading…
Reference in New Issue