Fix FN for distinct structs with identical members

This commit is contained in:
Dmitry-Me 2015-09-24 18:29:08 +02:00 committed by Daniel Marjamäki
parent 14c792f41e
commit da15efb3f6
2 changed files with 48 additions and 11 deletions

View File

@ -1232,34 +1232,43 @@ void CheckUnusedVar::checkStructMemberUsage()
structname.clear(); structname.clear();
if (!structname.empty() && Token::Match(tok, "[{;]")) { if (!structname.empty() && Token::Match(tok, "[{;]")) {
// declaring a POD variable? // declaring a POD member variable?
if (!tok->next()->isStandardType()) if (!tok->next()->isStandardType())
continue; continue;
// Declaring struct variable.. // Declaring struct member variable..
const std::string* varname; const std::string* memberVarName;
if (Token::Match(tok->next(), "%type% %name% [;[]")) if (Token::Match(tok->next(), "%type% %name% [;[]"))
varname = &tok->strAt(2); memberVarName = &tok->strAt(2);
else if (Token::Match(tok->next(), "%type% %type%|* %name% [;[]")) else if (Token::Match(tok->next(), "%type% %type%|* %name% [;[]"))
varname = &tok->strAt(3); memberVarName = &tok->strAt(3);
else if (Token::Match(tok->next(), "%type% %type% * %name% [;[]")) else if (Token::Match(tok->next(), "%type% %type% * %name% [;[]"))
varname = &tok->strAt(4); memberVarName = &tok->strAt(4);
else else
continue; continue;
// Check if the struct variable is used anywhere in the file // Check if the struct member variable is used anywhere in the file
const std::string usagePattern(". " + *varname); const std::string usagePattern(". " + *memberVarName);
bool used = false; bool used = false;
for (const Token *tok2 = _tokenizer->tokens(); tok2; tok2 = tok2->next()) { const Token* usageTok = _tokenizer->tokens();
if (Token::simpleMatch(tok2, usagePattern.c_str())) { while ((usageTok = Token::findsimplematch(usageTok->next(), usagePattern.c_str())) != nullptr) {
// Locate the containing struct variable and ensure it's of the same type, not a random struct
const Token* structVarTok = usageTok->previous();
// Walk backwards over array accesses
while (structVarTok && structVarTok->link())
structVarTok = structVarTok->link()->previous();
if (!structVarTok)
continue;
const Variable* structVar = structVarTok->variable();
if (structVar && structVar->type() && structVar->type()->name() == structname) {
used = true; used = true;
break; break;
} }
} }
if (!used) { if (!used) {
unusedStructMemberError(tok->next(), structname, *varname, tok->scope()->type == Scope::eUnion); unusedStructMemberError(tok->next(), structname, *memberVarName, tok->scope()->type == Scope::eUnion);
} }
} }
} }

View File

@ -222,6 +222,34 @@ private:
"[test.cpp:4]: (style) union member 'abc::b' is never used.\n" "[test.cpp:4]: (style) union member 'abc::b' is never used.\n"
"[test.cpp:5]: (style) union member 'abc::c' is never used.\n", errout.str()); "[test.cpp:5]: (style) union member 'abc::c' is never used.\n", errout.str());
checkStructMemberUsage("struct A\n"
"{\n"
" int a;\n"
"};\n"
"struct B\n"
"{\n"
" int a;\n"
"};\n"
"void foo()\n"
"{\n"
" A a;\n"
" a.a;\n"
"}");
ASSERT_EQUALS("[test.cpp:7]: (style) struct member 'B::a' is never used.\n", errout.str());
checkStructMemberUsage("struct A\n"
"{\n"
" int a;\n"
"};\n"
"struct B\n"
"{\n"
" int a;\n"
"};\n"
"void foo(A* a)\n"
"{\n"
" a->a;\n"
"}");
ASSERT_EQUALS("[test.cpp:7]: (style) struct member 'B::a' is never used.\n", errout.str());
} }
void structmember2() { void structmember2() {