From b57120c14ebbfd238f83080eca7d4a6358e1fa80 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Wed, 24 Jun 2026 23:23:16 +0200 Subject: [PATCH 1/3] Fix #13944 FN constParameterPointer in method in derived class --- lib/checkother.cpp | 18 +++++++++++++----- lib/checkother.h | 2 +- test/testother.cpp | 12 ++++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index a45dfdf672e..9826715ad50 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2030,8 +2030,11 @@ void CheckOtherImpl::checkConstPointer() nonConstPointers.emplace(var); } for (const Variable *p: pointers) { + bool foundAllBaseClasses = true; if (p->isArgument()) { - if (!p->scope() || !p->scope()->function || p->scope()->function->isImplicitlyVirtual(true) || p->scope()->function->hasVirtualSpecifier()) + if (!p->scope() || !p->scope()->function || p->scope()->function->hasVirtualSpecifier()) + continue; + if (p->scope()->function->isImplicitlyVirtual(true, &foundAllBaseClasses) && foundAllBaseClasses) continue; if (p->isMaybeUnused()) continue; @@ -2048,12 +2051,12 @@ void CheckOtherImpl::checkConstPointer() continue; if (p->typeStartToken() && p->typeStartToken()->isSimplifiedTypedef() && !(Token::simpleMatch(p->typeEndToken(), "*") && !p->typeEndToken()->isSimplifiedTypedef())) continue; - constVariableError(p, p->isArgument() ? p->scope()->function : nullptr); + constVariableError(p, p->isArgument() ? p->scope()->function : nullptr, foundAllBaseClasses); } } } -void CheckOtherImpl::constVariableError(const Variable *var, const Function *function) +void CheckOtherImpl::constVariableError(const Variable *var, const Function *function, bool foundAllBaseClasses) { if (!var) { reportError(nullptr, Severity::style, "constParameter", "Parameter 'x' can be declared with const"); @@ -2066,13 +2069,18 @@ void CheckOtherImpl::constVariableError(const Variable *var, const Function *fun return; } - const std::string vartype(var->isArgument() ? "Parameter" : "Variable"); + std::string vartype(var->isArgument() ? "Parameter" : "Variable"); const std::string& varname(var->name()); const std::string ptrRefArray = var->isArray() ? "const array" : (var->isPointer() ? "pointer to const" : "reference to const"); ErrorPath errorPath; std::string id = "const" + vartype; - std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared as " + ptrRefArray; + std::string message = "$symbol:" + varname + "\n"; + if (!foundAllBaseClasses) { + message += "Either there is a missing override/final keyword, or the "; + vartype[0] = std::tolower(vartype[0]); + } + message += vartype + " '$symbol' can be declared as " + ptrRefArray; errorPath.emplace_back(var->nameToken(), message); if (var->isArgument() && function && function->functionPointerUsage) { errorPath.emplace_front(function->functionPointerUsage, "You might need to cast the function pointer here"); diff --git a/lib/checkother.h b/lib/checkother.h index 7f21ffc00f8..a7ade4a586b 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -275,7 +275,7 @@ class CPPCHECKLIB CheckOtherImpl : public CheckImpl { void suspiciousFloatingPointCastError(const Token *tok); void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt); void passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor = false); - void constVariableError(const Variable *var, const Function *function); + void constVariableError(const Variable *var, const Function *function, bool foundAllBaseClasses = true); void constStatementError(const Token *tok, const std::string &type, bool inconclusive); void signedCharArrayIndexError(const Token *tok); void unknownSignCharArrayIndexError(const Token *tok); diff --git a/test/testother.cpp b/test/testother.cpp index 4215a3b3449..ba8814c42e2 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4872,6 +4872,18 @@ class TestOther : public TestFixture { " return *p->cbegin();\n" "}\n"); ASSERT_EQUALS("[test.cpp:1:25]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("struct S : U {\n" + "void f(int* p) const {\n" + " if (m == p) {}\n" + "}\n" + "void g(int* p) final {\n" + " if (m == p) {}\n" + "}\n" + "int* m;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:2:13]: (style) Either there is a missing override/final keyword, or the parameter 'p' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); } void constArray() { From abcbdb374a866c010d055e27d437be4b44f22642 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 25 Jun 2026 09:10:14 +0200 Subject: [PATCH 2/3] Format [skip ci] --- test/testother.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/testother.cpp b/test/testother.cpp index d2b091ce313..1fa7bdb5fab 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4896,13 +4896,13 @@ class TestOther : public TestFixture { errout_str()); check("struct S : U {\n" // #13944 - "void f(int* p) const {\n" - " if (m == p) {}\n" - "}\n" - "void g(int* p) final {\n" - " if (m == p) {}\n" - "}\n" - "int* m;\n" + " void f(int* p) const {\n" + " if (m == p) {}\n" + " }\n" + " void g(int* p) final {\n" + " if (m == p) {}\n" + " }\n" + " int* m;\n" "};\n"); ASSERT_EQUALS("[test.cpp:2:13]: (style) Either there is a missing override/final keyword, or the parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); From b8224e6b4b335ee23d62f05cd7a29cb6772c1201 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 25 Jun 2026 22:11:13 +0200 Subject: [PATCH 3/3] Update testother.cpp --- test/testother.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testother.cpp b/test/testother.cpp index 737d3477df3..fa6899cf543 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4894,7 +4894,7 @@ class TestOther : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:6:10]: (style) Parameter 's' can be declared as reference to const [constParameterReference]\n", errout_str()); - + check("struct S { std::string a; };\n" // #13678 "struct T { S s; };\n" "bool f(S* s) {\n" @@ -4924,7 +4924,7 @@ class TestOther : public TestFixture { " }\n" " int* m;\n" "};\n"); - ASSERT_EQUALS("[test.cpp:2:13]: (style) Either there is a missing override/final keyword, or the parameter 'p' can be declared as pointer to const [constParameterPointer]\n", + ASSERT_EQUALS("[test.cpp:2:17]: (style) Either there is a missing override/final keyword, or the parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); }