fix extra qualification check for same class name in different namespaces

This commit is contained in:
Robert Reif 2011-06-14 15:31:52 -04:00
parent be57aa5ad5
commit eaf836b323
2 changed files with 88 additions and 15 deletions

View File

@ -9788,40 +9788,52 @@ void Tokenizer::simplifyOperatorName()
} }
// remove unnecessary member qualification.. // remove unnecessary member qualification..
struct ClassInfo
{
std::string className;
Token *end;
};
void Tokenizer::removeUnnecessaryQualification() void Tokenizer::removeUnnecessaryQualification()
{ {
std::stack<ClassInfo> classInfo; std::vector<Space> classInfo;
for (Token *tok = _tokens; tok; tok = tok->next()) for (Token *tok = _tokens; tok; tok = tok->next())
{ {
if (Token::Match(tok, "class|struct %type% :|{") && if (Token::Match(tok, "class|struct|namespace %type% :|{") &&
(!tok->previous() || (tok->previous() && tok->previous()->str() != "enum"))) (!tok->previous() || (tok->previous() && tok->previous()->str() != "enum")))
{ {
tok = tok->next(); tok = tok->next();
ClassInfo info; Space info;
info.isNamespace = tok->str() == "namespace";
info.className = tok->str(); info.className = tok->str();
tok = tok->next(); tok = tok->next();
while (tok && tok->str() != "{") while (tok && tok->str() != "{")
tok = tok->next(); tok = tok->next();
if (!tok) if (!tok)
return; return;
info.end = tok->link(); info.classEnd = tok->link();
classInfo.push(info); classInfo.push_back(info);
} }
else if (!classInfo.empty()) else if (!classInfo.empty())
{ {
if (tok == classInfo.top().end) if (tok == classInfo.back().classEnd)
classInfo.pop(); classInfo.pop_back();
else if (tok->str() == classInfo.top().className && else if (tok->str() == classInfo.back().className &&
Token::Match(tok, "%type% :: %type% (") && Token::Match(tok, "%type% :: %type% (") &&
Token::Match(tok->tokAt(3)->link(), ") const| {|;") && Token::Match(tok->tokAt(3)->link(), ") const| {|;") &&
tok->previous()->str() != ":") tok->previous()->str() != ":")
{ {
std::string qualification = tok->str() + "::";
// check for extra qualification
/** @todo this should be made more generic to handle more levels */
if (Token::Match(tok->tokAt(-2), "%type% ::"))
{
if (classInfo.size() >= 2)
{
if (classInfo.at(classInfo.size() - 2).className != tok->strAt(-2))
continue;
else
qualification = tok->strAt(-2) + "::" + qualification;
}
else
continue;
}
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList; std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
ErrorLogger::ErrorMessage::FileLocation loc; ErrorLogger::ErrorMessage::FileLocation loc;
loc.line = tok->linenr(); loc.line = tok->linenr();
@ -9830,7 +9842,7 @@ void Tokenizer::removeUnnecessaryQualification()
const ErrorLogger::ErrorMessage errmsg(locationList, const ErrorLogger::ErrorMessage errmsg(locationList,
Severity::portability, Severity::portability,
"Extra qualification \'" + tok->str() + "::\' unnecessary and considered an error by many compilers.", "Extra qualification \'" + qualification + "\' unnecessary and considered an error by many compilers.",
"portability", "portability",
false); false);

View File

@ -350,6 +350,9 @@ private:
TEST_CASE(removeUnnecessaryQualification1); TEST_CASE(removeUnnecessaryQualification1);
TEST_CASE(removeUnnecessaryQualification2); TEST_CASE(removeUnnecessaryQualification2);
TEST_CASE(removeUnnecessaryQualification3);
TEST_CASE(removeUnnecessaryQualification4);
TEST_CASE(removeUnnecessaryQualification5);
TEST_CASE(simplifyIfNotNull); TEST_CASE(simplifyIfNotNull);
TEST_CASE(simplifyVarDecl1); // ticket # 2682 segmentation fault TEST_CASE(simplifyVarDecl1); // ticket # 2682 segmentation fault
@ -6970,6 +6973,64 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void removeUnnecessaryQualification3()
{
const char code[] = "namespace one {\n"
" class c {\n"
" public:\n"
" void function() {}\n"
" };\n"
"}\n"
"namespace two {\n"
" class c : public one::c {\n"
" public:\n"
" void function() {\n"
" one::c::function();\n"
" }\n"
" };\n"
"}\n";
tok(code, false);
ASSERT_EQUALS("", errout.str());
}
void removeUnnecessaryQualification4()
{
const char code[] = "namespace one {\n"
" class c {\n"
" public:\n"
" void function() {}\n"
" };\n"
"}\n"
"class c : public one::c {\n"
"public:\n"
" void function() {\n"
" one::c::function();\n"
" }\n"
"};\n";
tok(code, false);
ASSERT_EQUALS("", errout.str());
}
void removeUnnecessaryQualification5()
{
const char code[] = "namespace one {\n"
" class c {\n"
" public:\n"
" void function() {}\n"
" };\n"
"}\n"
"namespace two {\n"
" class c : public one::c {\n"
" public:\n"
" void function() {\n"
" two::c::function();\n"
" }\n"
" };\n"
"}\n";
tok(code, false);
ASSERT_EQUALS("[test.cpp:11]: (portability) Extra qualification 'two::c::' unnecessary and considered an error by many compilers.\n", errout.str());
}
void simplifyIfNotNull() void simplifyIfNotNull()
{ {
{ {