Fixed #5190 (FP Use const reference to avoid data copying)

This commit is contained in:
Daniel Marjamäki 2013-12-14 08:46:18 +01:00
parent 98b6fa2eaf
commit fdcb6634df
2 changed files with 31 additions and 6 deletions

View File

@ -3256,6 +3256,21 @@ void CheckOther::pointerPositiveError(const Token *tok, bool inconclusive)
"A pointer can not be negative so it is either pointless or an error to check if it is not.", inconclusive); "A pointer can not be negative so it is either pointless or an error to check if it is not.", inconclusive);
} }
/* check if a constructor in given class scope takes a reference */
static bool constructorTakesReference(const Scope * const classScope)
{
for (std::list<Function>::const_iterator func = classScope->functionList.begin(); func != classScope->functionList.end(); ++func) {
if (func->isConstructor()) {
const Function &constructor = *func;
for (std::size_t argnr = 0U; argnr < constructor.argCount(); argnr++) {
if (constructor.getArgumentVar(argnr)->isReference())
return true;
}
}
}
return false;
}
/* /*
This check rule works for checking the "const A a = getA()" usage when getA() returns "const A &" or "A &". This check rule works for checking the "const A a = getA()" usage when getA() returns "const A &" or "A &".
In most scenarios, "const A & a = getA()" will be more efficient. In most scenarios, "const A & a = getA()" will be more efficient.
@ -3274,12 +3289,13 @@ void CheckOther::checkRedundantCopy()
continue; continue;
const Token* startTok = var->nameToken(); const Token* startTok = var->nameToken();
const Token* endToken;
if (startTok->strAt(1) == "=") // %type% %var% = ... ; if (startTok->strAt(1) == "=") // %type% %var% = ... ;
endToken = Token::findsimplematch(startTok->tokAt(2), ";"); ;
else if (startTok->strAt(1) == "(") // %type% %var%(...) else if (startTok->strAt(1) == "(" && var->isClass() && var->typeScope()) {
endToken = startTok->linkAt(1); // Object is instantiated. Warn if constructor takes arguments by value.
else if (constructorTakesReference(var->typeScope()))
continue;
} else
continue; continue;
const Token* tok = startTok->tokAt(2); const Token* tok = startTok->tokAt(2);
@ -3287,7 +3303,7 @@ void CheckOther::checkRedundantCopy()
tok = tok->tokAt(2); tok = tok->tokAt(2);
if (!Token::Match(tok, "%var% (")) if (!Token::Match(tok, "%var% ("))
continue; continue;
if (tok->linkAt(1)->next() != endToken) // bailout for usage like "const A a = getA()+3" if (!Token::Match(tok->linkAt(1), ") )| ;")) // bailout for usage like "const A a = getA()+3"
continue; continue;
const Function* func = tok->function(); const Function* func = tok->function();

View File

@ -6122,6 +6122,15 @@ private:
" return 0;\n" " return 0;\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
// #5190 - FP when creating object with constructor that takes a reference
check_redundant_copy("class A {};\n"
"class B { B(const A &a); };\n"
"const A &getA();\n"
"void f() {\n"
" const B b(getA());\n"
"}");
ASSERT_EQUALS("", errout.str());
} }
void checkNegativeShift() { void checkNegativeShift() {