diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 38c524721..cb600357f 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1415,7 +1415,7 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func) // function call.. else if (Token::Match(tok1, "%var% (") && !tok1->isStandardType() && !Token::Match(tok1, "return|if|string|switch|while|catch|for")) { - if (isMemberFunc(scope, tok1) && !isConstMemberFunc(scope, tok1)) { + if (isMemberFunc(scope, tok1) && !isConstMemberFunc(scope, tok1) && tok1->strAt(-1) != ".") { return(false); } // Member variable given as parameter @@ -1428,7 +1428,9 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func) } else if (Token::Match(tok1, "> (") && (!tok1->link() || !Token::Match(tok1->link()->previous(), "static_cast|const_cast|dynamic_cast|reinterpret_cast"))) { return(false); } else if (Token::Match(tok1, "%var% . %var% (")) { - if (tok1->varId() && (Token::Match(tok1->tokAt(2), "size|empty|cend|crend|cbegin|crbegin|max_size|length|count|capacity|get_allocator|c_str|str ( )") || Token::Match(tok1->tokAt(2), "rfind|copy"))) { + if (!isMemberVar(scope, tok1)) + tok1 = tok1->tokAt(2); + else if (tok1->varId() && (Token::Match(tok1->tokAt(2), "size|empty|cend|crend|cbegin|crbegin|max_size|length|count|capacity|get_allocator|c_str|str ( )") || Token::Match(tok1->tokAt(2), "rfind|copy"))) { const Variable *var = symbolDatabase->getVariableFromVarId(tok1->varId()); // assume all std::*::size() and std::*::empty() are const @@ -1436,8 +1438,6 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func) tok1 = tok1->next(); else // TODO: Check if the function is const (#2477) return(false); - } else if (!isMemberVar(scope, tok1)) { - tok1 = tok1->tokAt(2); } else return(false); } diff --git a/test/testclass.cpp b/test/testclass.cpp index 7eb58f492..2308b1f3e 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -133,6 +133,7 @@ private: TEST_CASE(const55); TEST_CASE(const56); // ticket #3149 TEST_CASE(const57); // ticket #2669 + TEST_CASE(const58); // ticket #2698 TEST_CASE(assigningPointerToPointerIsNotAConstOperation); TEST_CASE(assigningArrayElementIsNotAConstOperation); TEST_CASE(constoperator1); // operator< can often be const @@ -4285,6 +4286,38 @@ private: } + void const58() { + checkConst("struct MyObject {\n" + " void foo(Foo f) {\n" + " f.clear();\n" + " }\n" + "};"); + ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Technically the member function 'MyObject::foo' can be const.\n", errout.str()); + + checkConst("struct MyObject {\n" + " int foo(Foo f) {\n" + " return f.length();\n" + " }\n" + "};"); + ASSERT_EQUALS("[test.cpp:2]: (style, inconclusive) Technically the member function 'MyObject::foo' can be const.\n", errout.str()); + + checkConst("struct MyObject {\n" + " Foo f;\n" + " int foo() {\n" + " return f.length();\n" + " }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + checkConst("struct MyObject {\n" + " std::string f;\n" + " int foo() {\n" + " return f.length();\n" + " }\n" + "};"); + ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Technically the member function 'MyObject::foo' can be const.\n", errout.str()); + } + void assigningPointerToPointerIsNotAConstOperation() { checkConst("struct s\n" "{\n"