Fixed false negatives in checkautovariables.cpp:

- Detect returning temporary instances (#4076)
- Added support for returning user defined types
This commit is contained in:
PKEuS 2012-08-22 04:08:32 -07:00
parent 00f6c635b8
commit e05a597066
2 changed files with 86 additions and 10 deletions

View File

@ -238,22 +238,45 @@ bool CheckAutoVariables::returnTemporary(const Token *tok) const
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 retvalue = false; // is there such a function that returns a value?
for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
if (scope->type == Scope::eFunction) {
if (scope->classDef->str() == funcname) {
const Token *tok2 = scope->classDef;
while (tok2 && Token::Match(tok2->tokAt(-2), "%type% ::"))
tok2 = tok2->tokAt(-2);
if (tok2 && Token::simpleMatch(tok2->tokAt(-3), "std :: string"))
retvalue = true;
else if (tok2 && Token::simpleMatch(tok2->tokAt(-4), "std :: string &"))
retref = true;
for (scope = symbolDatabase->scopeList.begin(); !retref && scope != symbolDatabase->scopeList.end(); ++scope) {
if (scope->type == Scope::eFunction && scope->function->type != Function::eConstructor && scope->function->type != Function::eCopyConstructor) {
if (scope->className == funcname) {
retref = scope->classDef->strAt(-1) == "&";
if (!retref) {
const Token* start = scope->classDef;
while (start->previous() && !Token::Match(start->previous(), ";|}|{|public:|private:|protected:")) {
if ((start->str() == ")" || start->str() == ">") && start->link())
start = start->link();
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);
}

View File

@ -445,6 +445,34 @@ private:
" return hello();\n"
"}\n");
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() {
@ -504,6 +532,31 @@ private:
" return hello();\n"
"}\n");
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() {