This commit is contained in:
parent
cb9efcb100
commit
277da763aa
|
@ -3690,7 +3690,7 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
if (mTemplateDeclarations.empty() && mTemplateForwardDeclarations.empty())
|
if (mTemplateDeclarations.empty() && mTemplateForwardDeclarations.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (passCount != 0 && mSettings->debugtemplate && mSettings->debugnormal) {
|
if (mSettings->debugtemplate && mSettings->debugnormal) {
|
||||||
std::string title("Template Simplifier pass " + std::to_string(passCount + 1));
|
std::string title("Template Simplifier pass " + std::to_string(passCount + 1));
|
||||||
mTokenList.front()->printOut(title.c_str(), mTokenList.getFiles());
|
mTokenList.front()->printOut(title.c_str(), mTokenList.getFiles());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1702,6 +1702,7 @@ namespace {
|
||||||
const Token * const bodyStart;
|
const Token * const bodyStart;
|
||||||
const Token * const bodyEnd;
|
const Token * const bodyEnd;
|
||||||
std::set<std::string> usingNamespaces;
|
std::set<std::string> usingNamespaces;
|
||||||
|
std::set<std::string> recordTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string getScopeName(const std::list<ScopeInfo3> &scopeInfo)
|
std::string getScopeName(const std::list<ScopeInfo3> &scopeInfo)
|
||||||
|
@ -1778,12 +1779,16 @@ namespace {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool record = Token::Match(tok, "class|struct|union %name%");
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
std::string classname = tok->str();
|
std::string classname = tok->str();
|
||||||
while (Token::Match(tok, "%name% :: %name%")) {
|
while (Token::Match(tok, "%name% :: %name%")) {
|
||||||
tok = tok->tokAt(2);
|
tok = tok->tokAt(2);
|
||||||
classname += " :: " + tok->str();
|
classname += " :: " + tok->str();
|
||||||
}
|
}
|
||||||
|
// add record type to scope info
|
||||||
|
if (record)
|
||||||
|
scopeInfo->back().recordTypes.insert(classname);
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
if (tok && tok->str() == ":") {
|
if (tok && tok->str() == ":") {
|
||||||
while (tok && !Token::Match(tok, ";|{"))
|
while (tok && !Token::Match(tok, ";|{"))
|
||||||
|
@ -1968,6 +1973,11 @@ bool Tokenizer::simplifyUsing()
|
||||||
|
|
||||||
// skip template declarations
|
// skip template declarations
|
||||||
if (Token::Match(tok, "template < !!>")) {
|
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);
|
Token *endToken = TemplateSimplifier::findTemplateDeclarationEnd(tok);
|
||||||
if (endToken)
|
if (endToken)
|
||||||
tok = endToken;
|
tok = endToken;
|
||||||
|
@ -2088,7 +2098,9 @@ bool Tokenizer::simplifyUsing()
|
||||||
|
|
||||||
// remove the qualification
|
// remove the qualification
|
||||||
std::string fullScope = scope;
|
std::string fullScope = scope;
|
||||||
|
std::string removed;
|
||||||
while (tok1->strAt(-1) == "::") {
|
while (tok1->strAt(-1) == "::") {
|
||||||
|
removed = (tok1->strAt(-2) + " :: ") + removed;
|
||||||
if (fullScope == tok1->strAt(-2)) {
|
if (fullScope == tok1->strAt(-2)) {
|
||||||
tok1->deletePrevious();
|
tok1->deletePrevious();
|
||||||
tok1->deletePrevious();
|
tok1->deletePrevious();
|
||||||
|
@ -2220,6 +2232,32 @@ bool Tokenizer::simplifyUsing()
|
||||||
substitute = true;
|
substitute = true;
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
// just replace simple type aliases
|
||||||
TokenList::copyTokens(tok1, start, usingEnd->previous());
|
TokenList::copyTokens(tok1, start, usingEnd->previous());
|
||||||
tok1->deleteThis();
|
tok1->deleteThis();
|
||||||
|
|
|
@ -207,7 +207,7 @@ private:
|
||||||
TEST_CASE(template162);
|
TEST_CASE(template162);
|
||||||
TEST_CASE(template163); // #9685 syntax error
|
TEST_CASE(template163); // #9685 syntax error
|
||||||
TEST_CASE(template164); // #9394
|
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_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)
|
||||||
|
|
|
@ -76,6 +76,7 @@ private:
|
||||||
TEST_CASE(simplifyUsing9518);
|
TEST_CASE(simplifyUsing9518);
|
||||||
TEST_CASE(simplifyUsing9757);
|
TEST_CASE(simplifyUsing9757);
|
||||||
TEST_CASE(simplifyUsing10008);
|
TEST_CASE(simplifyUsing10008);
|
||||||
|
TEST_CASE(simplifyUsing10054);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Native, bool debugwarnings = true) {
|
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));
|
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)
|
REGISTER_TEST(TestSimplifyUsing)
|
||||||
|
|
Loading…
Reference in New Issue