Fix FN unusedStructMember with member functions, inheritance (#4978)

* Fix #551 Detect unused Private member variables

* Fix FN unusedStructMember when there are member functions

* Unused member

* Warn for unused private variables in base class

* Warn for private inheritance, add test
This commit is contained in:
chrchr-github 2023-04-18 22:30:08 +02:00 committed by GitHub
parent 9cc56fb660
commit 35a46dfd00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 9 deletions

View File

@ -919,7 +919,7 @@ struct InvalidContainerAnalyzer {
const Token* ftok; const Token* ftok;
}; };
std::unordered_map<int, Reference> expressions; std::unordered_map<int, Reference> expressions;
ErrorPath errorPath;
void add(const std::vector<Reference>& refs) { void add(const std::vector<Reference>& refs) {
for (const Reference& r : refs) { for (const Reference& r : refs) {
add(r); add(r);

View File

@ -1455,25 +1455,20 @@ void CheckUnusedVar::checkStructMemberUsage()
continue; continue;
} }
// Bail out if struct/union contains any functions
if (!scope.functionList.empty())
continue;
// Bail out for template struct, members might be used in non-matching instantiations // Bail out for template struct, members might be used in non-matching instantiations
if (scope.className.find('<') != std::string::npos) if (scope.className.find('<') != std::string::npos)
continue; continue;
// bail out if struct is inherited // bail out if struct is inherited
bool bailout = std::any_of(symbolDatabase->scopeList.cbegin(), symbolDatabase->scopeList.cend(), [&](const Scope& derivedScope) { const bool isInherited = std::any_of(symbolDatabase->scopeList.cbegin(), symbolDatabase->scopeList.cend(), [&](const Scope& derivedScope) {
const Type* dType = derivedScope.definedType; const Type* dType = derivedScope.definedType;
return dType && std::any_of(dType->derivedFrom.cbegin(), dType->derivedFrom.cend(), [&](const Type::BaseInfo& derivedFrom) { return dType && std::any_of(dType->derivedFrom.cbegin(), dType->derivedFrom.cend(), [&](const Type::BaseInfo& derivedFrom) {
return derivedFrom.type == scope.definedType; return derivedFrom.type == scope.definedType && derivedFrom.access != AccessControl::Private;
}); });
}); });
if (bailout)
continue;
// bail out for extern/global struct // bail out for extern/global struct
bool bailout = false;
for (const Variable* var : symbolDatabase->variableList()) { for (const Variable* var : symbolDatabase->variableList()) {
if (var && (var->isExtern() || (var->isGlobal() && !var->isStatic())) && var->typeEndToken()->str() == scope.className) { if (var && (var->isExtern() || (var->isGlobal() && !var->isStatic())) && var->typeEndToken()->str() == scope.className) {
bailout = true; bailout = true;
@ -1510,6 +1505,8 @@ void CheckUnusedVar::checkStructMemberUsage()
// only warn for variables without side effects // only warn for variables without side effects
if (!var.typeStartToken()->isStandardType() && !var.isPointer() && !astIsContainer(var.nameToken()) && !isRecordTypeWithoutSideEffects(var.type())) if (!var.typeStartToken()->isStandardType() && !var.isPointer() && !astIsContainer(var.nameToken()) && !isRecordTypeWithoutSideEffects(var.type()))
continue; continue;
if (isInherited && !var.isPrivate())
continue;
// Check if the struct member variable is used anywhere in the file // Check if the struct member variable is used anywhere in the file
bool use = false; bool use = false;

View File

@ -1876,6 +1876,34 @@ private:
" int i{};\n" " int i{};\n"
"};\n"); "};\n");
ASSERT_EQUALS("[test.cpp:2]: (style) class member 'C::i' is never used.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (style) class member 'C::i' is never used.\n", errout.str());
checkStructMemberUsage("class C {\n"
" int i{}, j{};\n"
"public:\n"
" int& get() { return i; }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:2]: (style) class member 'C::j' is never used.\n", errout.str());
checkStructMemberUsage("class C {\n"
"private:\n"
" int i;\n"
"};\n"
"class D : public C {};\n");
ASSERT_EQUALS("[test.cpp:3]: (style) class member 'C::i' is never used.\n", errout.str());
checkStructMemberUsage("class C {\n"
"public:\n"
" int i;\n"
"};\n"
"class D : C {};\n");
ASSERT_EQUALS("[test.cpp:3]: (style) class member 'C::i' is never used.\n", errout.str());
checkStructMemberUsage("class C {\n"
"public:\n"
" int i;\n"
"};\n"
"class D : public C {};\n");
ASSERT_EQUALS("", errout.str());
} }
void functionVariableUsage_(const char* file, int line, const char code[], const char filename[] = "test.cpp") { void functionVariableUsage_(const char* file, int line, const char code[], const char filename[] = "test.cpp") {