Fixed #8833 (false negative: No 'return' statement in non-void function causes undefined behavior.) (#1463)
This commit is contained in:
parent
977fdd88a9
commit
2275f05f65
|
@ -1345,7 +1345,7 @@ void CheckClass::operatorEqRetRefThis()
|
||||||
for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
|
for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
|
||||||
if (func->type == Function::eOperatorEqual && func->hasBody()) {
|
if (func->type == Function::eOperatorEqual && func->hasBody()) {
|
||||||
// make sure return signature is correct
|
// 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);
|
checkReturnPtrThis(scope, &(*func), func->functionScope->bodyStart, func->functionScope->bodyEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1991,7 +1991,7 @@ bool Function::argsMatch(const Scope *scope, const Token *first, const Token *se
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove class name
|
// 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;
|
std::string short_path = path;
|
||||||
unsigned int short_path_length = arg_path_length;
|
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
|
// skip over qualification if present
|
||||||
nameTok = skipScopeIdentifiers(nameTok);
|
nameTok = skipScopeIdentifiers(nameTok);
|
||||||
if (nameTok && ((type == Scope::eEnum && Token::Match(nameTok, ":|{")) || nameTok->str() != "{")) // anonymous and unnamed structs/unions don't have a name
|
if (nameTok && ((type == Scope::eEnum && Token::Match(nameTok, ":|{")) || nameTok->str() != "{")) // anonymous and unnamed structs/unions don't have a name
|
||||||
|
|
||||||
className = nameTok->str();
|
className = nameTok->str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1237,6 +1237,90 @@ private:
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::B & A::B::operator=(const A::B &b) { return b; }");
|
"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());
|
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() {
|
void operatorEqRetRefThis2() {
|
||||||
|
@ -1244,7 +1328,7 @@ private:
|
||||||
checkOpertorEqRetRefThis(
|
checkOpertorEqRetRefThis(
|
||||||
"class szp\n"
|
"class szp\n"
|
||||||
"{\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());
|
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"
|
"};\n"
|
||||||
"szp &szp::operator =(int *other) {}");
|
"szp &szp::operator =(int *other) {}");
|
||||||
ASSERT_EQUALS("[test.cpp:5]: (error) No 'return' statement in non-void function causes undefined behavior.\n", errout.str());
|
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() {
|
void operatorEqRetRefThis3() {
|
||||||
|
|
Loading…
Reference in New Issue