Fix #11654 FN functionConst if only non-const member usage is call to itself (#5092)

* Fix #11654 FN functionConst if only non-const member usage is call to itself

* Format

* Add const
This commit is contained in:
chrchr-github 2023-05-26 17:24:13 +02:00 committed by GitHub
parent c039d232d0
commit 10b55cc0cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 33 additions and 9 deletions

View File

@ -741,7 +741,7 @@ bool CheckClass::isBaseClassMutableMemberFunc(const Token *tok, const Scope *sco
return false;
}
void CheckClass::initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage)
void CheckClass::initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage) const
{
if (!func.functionScope)
return;
@ -2310,9 +2310,9 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool&
return nullptr;
};
auto checkFuncCall = [this, &memberAccessed](const Token* funcTok, const Scope* scope) {
auto checkFuncCall = [this, &memberAccessed](const Token* funcTok, const Scope* scope, const Function* func) {
if (isMemberFunc(scope, funcTok) && (funcTok->strAt(-1) != "." || Token::simpleMatch(funcTok->tokAt(-2), "this ."))) {
if (!isConstMemberFunc(scope, funcTok))
if (!isConstMemberFunc(scope, funcTok) && func != funcTok->function())
return false;
memberAccessed = true;
}
@ -2490,7 +2490,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool&
return false;
tok1 = jumpBackToken?jumpBackToken:end; // Jump back to first [ to check inside, or jump to end of expression
if (tok1 == end && Token::Match(end->previous(), ". %name% ( !!)") && !checkFuncCall(tok1, scope)) // function call on member
if (tok1 == end && Token::Match(end->previous(), ". %name% ( !!)") && !checkFuncCall(tok1, scope, func)) // function call on member
return false;
}
@ -2509,7 +2509,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool&
// function/constructor call, return init list
else if (const Token* funcTok = getFuncTok(tok1)) {
if (!checkFuncCall(funcTok, scope))
if (!checkFuncCall(funcTok, scope, func))
return false;
} else if (Token::simpleMatch(tok1, "> (") && (!tok1->link() || !Token::Match(tok1->link()->previous(), "static_cast|const_cast|dynamic_cast|reinterpret_cast"))) {
return false;

View File

@ -392,7 +392,7 @@ private:
* @param scope pointer to variable Scope
* @param usage reference to usage vector
*/
void initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage);
void initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage) const;
/**
* @brief gives a list of tokens where virtual functions are called directly or indirectly

View File

@ -827,7 +827,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
return false;
}
const Token *CheckUninitVar::checkExpr(const Token *tok, const Variable& var, const Alloc alloc, bool known, bool *bailout)
const Token* CheckUninitVar::checkExpr(const Token* tok, const Variable& var, const Alloc alloc, bool known, bool* bailout) const
{
if (!tok)
return nullptr;

View File

@ -82,7 +82,7 @@ public:
void checkStruct(const Token *tok, const Variable &structvar);
enum Alloc { NO_ALLOC, NO_CTOR_CALL, CTOR_CALL, ARRAY };
bool checkScopeForVariable(const Token *tok, const Variable& var, bool* const possibleInit, bool* const noreturn, Alloc* const alloc, const std::string &membervar, std::map<nonneg int, VariableValue> variableValue);
const Token *checkExpr(const Token *tok, const Variable& var, const Alloc alloc, bool known, bool *bailout=nullptr);
const Token* checkExpr(const Token* tok, const Variable& var, const Alloc alloc, bool known, bool* bailout = nullptr) const;
bool checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, Alloc alloc, const std::string &membervar);
bool checkLoopBody(const Token *tok, const Variable& var, const Alloc alloc, const std::string &membervar, const bool suppressErrors);
const Token* checkLoopBodyRecursive(const Token *start, const Variable& var, const Alloc alloc, const std::string &membervar, bool &bailout) const;

View File

@ -195,7 +195,7 @@ public:
* \param only_k_r_fpar Only simplify K&R function parameters
*/
void simplifyVarDecl(const bool only_k_r_fpar);
void simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar);
void simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar); // cppcheck-suppress functionConst // has side effects
/**
* Simplify variable initialization

View File

@ -198,6 +198,7 @@ private:
TEST_CASE(const85);
TEST_CASE(const86);
TEST_CASE(const87);
TEST_CASE(const89);
TEST_CASE(const_handleDefaultParameters);
TEST_CASE(const_passThisToMemberOfOtherClass);
@ -6414,6 +6415,29 @@ private:
errout.str());
}
void const89() { // #11654
checkConst("struct S {\n"
" void f(bool b);\n"
" int i;\n"
"};\n"
"void S::f(bool b) {\n"
" if (i && b)\n"
" f(false);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:2]: (style, inconclusive) Technically the member function 'S::f' can be const.\n", errout.str());
checkConst("struct S {\n"
" void f(int& r);\n"
" int i;\n"
"};\n"
"void S::f(int& r) {\n"
" r = 0;\n"
" if (i)\n"
" f(i);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void const_handleDefaultParameters() {
checkConst("struct Foo {\n"
" void foo1(int i, int j = 0) {\n"