Skip to content

Commit 277da76

Browse files
authored
fix #10054 (debug: Executable scope 'x' with unknown function.) (cppcheck-opensource#2994)
1 parent cb9efcb commit 277da76

4 files changed

Lines changed: 240 additions & 2 deletions

File tree

lib/templatesimplifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3690,7 +3690,7 @@ void TemplateSimplifier::simplifyTemplates(
36903690
if (mTemplateDeclarations.empty() && mTemplateForwardDeclarations.empty())
36913691
return;
36923692

3693-
if (passCount != 0 && mSettings->debugtemplate && mSettings->debugnormal) {
3693+
if (mSettings->debugtemplate && mSettings->debugnormal) {
36943694
std::string title("Template Simplifier pass " + std::to_string(passCount + 1));
36953695
mTokenList.front()->printOut(title.c_str(), mTokenList.getFiles());
36963696
}

lib/tokenize.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,6 +1702,7 @@ namespace {
17021702
const Token * const bodyStart;
17031703
const Token * const bodyEnd;
17041704
std::set<std::string> usingNamespaces;
1705+
std::set<std::string> recordTypes;
17051706
};
17061707

17071708
std::string getScopeName(const std::list<ScopeInfo3> &scopeInfo)
@@ -1778,12 +1779,16 @@ namespace {
17781779
return;
17791780
}
17801781

1782+
const bool record = Token::Match(tok, "class|struct|union %name%");
17811783
tok = tok->next();
17821784
std::string classname = tok->str();
17831785
while (Token::Match(tok, "%name% :: %name%")) {
17841786
tok = tok->tokAt(2);
17851787
classname += " :: " + tok->str();
17861788
}
1789+
// add record type to scope info
1790+
if (record)
1791+
scopeInfo->back().recordTypes.insert(classname);
17871792
tok = tok->next();
17881793
if (tok && tok->str() == ":") {
17891794
while (tok && !Token::Match(tok, ";|{"))
@@ -1968,6 +1973,11 @@ bool Tokenizer::simplifyUsing()
19681973

19691974
// skip template declarations
19701975
if (Token::Match(tok, "template < !!>")) {
1976+
// add template record type to scope info
1977+
const Token *end = tok->next()->findClosingBracket();
1978+
if (end && Token::Match(end->next(), "class|struct|union %name%"))
1979+
scopeList.back().recordTypes.insert(end->strAt(2));
1980+
19711981
Token *endToken = TemplateSimplifier::findTemplateDeclarationEnd(tok);
19721982
if (endToken)
19731983
tok = endToken;
@@ -2088,7 +2098,9 @@ bool Tokenizer::simplifyUsing()
20882098

20892099
// remove the qualification
20902100
std::string fullScope = scope;
2101+
std::string removed;
20912102
while (tok1->strAt(-1) == "::") {
2103+
removed = (tok1->strAt(-2) + " :: ") + removed;
20922104
if (fullScope == tok1->strAt(-2)) {
20932105
tok1->deletePrevious();
20942106
tok1->deletePrevious();
@@ -2220,6 +2232,32 @@ bool Tokenizer::simplifyUsing()
22202232
substitute = true;
22212233
}
22222234
} else {
2235+
// add some qualification back if needed
2236+
std::string removed1 = removed;
2237+
std::string::size_type idx = removed1.rfind(" ::");
2238+
if (idx != std::string::npos)
2239+
removed1.resize(idx);
2240+
if (removed1 == scope && !removed1.empty()) {
2241+
for (std::list<ScopeInfo3>::const_reverse_iterator it = scopeList.crbegin(); it != scopeList.crend(); ++it) {
2242+
if (it->recordTypes.find(start->str()) != it->recordTypes.end()) {
2243+
std::string::size_type spaceIdx = 0;
2244+
std::string::size_type startIdx = 0;
2245+
while ((spaceIdx = removed1.find(" ", startIdx)) != std::string::npos) {
2246+
tok1->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx).c_str());
2247+
startIdx = spaceIdx + 1;
2248+
}
2249+
tok1->previous()->insertToken(removed1.substr(startIdx).c_str());
2250+
tok1->previous()->insertToken("::");
2251+
break;
2252+
}
2253+
idx = removed1.rfind(" ::");
2254+
if (idx == std::string::npos)
2255+
break;
2256+
2257+
removed1.resize(idx);
2258+
}
2259+
}
2260+
22232261
// just replace simple type aliases
22242262
TokenList::copyTokens(tok1, start, usingEnd->previous());
22252263
tok1->deleteThis();

test/testsimplifytemplate.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ class TestSimplifyTemplate : public TestFixture {
207207
TEST_CASE(template162);
208208
TEST_CASE(template163); // #9685 syntax error
209209
TEST_CASE(template164); // #9394
210-
TEST_CASE(template162); // #10032 syntax error
210+
TEST_CASE(template165); // #10032 syntax error
211211
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
212212
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
213213
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)

test/testsimplifyusing.cpp

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class TestSimplifyUsing : public TestFixture {
7676
TEST_CASE(simplifyUsing9518);
7777
TEST_CASE(simplifyUsing9757);
7878
TEST_CASE(simplifyUsing10008);
79+
TEST_CASE(simplifyUsing10054);
7980
}
8081

8182
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Native, bool debugwarnings = true) {
@@ -663,6 +664,205 @@ class TestSimplifyUsing : public TestFixture {
663664
"}";
664665
ASSERT_EQUALS(exp, tok(code, false));
665666
}
667+
668+
void simplifyUsing10054() { // debug: Executable scope 'x' with unknown function.
669+
{
670+
// original example: using "namespace external::ns1;" but redundant qualification
671+
const char code[] = "namespace external {\n"
672+
" namespace ns1 {\n"
673+
" template <int size> struct B { };\n"
674+
" using V = B<sizeof(bool)>;\n"
675+
" }\n"
676+
"}\n"
677+
"namespace ns {\n"
678+
" struct A {\n"
679+
" void f(external::ns1::V);\n"
680+
" };\n"
681+
"}\n"
682+
"using namespace external::ns1;\n"
683+
"namespace ns {\n"
684+
" void A::f(external::ns1::V) {}\n"
685+
"}";
686+
const char exp[] = "namespace external { "
687+
"namespace ns1 { "
688+
"struct B<1> ; "
689+
"} "
690+
"} "
691+
"namespace ns { "
692+
"struct A { "
693+
"void f ( external :: ns1 :: B<1> ) ; "
694+
"} ; "
695+
"} "
696+
"using namespace external :: ns1 ; "
697+
"namespace ns { "
698+
"void A :: f ( external :: ns1 :: B<1> ) { } "
699+
"} "
700+
"struct external :: ns1 :: B<1> { } ;";
701+
ASSERT_EQUALS(exp, tok(code, true));
702+
ASSERT_EQUALS("", errout.str());
703+
}
704+
{
705+
// no using "namespace external::ns1;"
706+
const char code[] = "namespace external {\n"
707+
" namespace ns1 {\n"
708+
" template <int size> struct B { };\n"
709+
" using V = B<sizeof(bool)>;\n"
710+
" }\n"
711+
"}\n"
712+
"namespace ns {\n"
713+
" struct A {\n"
714+
" void f(external::ns1::V);\n"
715+
" };\n"
716+
"}\n"
717+
"namespace ns {\n"
718+
" void A::f(external::ns1::V) {}\n"
719+
"}";
720+
const char exp[] = "namespace external { "
721+
"namespace ns1 { "
722+
"struct B<1> ; "
723+
"} "
724+
"} "
725+
"namespace ns { "
726+
"struct A { "
727+
"void f ( external :: ns1 :: B<1> ) ; "
728+
"} ; "
729+
"} "
730+
"namespace ns { "
731+
"void A :: f ( external :: ns1 :: B<1> ) { } "
732+
"} "
733+
"struct external :: ns1 :: B<1> { } ;";
734+
ASSERT_EQUALS(exp, tok(code, true));
735+
ASSERT_EQUALS("", errout.str());
736+
}
737+
{
738+
// using "namespace external::ns1;" without redundant qualification
739+
const char code[] = "namespace external {\n"
740+
" namespace ns1 {\n"
741+
" template <int size> struct B { };\n"
742+
" using V = B<sizeof(bool)>;\n"
743+
" }\n"
744+
"}\n"
745+
"namespace ns {\n"
746+
" struct A {\n"
747+
" void f(external::ns1::V);\n"
748+
" };\n"
749+
"}\n"
750+
"using namespace external::ns1;\n"
751+
"namespace ns {\n"
752+
" void A::f(V) {}\n"
753+
"}";
754+
const char exp[] = "namespace external { "
755+
"namespace ns1 { "
756+
"struct B<1> ; "
757+
"} "
758+
"} "
759+
"namespace ns { "
760+
"struct A { "
761+
"void f ( external :: ns1 :: B<1> ) ; "
762+
"} ; "
763+
"} "
764+
"using namespace external :: ns1 ; "
765+
"namespace ns { "
766+
"void A :: f ( external :: ns1 :: B<1> ) { } "
767+
"} "
768+
"struct external :: ns1 :: B<1> { } ;";
769+
ASSERT_EQUALS(exp, tok(code, true));
770+
ASSERT_EQUALS("", errout.str());
771+
}
772+
{
773+
// using "namespace external::ns1;" without redundant qualification on declaration and definition
774+
const char code[] = "namespace external {\n"
775+
" namespace ns1 {\n"
776+
" template <int size> struct B { };\n"
777+
" using V = B<sizeof(bool)>;\n"
778+
" }\n"
779+
"}\n"
780+
"using namespace external::ns1;\n"
781+
"namespace ns {\n"
782+
" struct A {\n"
783+
" void f(V);\n"
784+
" };\n"
785+
"}\n"
786+
"namespace ns {\n"
787+
" void A::f(V) {}\n"
788+
"}";
789+
const char exp[] = "namespace external { "
790+
"namespace ns1 { "
791+
"struct B<1> ; "
792+
"} "
793+
"} "
794+
"using namespace external :: ns1 ; "
795+
"namespace ns { "
796+
"struct A { "
797+
"void f ( external :: ns1 :: B<1> ) ; "
798+
"} ; "
799+
"} "
800+
"namespace ns { "
801+
"void A :: f ( external :: ns1 :: B<1> ) { } "
802+
"} "
803+
"struct external :: ns1 :: B<1> { } ;";
804+
ASSERT_EQUALS(exp, tok(code, true));
805+
ASSERT_EQUALS("", errout.str());
806+
}
807+
{
808+
const char code[] = "namespace external {\n"
809+
" template <int size> struct B { };\n"
810+
" namespace ns1 {\n"
811+
" using V = B<sizeof(bool)>;\n"
812+
" }\n"
813+
"}\n"
814+
"namespace ns {\n"
815+
" struct A {\n"
816+
" void f(external::ns1::V);\n"
817+
" };\n"
818+
"}\n"
819+
"namespace ns {\n"
820+
" void A::f(external::ns1::V) {}\n"
821+
"}";
822+
const char exp[] = "namespace external { "
823+
"struct B<1> ; "
824+
"} "
825+
"namespace ns { "
826+
"struct A { "
827+
"void f ( external :: B<1> ) ; "
828+
"} ; "
829+
"} "
830+
"namespace ns { "
831+
"void A :: f ( external :: B<1> ) { } "
832+
"} "
833+
"struct external :: B<1> { } ;";
834+
ASSERT_EQUALS(exp, tok(code, true));
835+
ASSERT_EQUALS("", errout.str());
836+
}
837+
{
838+
const char code[] = "template <int size> struct B { };\n"
839+
"namespace external {\n"
840+
" namespace ns1 {\n"
841+
" using V = B<sizeof(bool)>;\n"
842+
" }\n"
843+
"}\n"
844+
"namespace ns {\n"
845+
" struct A {\n"
846+
" void f(external::ns1::V);\n"
847+
" };\n"
848+
"}\n"
849+
"namespace ns {\n"
850+
" void A::f(external::ns1::V) {}\n"
851+
"}";
852+
const char exp[] = "struct B<1> ; "
853+
"namespace ns { "
854+
"struct A { "
855+
"void f ( B<1> ) ; "
856+
"} ; "
857+
"} "
858+
"namespace ns { "
859+
"void A :: f ( B<1> ) { } "
860+
"} "
861+
"struct B<1> { } ;";
862+
ASSERT_EQUALS(exp, tok(code, true));
863+
ASSERT_EQUALS("", errout.str());
864+
}
865+
}
666866
};
667867

668868
REGISTER_TEST(TestSimplifyUsing)

0 commit comments

Comments
 (0)