Fixed false negatives in checkautovariables.cpp:
- Detect returning temporary instances (#4076) - Added support for returning user defined types
This commit is contained in:
parent
00f6c635b8
commit
e05a597066
|
@ -238,22 +238,45 @@ bool CheckAutoVariables::returnTemporary(const Token *tok) const
|
||||||
|
|
||||||
std::list<Scope>::const_iterator scope;
|
std::list<Scope>::const_iterator scope;
|
||||||
|
|
||||||
|
bool func = false; // Might it be a function call?
|
||||||
bool retref = false; // is there such a function that returns a reference?
|
bool retref = false; // is there such a function that returns a reference?
|
||||||
bool retvalue = false; // is there such a function that returns a value?
|
bool retvalue = false; // is there such a function that returns a value?
|
||||||
|
|
||||||
for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
|
for (scope = symbolDatabase->scopeList.begin(); !retref && scope != symbolDatabase->scopeList.end(); ++scope) {
|
||||||
if (scope->type == Scope::eFunction) {
|
if (scope->type == Scope::eFunction && scope->function->type != Function::eConstructor && scope->function->type != Function::eCopyConstructor) {
|
||||||
if (scope->classDef->str() == funcname) {
|
if (scope->className == funcname) {
|
||||||
const Token *tok2 = scope->classDef;
|
retref = scope->classDef->strAt(-1) == "&";
|
||||||
while (tok2 && Token::Match(tok2->tokAt(-2), "%type% ::"))
|
if (!retref) {
|
||||||
tok2 = tok2->tokAt(-2);
|
const Token* start = scope->classDef;
|
||||||
if (tok2 && Token::simpleMatch(tok2->tokAt(-3), "std :: string"))
|
while (start->previous() && !Token::Match(start->previous(), ";|}|{|public:|private:|protected:")) {
|
||||||
retvalue = true;
|
if ((start->str() == ")" || start->str() == ">") && start->link())
|
||||||
else if (tok2 && Token::simpleMatch(tok2->tokAt(-4), "std :: string &"))
|
start = start->link();
|
||||||
retref = true;
|
start = start->previous();
|
||||||
|
}
|
||||||
|
if (start->str() == "const")
|
||||||
|
start = start->next();
|
||||||
|
if (start->str() == "::")
|
||||||
|
start = start->next();
|
||||||
|
|
||||||
|
if (Token::simpleMatch(start, "std ::")) {
|
||||||
|
if (start->strAt(3) != "<" || !Token::simpleMatch(start->linkAt(3), "> ::"))
|
||||||
|
retvalue = true;
|
||||||
|
else
|
||||||
|
retref = true; // Assume that a reference is returned
|
||||||
|
} else {
|
||||||
|
if (symbolDatabase->isClassOrStruct(start->str()))
|
||||||
|
retvalue = true;
|
||||||
|
else
|
||||||
|
retref = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!func && symbolDatabase->isClassOrStruct(funcname))
|
||||||
|
return true;
|
||||||
|
|
||||||
return bool(!retref && retvalue);
|
return bool(!retref && retvalue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -445,6 +445,34 @@ private:
|
||||||
" return hello();\n"
|
" return hello();\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:8]: (error) Reference to temporary returned.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:8]: (error) Reference to temporary returned.\n", errout.str());
|
||||||
|
|
||||||
|
check("std::string hello() {\n"
|
||||||
|
" return std::string();\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"std::string &f() {\n"
|
||||||
|
" return hello();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:6]: (error) Reference to temporary returned.\n", errout.str());
|
||||||
|
|
||||||
|
check("class Foo;\n"
|
||||||
|
"Foo hello() {\n"
|
||||||
|
" return Foo();\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"Foo& f() {\n"
|
||||||
|
" return hello();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:7]: (error) Reference to temporary returned.\n", errout.str());
|
||||||
|
|
||||||
|
check("Foo hello() {\n"
|
||||||
|
" return Foo();\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"Foo& f() {\n" // Unknown type - might be a reference
|
||||||
|
" return hello();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void returnReference2() {
|
void returnReference2() {
|
||||||
|
@ -504,6 +532,31 @@ private:
|
||||||
" return hello();\n"
|
" return hello();\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:11]: (error) Reference to temporary returned.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:11]: (error) Reference to temporary returned.\n", errout.str());
|
||||||
|
|
||||||
|
check("class Bar;\n"
|
||||||
|
"Bar foo() {\n"
|
||||||
|
" return something;\n"
|
||||||
|
"}\n"
|
||||||
|
"Bar& bar() {\n"
|
||||||
|
" return foo();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:6]: (error) Reference to temporary returned.\n", errout.str());
|
||||||
|
|
||||||
|
check("std::map<int, string> foo() {\n"
|
||||||
|
" return something;\n"
|
||||||
|
"}\n"
|
||||||
|
"std::map<int, string>& bar() {\n"
|
||||||
|
" return foo();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Reference to temporary returned.\n", errout.str());
|
||||||
|
|
||||||
|
check("Bar foo() {\n"
|
||||||
|
" return something;\n"
|
||||||
|
"}\n"
|
||||||
|
"Bar& bar() {\n" // Unknown type - might be a typedef to a reference type
|
||||||
|
" return foo();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void returnReference3() {
|
void returnReference3() {
|
||||||
|
|
Loading…
Reference in New Issue