Fixed #8833 (false negative: No 'return' statement in non-void function causes undefined behavior.) (#1463)

This commit is contained in:
IOBYTE 2018-11-05 00:55:30 -05:00 committed by Daniel Marjamäki
parent 977fdd88a9
commit 2275f05f65
3 changed files with 171 additions and 4 deletions

View File

@ -1345,7 +1345,7 @@ void CheckClass::operatorEqRetRefThis()
for (std::list<Function>::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);
}
}

View File

@ -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();
}

View File

@ -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() {