Improved check: Complain about returning reference to literals or reference to calculation result (#4317)

This commit is contained in:
PKEuS 2014-05-22 11:39:11 +02:00
parent 35f644542e
commit 6635abbe55
2 changed files with 49 additions and 0 deletions

View File

@ -344,6 +344,9 @@ void CheckAutoVariables::returnReference()
// have we reached a function that returns a reference? // have we reached a function that returns a reference?
if (tok->previous() && tok->previous()->str() == "&") { if (tok->previous() && tok->previous()->str() == "&") {
for (const Token *tok2 = scope->classStart->next(); tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) { for (const Token *tok2 = scope->classStart->next(); tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) {
if (tok2->str() != "return")
continue;
// return.. // return..
if (Token::Match(tok2, "return %var% ;")) { if (Token::Match(tok2, "return %var% ;")) {
// is the returned variable a local variable? // is the returned variable a local variable?
@ -374,6 +377,11 @@ void CheckAutoVariables::returnReference()
errorReturnTempReference(tok2); errorReturnTempReference(tok2);
} }
} }
// Return reference to a literal or the result of a calculation
else if (tok2->astOperand1() && (tok2->astOperand1()->isCalculation() || tok2->next()->isLiteral())) {
errorReturnTempReference(tok2);
}
} }
} }
} }

View File

@ -104,6 +104,8 @@ private:
TEST_CASE(returnReference5); TEST_CASE(returnReference5);
TEST_CASE(returnReference6); TEST_CASE(returnReference6);
TEST_CASE(returnReference7); TEST_CASE(returnReference7);
TEST_CASE(returnReferenceLiteral);
TEST_CASE(returnReferenceCalculation);
// global namespace // global namespace
TEST_CASE(testglobalnamespace); TEST_CASE(testglobalnamespace);
@ -847,6 +849,45 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void returnReferenceLiteral() {
check("const std::string &a() {\n"
" return \"foo\";\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Reference to temporary returned.\n", errout.str());
check("const std::string a() {\n"
" return \"foo\";\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void returnReferenceCalculation() {
check("const std::string &a(const std::string& str) {\n"
" return \"foo\" + str;\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Reference to temporary returned.\n", errout.str());
check("int& a(int b) {\n"
" return 2*(b+1);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Reference to temporary returned.\n", errout.str());
check("const std::string &a(const std::string& str) {\n"
" return str;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("const std::string &a(int bar) {\n"
" return foo(bar + 1);\n"
"}");
ASSERT_EQUALS("", errout.str());
check("const std::string a(const std::string& str) {\n"
" return \"foo\" + str;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void testglobalnamespace() { void testglobalnamespace() {
check("class SharedPtrHolder\n" check("class SharedPtrHolder\n"