diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index cb600357f..3aff88e11 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1280,6 +1280,29 @@ static unsigned int countParameters(const Token *tok) return numpar; } +static unsigned int countMinArgs(const Token* argList) +{ + if (!argList) + return 0; + + argList = argList->next(); + if (argList->str() == ")") + return 0; + + unsigned int count = 1; + for (; argList; argList = argList->next()) { + if (argList->link() && Token::Match(argList, "(|[|{|<")) + argList = argList->link(); + else if (argList->str() == ",") + count++; + else if (argList->str() == "=") + return count-1; + else if (argList->str() == ")") + break; + } + return count; +} + bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok) { unsigned int args = countParameters(tok); @@ -1287,7 +1310,7 @@ bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok) for (std::list::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) { /** @todo we need to look at the argument types when there are overloaded functions * with the same number of arguments */ - if (func->tokenDef->str() == tok->str() && func->argCount() == args) { + if (func->tokenDef->str() == tok->str() && (func->argCount() == args || (func->argCount() > args && countMinArgs(func->argDef) <= args))) { return true; } } @@ -1321,7 +1344,7 @@ bool CheckClass::isConstMemberFunc(const Scope *scope, const Token *tok) for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) { /** @todo we need to look at the argument types when there are overloaded functions * with the same number of arguments */ - if (func->tokenDef->str() == tok->str() && func->argCount() == args) { + if (func->tokenDef->str() == tok->str() && (func->argCount() == args || (func->argCount() > args && countMinArgs(func->argDef) <= args))) { matches++; if (func->isConst) consts++; diff --git a/test/testclass.cpp b/test/testclass.cpp index 2308b1f3e..f14323189 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -134,6 +134,7 @@ private: TEST_CASE(const56); // ticket #3149 TEST_CASE(const57); // ticket #2669 TEST_CASE(const58); // ticket #2698 + TEST_CASE(const_handleDefaultParameters); TEST_CASE(assigningPointerToPointerIsNotAConstOperation); TEST_CASE(assigningArrayElementIsNotAConstOperation); TEST_CASE(constoperator1); // operator< can often be const @@ -4318,6 +4319,40 @@ private: ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Technically the member function 'MyObject::foo' can be const.\n", errout.str()); } + void const_handleDefaultParameters() { + checkConst("struct Foo {\n" + " void foo1(int i, int j = 0) {\n" + " return func(this);\n" + " }\n" + " int bar1() {\n" + " return foo1(1);\n" + " }\n" + " int bar2() {\n" + " return foo1(1, 2);\n" + " }\n" + " int bar3() {\n" + " return foo1(1, 2, 3);\n" + " }\n" + " int bar4() {\n" + " return foo1();\n" + " }\n" + " void foo2(int i = 0) {\n" + " return func(this);\n" + " }\n" + " int bar5() {\n" + " return foo2();\n" + " }\n" + " void foo3() {\n" + " return func(this);\n" + " }\n" + " int bar6() {\n" + " return foo3();\n" + " }\n" + "};"); + ASSERT_EQUALS("[test.cpp:11]: (style, inconclusive) Technically the member function 'Foo::bar3' can be const.\n" + "[test.cpp:14]: (style, inconclusive) Technically the member function 'Foo::bar4' can be const.\n", errout.str()); + } + void assigningPointerToPointerIsNotAConstOperation() { checkConst("struct s\n" "{\n"