Skip to content

Commit eaf836b

Browse files
committed
fix extra qualification check for same class name in different namespaces
1 parent be57aa5 commit eaf836b

2 files changed

Lines changed: 88 additions & 15 deletions

File tree

lib/tokenize.cpp

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9788,40 +9788,52 @@ void Tokenizer::simplifyOperatorName()
97889788
}
97899789

97909790
// remove unnecessary member qualification..
9791-
struct ClassInfo
9792-
{
9793-
std::string className;
9794-
Token *end;
9795-
};
9796-
97979791
void Tokenizer::removeUnnecessaryQualification()
97989792
{
9799-
std::stack<ClassInfo> classInfo;
9793+
std::vector<Space> classInfo;
98009794
for (Token *tok = _tokens; tok; tok = tok->next())
98019795
{
9802-
if (Token::Match(tok, "class|struct %type% :|{") &&
9796+
if (Token::Match(tok, "class|struct|namespace %type% :|{") &&
98039797
(!tok->previous() || (tok->previous() && tok->previous()->str() != "enum")))
98049798
{
98059799
tok = tok->next();
9806-
ClassInfo info;
9800+
Space info;
9801+
info.isNamespace = tok->str() == "namespace";
98079802
info.className = tok->str();
98089803
tok = tok->next();
98099804
while (tok && tok->str() != "{")
98109805
tok = tok->next();
98119806
if (!tok)
98129807
return;
9813-
info.end = tok->link();
9814-
classInfo.push(info);
9808+
info.classEnd = tok->link();
9809+
classInfo.push_back(info);
98159810
}
98169811
else if (!classInfo.empty())
98179812
{
9818-
if (tok == classInfo.top().end)
9819-
classInfo.pop();
9820-
else if (tok->str() == classInfo.top().className &&
9813+
if (tok == classInfo.back().classEnd)
9814+
classInfo.pop_back();
9815+
else if (tok->str() == classInfo.back().className &&
98219816
Token::Match(tok, "%type% :: %type% (") &&
98229817
Token::Match(tok->tokAt(3)->link(), ") const| {|;") &&
98239818
tok->previous()->str() != ":")
98249819
{
9820+
std::string qualification = tok->str() + "::";
9821+
9822+
// check for extra qualification
9823+
/** @todo this should be made more generic to handle more levels */
9824+
if (Token::Match(tok->tokAt(-2), "%type% ::"))
9825+
{
9826+
if (classInfo.size() >= 2)
9827+
{
9828+
if (classInfo.at(classInfo.size() - 2).className != tok->strAt(-2))
9829+
continue;
9830+
else
9831+
qualification = tok->strAt(-2) + "::" + qualification;
9832+
}
9833+
else
9834+
continue;
9835+
}
9836+
98259837
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
98269838
ErrorLogger::ErrorMessage::FileLocation loc;
98279839
loc.line = tok->linenr();
@@ -9830,7 +9842,7 @@ void Tokenizer::removeUnnecessaryQualification()
98309842

98319843
const ErrorLogger::ErrorMessage errmsg(locationList,
98329844
Severity::portability,
9833-
"Extra qualification \'" + tok->str() + "::\' unnecessary and considered an error by many compilers.",
9845+
"Extra qualification \'" + qualification + "\' unnecessary and considered an error by many compilers.",
98349846
"portability",
98359847
false);
98369848

test/testsimplifytokens.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ class TestSimplifyTokens : public TestFixture
350350

351351
TEST_CASE(removeUnnecessaryQualification1);
352352
TEST_CASE(removeUnnecessaryQualification2);
353+
TEST_CASE(removeUnnecessaryQualification3);
354+
TEST_CASE(removeUnnecessaryQualification4);
355+
TEST_CASE(removeUnnecessaryQualification5);
353356

354357
TEST_CASE(simplifyIfNotNull);
355358
TEST_CASE(simplifyVarDecl1); // ticket # 2682 segmentation fault
@@ -6970,6 +6973,64 @@ class TestSimplifyTokens : public TestFixture
69706973
ASSERT_EQUALS("", errout.str());
69716974
}
69726975

6976+
void removeUnnecessaryQualification3()
6977+
{
6978+
const char code[] = "namespace one {\n"
6979+
" class c {\n"
6980+
" public:\n"
6981+
" void function() {}\n"
6982+
" };\n"
6983+
"}\n"
6984+
"namespace two {\n"
6985+
" class c : public one::c {\n"
6986+
" public:\n"
6987+
" void function() {\n"
6988+
" one::c::function();\n"
6989+
" }\n"
6990+
" };\n"
6991+
"}\n";
6992+
tok(code, false);
6993+
ASSERT_EQUALS("", errout.str());
6994+
}
6995+
6996+
void removeUnnecessaryQualification4()
6997+
{
6998+
const char code[] = "namespace one {\n"
6999+
" class c {\n"
7000+
" public:\n"
7001+
" void function() {}\n"
7002+
" };\n"
7003+
"}\n"
7004+
"class c : public one::c {\n"
7005+
"public:\n"
7006+
" void function() {\n"
7007+
" one::c::function();\n"
7008+
" }\n"
7009+
"};\n";
7010+
tok(code, false);
7011+
ASSERT_EQUALS("", errout.str());
7012+
}
7013+
7014+
void removeUnnecessaryQualification5()
7015+
{
7016+
const char code[] = "namespace one {\n"
7017+
" class c {\n"
7018+
" public:\n"
7019+
" void function() {}\n"
7020+
" };\n"
7021+
"}\n"
7022+
"namespace two {\n"
7023+
" class c : public one::c {\n"
7024+
" public:\n"
7025+
" void function() {\n"
7026+
" two::c::function();\n"
7027+
" }\n"
7028+
" };\n"
7029+
"}\n";
7030+
tok(code, false);
7031+
ASSERT_EQUALS("[test.cpp:11]: (portability) Extra qualification 'two::c::' unnecessary and considered an error by many compilers.\n", errout.str());
7032+
}
7033+
69737034
void simplifyIfNotNull()
69747035
{
69757036
{

0 commit comments

Comments
 (0)