From 19ec98fd0d08441f41f1b80f1efd1aca64a1917e Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 1 Jul 2024 23:00:40 +0200 Subject: [PATCH] Fix #10660 FP: overridden member functions of unknown abstract base classes reported as unused --- lib/checkunusedfunctions.cpp | 9 +++++++++ lib/symboldatabase.cpp | 4 +--- test/testunusedfunctions.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/checkunusedfunctions.cpp b/lib/checkunusedfunctions.cpp index 3fc19d340d7..fa914523813 100644 --- a/lib/checkunusedfunctions.cpp +++ b/lib/checkunusedfunctions.cpp @@ -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())]; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 31e54535512..a6d9c9bd928 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -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 diff --git a/test/testunusedfunctions.cpp b/test/testunusedfunctions.cpp index 2b1773f2f66..4be243363ac 100644 --- a/test/testunusedfunctions.cpp +++ b/test/testunusedfunctions.cpp @@ -82,6 +82,7 @@ class TestUnusedFunctions : public TestFixture { TEST_CASE(entrypointsUnix); TEST_CASE(includes); + TEST_CASE(virtualFunc); } #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) @@ -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)