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:
parent
9cc56fb660
commit
35a46dfd00
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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") {
|
||||||
|
|
Loading…
Reference in New Issue