diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 4f4757fb4..3a6bc79d0 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -2108,12 +2108,12 @@ void CheckClass::checkConst() if (!scope->definedType->derivedFrom.empty() && func.isImplicitlyVirtual(true)) continue; - bool memberAccessed = false; + enum MemberAccess memberAccessed = MemberAccess::NONE; // if nothing non-const was found. write error.. if (!checkConstFunc(scope, &func, memberAccessed)) continue; - const bool suggestStatic = !memberAccessed && !func.isOperator(); + const bool suggestStatic = memberAccessed != MemberAccess::MEMBER && !func.isOperator(); if ((returnsPtrOrRef || func.isConst()) && !suggestStatic) continue; @@ -2293,7 +2293,7 @@ bool CheckClass::isConstMemberFunc(const Scope *scope, const Token *tok) const std::set CheckClass::stl_containers_not_const = { "map", "unordered_map", "std :: map|unordered_map <" }; // start pattern -bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool& memberAccessed) const +bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, MemberAccess& memberAccessed) const { if (mTokenizer->hasIfdef(func->functionScope->bodyStart, func->functionScope->bodyEnd)) return false; @@ -2312,9 +2312,10 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool& 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) && func != funcTok->function()) + const bool isSelf = func == funcTok->function(); + if (!isConstMemberFunc(scope, funcTok) && !isSelf) return false; - memberAccessed = true; + memberAccessed = (isSelf && memberAccessed != MemberAccess::MEMBER) ? MemberAccess::SELF : MemberAccess::MEMBER; } if (const Function* f = funcTok->function()) { // check known function @@ -2361,7 +2362,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool& // it can be a const function.. for (const Token *tok1 = func->functionScope->bodyStart; tok1 && tok1 != func->functionScope->bodyEnd; tok1 = tok1->next()) { if (tok1->isName() && isMemberVar(scope, tok1)) { - memberAccessed = true; + memberAccessed = MemberAccess::MEMBER; const Variable* v = tok1->variable(); if (v && v->isMutable()) continue; @@ -2476,7 +2477,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool& ; } else if (hasOverloadedMemberAccess(end, var->typeScope())) { ; - } else if (!var->typeScope() || !isConstMemberFunc(var->typeScope(), end)) + } else if (!var->typeScope() || (end->function() != func && !isConstMemberFunc(var->typeScope(), end))) return false; } diff --git a/lib/checkclass.h b/lib/checkclass.h index 4a940857f..a2303774d 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -319,7 +319,8 @@ private: bool isMemberVar(const Scope *scope, const Token *tok) const; static bool isMemberFunc(const Scope *scope, const Token *tok); static bool isConstMemberFunc(const Scope *scope, const Token *tok); - bool checkConstFunc(const Scope *scope, const Function *func, bool& memberAccessed) const; + enum class MemberAccess { NONE, SELF, MEMBER }; + bool checkConstFunc(const Scope *scope, const Function *func, MemberAccess& memberAccessed) const; // constructors helper function /** @brief Information about a member variable. Used when checking for uninitialized variables */ diff --git a/test/testclass.cpp b/test/testclass.cpp index 7be1486d6..4119f8e2f 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -6539,8 +6539,8 @@ private: errout.str()); } - void const89() { // #11654 - checkConst("struct S {\n" + void const89() { + checkConst("struct S {\n" // #11654 " void f(bool b);\n" " int i;\n" "};\n" @@ -6560,6 +6560,23 @@ private: " f(i);\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + checkConst("struct S {\n" // #11744 + " S* p;\n" + " int f() {\n" + " if (p)\n" + " return 1 + p->f();\n" + " return 1;\n" + " }\n" + " int g(int i) {\n" + " if (i > 0)\n" + " return i + g(i - 1);\n" + " return 0;\n" + " }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Technically the member function 'S::f' can be const.\n" + "[test.cpp:8]: (performance, inconclusive) Technically the member function 'S::g' can be static (but you may consider moving to unnamed namespace).\n", + errout.str()); } void const90() { // #11637