diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 439afe2fb..02ba55e2b 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1345,7 +1345,7 @@ void CheckClass::operatorEqRetRefThis() for (std::list::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) { if (func->type == Function::eOperatorEqual && func->hasBody()) { // make sure return signature is correct - if (Token::Match(func->retDef, "%type% &") && func->retDef->str() == scope->className) { + if (func->retType == func->nestedIn->definedType && func->tokenDef->strAt(-1) == "&") { checkReturnPtrThis(scope, &(*func), func->functionScope->bodyStart, func->functionScope->bodyEnd); } } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 25f7c3bf5..a0a6eaa31 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1991,7 +1991,7 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se } // remove class name - else if (arg_path_length > 2) { + else if (arg_path_length > 2 && first->strAt(1) != second->strAt(1)) { std::string short_path = path; unsigned int short_path_length = arg_path_length; @@ -3297,7 +3297,6 @@ Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope * // skip over qualification if present nameTok = skipScopeIdentifiers(nameTok); if (nameTok && ((type == Scope::eEnum && Token::Match(nameTok, ":|{")) || nameTok->str() != "{")) // anonymous and unnamed structs/unions don't have a name - className = nameTok->str(); } diff --git a/test/testclass.cpp b/test/testclass.cpp index 816e93a9e..7809531bc 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -1237,6 +1237,90 @@ private: "};\n" "A::B & A::B::operator=(const A::B &b) { return b; }"); ASSERT_EQUALS("[test.cpp:10]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str()); + + checkOpertorEqRetRefThis( + "class A {\n" + " class B;\n" + "};\n" + "class A::B\n" + "{\n" + " B & operator=(const B & b) { return b; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str()); + + checkOpertorEqRetRefThis( + "class A {\n" + " class B;\n" + "};\n" + "class A::B\n" + "{\n" + " B & operator=(const B &);\n" + "};\n" + "A::B & A::B::operator=(const A::B & b) { return b; }\n"); + ASSERT_EQUALS("[test.cpp:8]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str()); + + checkOpertorEqRetRefThis( + "class A {\n" + " class B;\n" + "};\n" + "class A::B\n" + "{\n" + " A::B & operator=(const A::B & b) { return b; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str()); + + checkOpertorEqRetRefThis( + "class A {\n" + " class B;\n" + "};\n" + "class A::B\n" + "{\n" + " A::B & operator=(const A::B &);\n" + "};\n" + "A::B & A::B::operator=(const A::B & b) { return b; }\n"); + ASSERT_EQUALS("[test.cpp:8]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str()); + + checkOpertorEqRetRefThis( + "namespace A {\n" + " class B;\n" + "}\n" + "class A::B\n" + "{\n" + " B & operator=(const B & b) { return b; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str()); + + checkOpertorEqRetRefThis( + "namespace A {\n" + " class B;\n" + "}\n" + "class A::B\n" + "{\n" + " B & operator=(const B &);\n" + "};\n" + "A::B & A::B::operator=(const A::B & b) { return b; }\n"); + ASSERT_EQUALS("[test.cpp:8]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str()); + + checkOpertorEqRetRefThis( + "namespace A {\n" + " class B;\n" + "}\n" + "class A::B\n" + "{\n" + " A::B & operator=(const A::B & b) { return b; }\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str()); + + checkOpertorEqRetRefThis( + "namespace A {\n" + " class B;\n" + "}\n" + "class A::B\n" + "{\n" + " A::B & operator=(const A::B &);\n" + "};\n" + "A::B & A::B::operator=(const A::B & b) { return b; }\n"); + ASSERT_EQUALS("[test.cpp:8]: (style) 'operator=' should return reference to 'this' instance.\n", errout.str()); } void operatorEqRetRefThis2() { @@ -1244,7 +1328,7 @@ private: checkOpertorEqRetRefThis( "class szp\n" "{\n" - " szp &operator =(int *other) {};\n" + " szp &operator =(int *other) {}\n" "};"); ASSERT_EQUALS("[test.cpp:3]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); @@ -1255,6 +1339,90 @@ private: "};\n" "szp &szp::operator =(int *other) {}"); ASSERT_EQUALS("[test.cpp:5]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); + + checkOpertorEqRetRefThis( + "namespace NS {\n" + " class szp;\n" + "}\n" + "class NS::szp\n" + "{\n" + " szp &operator =(int *other) {}\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); + + checkOpertorEqRetRefThis( + "namespace NS {\n" + " class szp;\n" + "}\n" + "class NS::szp\n" + "{\n" + " szp &operator =(int *other);\n" + "};\n" + "NS::szp &NS::szp::operator =(int *other) {}"); + ASSERT_EQUALS("[test.cpp:8]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); + + checkOpertorEqRetRefThis( + "namespace NS {\n" + " class szp;\n" + "}\n" + "class NS::szp\n" + "{\n" + " NS::szp &operator =(int *other) {}\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); + + checkOpertorEqRetRefThis( + "namespace NS {\n" + " class szp;\n" + "}\n" + "class NS::szp\n" + "{\n" + " NS::szp &operator =(int *other);\n" + "};\n" + "NS::szp &NS::szp::operator =(int *other) {}"); + ASSERT_EQUALS("[test.cpp:8]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); + + checkOpertorEqRetRefThis( + "class A {\n" + " class szp;\n" + "};\n" + "class A::szp\n" + "{\n" + " szp &operator =(int *other) {}\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); + + checkOpertorEqRetRefThis( + "class A {\n" + " class szp;\n" + "};\n" + "class A::szp\n" + "{\n" + " szp &operator =(int *other);\n" + "};\n" + "A::szp &A::szp::operator =(int *other) {}"); + ASSERT_EQUALS("[test.cpp:8]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); + + checkOpertorEqRetRefThis( + "class A {\n" + " class szp;\n" + "};\n" + "class A::szp\n" + "{\n" + " A::szp &operator =(int *other) {}\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:6]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); + + checkOpertorEqRetRefThis( + "class A {\n" + " class szp;\n" + "};\n" + "class A::szp\n" + "{\n" + " A::szp &operator =(int *other);\n" + "};\n" + "A::szp &A::szp::operator =(int *other) {}"); + ASSERT_EQUALS("[test.cpp:8]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str()); } void operatorEqRetRefThis3() {