diff --git a/lib/checkother.cpp b/lib/checkother.cpp index cf5ecb65b91..4e7231c4758 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1996,8 +1996,9 @@ void CheckOther::checkConstPointer() nonConstPointers.emplace(var); } for (const Variable *p: pointers) { + bool inconclusive = false; 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->isImplicitlyVirtual(false, nullptr, &inconclusive) || p->scope()->function->hasVirtualSpecifier()) continue; if (p->isMaybeUnused()) continue; @@ -2014,12 +2015,12 @@ void CheckOther::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, &inconclusive); } } } -void CheckOther::constVariableError(const Variable *var, const Function *function) +void CheckOther::constVariableError(const Variable *var, const Function *function, const bool *inconclusive) { if (!var) { reportError(nullptr, Severity::style, "constParameter", "Parameter 'x' can be declared with const"); @@ -2038,7 +2039,9 @@ void CheckOther::constVariableError(const Variable *var, const Function *functio ErrorPath errorPath; std::string id = "const" + vartype; - std::string message = "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared as " + ptrRefArray; + std::string message = !(inconclusive && *inconclusive) ? + "$symbol:" + varname + "\n" + vartype + " '$symbol' can be declared as " + ptrRefArray : + "$symbol:" + varname + "\nEither there is missing override/final keyword, or the " + vartype + " '$symbol' can be " + 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 28ee25cfa76..bab08518857 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -215,7 +215,7 @@ class CPPCHECKLIB CheckOther : public Check { 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, const bool *inconclusive = nullptr); void constStatementError(const Token *tok, const std::string &type, bool inconclusive); void signedCharArrayIndexError(const Token *tok); void unknownSignCharArrayIndexError(const Token *tok); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index f5ffa4e1604..28406942479 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4810,8 +4810,10 @@ void Function::addArguments(const Scope *scope) } } -bool Function::isImplicitlyVirtual(bool defaultVal, bool* pFoundAllBaseClasses) const +bool Function::isImplicitlyVirtual(bool defaultVal, bool* pFoundAllBaseClasses, bool* inconclusive) const { + if (inconclusive) + *inconclusive = false; // assume not inconclusive. if (hasVirtualSpecifier() || hasOverrideSpecifier() || hasFinalSpecifier()) return true; bool foundAllBaseClasses = true; @@ -4821,7 +4823,10 @@ bool Function::isImplicitlyVirtual(bool defaultVal, bool* pFoundAllBaseClasses) *pFoundAllBaseClasses = foundAllBaseClasses; if (foundAllBaseClasses) //If we've seen all the base classes and none of the above were true then it must not be virtual return false; - return defaultVal; //If we can't see all the bases classes then we can't say conclusively + //If we can't see all the bases classes then we can't say conclusively, set inconclusive (if possible) and return default value + if (inconclusive) + *inconclusive = true; + return defaultVal; } std::vector Function::getOverloadedFunctions() const diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 954b31cc05b..36acb167315 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -783,7 +783,7 @@ class CPPCHECKLIB Function { void addArguments(const Scope *scope); /** @brief check if this function is virtual in the base classes */ - bool isImplicitlyVirtual(bool defaultVal = false, bool* pFoundAllBaseClasses = nullptr) const; + bool isImplicitlyVirtual(bool defaultVal = false, bool* pFoundAllBaseClasses = nullptr, bool* inconclusive = nullptr) const; std::vector getOverloadedFunctions() const; diff --git a/test/testother.cpp b/test/testother.cpp index 06512a930c9..def57dda329 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -4676,6 +4676,31 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:1:18]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n" "[test.cpp:4:18]: (style) Parameter 'p' can be declared as pointer to const [constParameterPointer]\n", errout_str()); + + check("class A {\n" + "public:\n" + " void func01(QPoint* pt1) {\n" + " if (nullptr == pt1) {}\n" + " }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3:25]: (style) Parameter 'pt1' can be declared as pointer to const [constParameterPointer]\n", + errout_str()); + + check("class A : public QObject {\n" + "public:\n" + " void func01(QPoint* pt2) {\n" + " if (nullptr == pt2) {}\n" + " }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3:25]: (style) Either there is missing override/final keyword, or the Parameter 'pt2' can be pointer to const [constParameterPointer]\n", + errout_str()); + check("class A : public QObject {\n" + "public:\n" + " void func01(QPoint* pt3) override {\n" + " if (nullptr == pt3) {}\n" + " }\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); } void constArray() {