diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 21657cfd9fd..9dee8df7810 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2033,8 +2033,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; @@ -2051,12 +2054,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"); @@ -2069,13 +2072,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 759a4d23e7b..caf9f4a9e57 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 60323b3395b..fa6899cf543 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4914,6 +4914,18 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:2:14]: (style) Parameter 's' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:2:46]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", 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" + "};\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()); } void constArray() {