From e05a5970666ca562af1f0d0be7984525715ea804 Mon Sep 17 00:00:00 2001 From: PKEuS Date: Wed, 22 Aug 2012 04:08:32 -0700 Subject: [PATCH] Fixed false negatives in checkautovariables.cpp: - Detect returning temporary instances (#4076) - Added support for returning user defined types --- lib/checkautovariables.cpp | 43 ++++++++++++++++++++++++------- test/testautovariables.cpp | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index 5471c67f2..68a1230d1 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -238,22 +238,45 @@ bool CheckAutoVariables::returnTemporary(const Token *tok) const std::list::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); } diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index bb6e7bdb8..0b143c5a4 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -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 foo() {\n" + " return something;\n" + "}\n" + "std::map& 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() {