diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index ffecf5748..79fe49b2d 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1802,6 +1802,21 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool& if (tok1->str() == "this" && tok1->previous()->isAssignmentOp()) return (false); + + const Token* lhs = tok1->tokAt(-1); + if (lhs->str() == "&") { + lhs = lhs->previous(); + if (lhs->type() == Token::eAssignmentOp && lhs->previous()->variable()) { + if (lhs->previous()->variable()->typeStartToken()->strAt(-1) != "const" && lhs->previous()->variable()->isPointer()) + return false; + } + } else { + const Variable* v2 = lhs->previous()->variable(); + if (lhs->type() == Token::eAssignmentOp && v2) + if (!v2->isConst() && v2->isReference() && lhs == v2->nameToken()->next()) + return false; + } + const Token* jumpBackToken = 0; const Token *lastVarTok = tok1; const Token *end = tok1; diff --git a/test/testclass.cpp b/test/testclass.cpp index 60688f4ab..b8efb9f8d 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -143,6 +143,7 @@ private: TEST_CASE(const60); // ticket #3322 TEST_CASE(const61); // ticket #5606 TEST_CASE(const62); // ticket #5701 + TEST_CASE(const63); // ticket #5983 TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); TEST_CASE(assigningPointerToPointerIsNotAConstOperation); @@ -4842,6 +4843,53 @@ private: ASSERT_EQUALS("", errout.str()); } + void const63() { + checkConst("struct A {\n" + " std::string s;\n" + " void clear() {\n" + " std::string* p = &s;\n" + " p->clear();\n" + " }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + checkConst("struct A {\n" + " std::string s;\n" + " void clear() {\n" + " std::string& r = s;\n" + " r.clear();\n" + " }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + checkConst("struct A {\n" + " std::string s;\n" + " void clear() {\n" + " std::string& r = sth; r = s;\n" + " r.clear();\n" + " }\n" + "};"); + ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Technically the member function 'A::clear' can be const.\n", errout.str()); + + checkConst("struct A {\n" + " std::string s;\n" + " void clear() {\n" + " const std::string* p = &s;\n" + " p->somefunction();\n" + " }\n" + "};"); + ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Technically the member function 'A::clear' can be const.\n", errout.str()); + + checkConst("struct A {\n" + " std::string s;\n" + " void clear() {\n" + " const std::string& r = s;\n" + " r.somefunction();\n" + " }\n" + "};"); + ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Technically the member function 'A::clear' can be const.\n", errout.str()); + } + void const_handleDefaultParameters() { checkConst("struct Foo {\n" " void foo1(int i, int j = 0) {\n"