Skip to content

Commit

Permalink
Fix #10660 FP: overridden member functions of unknown abstract base c…
Browse files Browse the repository at this point in the history
…lasses reported as unused (danmar#6564)
  • Loading branch information
chrchr-github committed Jul 4, 2024
1 parent a6cc9b2 commit 4be49b3
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 12 deletions.
9 changes: 1 addition & 8 deletions .selfcheck_unused_suppressions
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
# we are not using all methods of their interfaces
unusedFunction:externals/*/*

# TODO: fix these
# false positive - # 10660
unusedFunction:gui/mainwindow.cpp
unusedFunction:gui/resultstree.cpp
unusedFunction:gui/codeeditor.*
# usage is disabled
unusedFunction:lib/symboldatabase.cpp
# false positive - #10661
unusedFunction:oss-fuzz/main.cpp

# Q_OBJECT functions which are not called in our code
unusedFunction:cmake.output.notest/gui/cppcheck-gui_autogen/*/moc_aboutdialog.cpp
unusedFunction:cmake.output.notest/gui/cppcheck-gui_autogen/*/moc_aboutdialog.cpp
9 changes: 9 additions & 0 deletions lib/checkunusedfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting
if (func->isExtern())
continue;

bool foundAllBaseClasses{};
if (const Function* ofunc = func->getOverriddenFunction(&foundAllBaseClasses)) {
if (!foundAllBaseClasses || ofunc->isPure())
continue;
}
else if (func->isImplicitlyVirtual()) {
continue;
}

mFunctionDecl.emplace_back(func);

FunctionUsage &usage = mFunctions[stripTemplateParameters(func->name())];
Expand Down
4 changes: 1 addition & 3 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4554,9 +4554,7 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s

bool Function::isImplicitlyVirtual(bool defaultVal) const
{
if (hasVirtualSpecifier()) //If it has the virtual specifier it's definitely virtual
return true;
if (hasOverrideSpecifier()) //If it has the override specifier then it's either virtual or not going to compile
if (hasVirtualSpecifier() || hasOverrideSpecifier() || hasFinalSpecifier())
return true;
bool foundAllBaseClasses = true;
if (getOverriddenFunction(&foundAllBaseClasses)) //If it overrides a base class's method then it's virtual
Expand Down
2 changes: 1 addition & 1 deletion test/cli/other_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ def test_showtime_top5_file(tmpdir):
elif lines[i].startswith('valueFlowEnumValue'):
assert lines[i].endswith(' - 2 result(s))')
else:
assert lines[i].endswith(' - 1 result(s))')
assert lines[i].endswith(' result(s))')
assert lines[6].startswith('Overall time:')
assert stderr == ''

Expand Down
24 changes: 24 additions & 0 deletions test/testunusedfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class TestUnusedFunctions : public TestFixture {
TEST_CASE(entrypointsUnix);

TEST_CASE(includes);
TEST_CASE(virtualFunc);
}

#define check(...) check_(__FILE__, __LINE__, __VA_ARGS__)
Expand Down Expand Up @@ -711,6 +712,29 @@ class TestUnusedFunctions : public TestFixture {
check(processed);
TODO_ASSERT_EQUALS("[test.h:3]: (style) The function 'f' is never used.\n", "[test.cpp:3]: (style) The function 'f' is never used.\n", errout_str());
}

void virtualFunc()
{
check("struct D : public B {\n" // #10660
" virtual void f() {}\n"
" void g() override {}\n"
" void h() final {}\n"
"};\n");
ASSERT_EQUALS("", errout_str());

check("struct B {\n"
" virtual void f() = 0;\n"
" void g();\n"
"};\n"
"struct D : B {\n"
" void f() override {}\n"
"};\n"
"int main() {\n"
" D d;\n"
" d.g();\n"
"}\n");
ASSERT_EQUALS("", errout_str());
}
};

REGISTER_TEST(TestUnusedFunctions)

0 comments on commit 4be49b3

Please sign in to comment.