Fix #12118 FP passedByValue for callbacks (#5591)

This commit is contained in:
chrchr-github 2023-10-31 12:06:31 +01:00 committed by GitHub
parent 7618e100b4
commit bbaa7be901
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 12 deletions

View File

@ -580,7 +580,7 @@ bool CppCheckExecutor::tryLoadLibrary(Library& destination, const std::string& b
/** /**
* Execute a shell command and read the output from it. Returns true if command terminated successfully. * Execute a shell command and read the output from it. Returns true if command terminated successfully.
*/ */
// cppcheck-suppress passedByValue - used as callback so we need to preserve the signature // cppcheck-suppress passedByValueCallback - used as callback so we need to preserve the signature
// NOLINTNEXTLINE(performance-unnecessary-value-param) - used as callback so we need to preserve the signature // NOLINTNEXTLINE(performance-unnecessary-value-param) - used as callback so we need to preserve the signature
int CppCheckExecutor::executeCommand(std::string exe, std::vector<std::string> args, std::string redirect, std::string &output_) int CppCheckExecutor::executeCommand(std::string exe, std::vector<std::string> args, std::string redirect, std::string &output_)
{ {

View File

@ -56,7 +56,7 @@
#endif #endif
// NOLINTNEXTLINE(performance-unnecessary-value-param) - used as callback so we need to preserve the signature // NOLINTNEXTLINE(performance-unnecessary-value-param) - used as callback so we need to preserve the signature
static int executeCommand(std::string exe, std::vector<std::string> args, std::string redirect, std::string &output) // cppcheck-suppress passedByValue static int executeCommand(std::string exe, std::vector<std::string> args, std::string redirect, std::string &output) // cppcheck-suppress passedByValueCallback
{ {
output.clear(); output.clear();

View File

@ -1366,7 +1366,7 @@ void CheckOther::checkPassByReference()
const bool isConst = var->isConst(); const bool isConst = var->isConst();
if (isConst) { if (isConst) {
passedByValueError(var->nameToken(), var->name(), inconclusive); passedByValueError(var, inconclusive);
continue; continue;
} }
@ -1375,18 +1375,26 @@ void CheckOther::checkPassByReference()
continue; continue;
if (canBeConst(var, mSettings)) { if (canBeConst(var, mSettings)) {
passedByValueError(var->nameToken(), var->name(), inconclusive); passedByValueError(var, inconclusive);
} }
} }
} }
void CheckOther::passedByValueError(const Token *tok, const std::string &parname, bool inconclusive) void CheckOther::passedByValueError(const Variable* var, bool inconclusive)
{ {
reportError(tok, Severity::performance, "passedByValue", std::string id = "passedByValue";
"$symbol:" + parname + "\n" std::string msg = "$symbol:" + (var ? var->name() : "") + "\n"
"Function parameter '$symbol' should be passed by const reference.\n" "Function parameter '$symbol' should be passed by const reference.";
"Parameter '$symbol' is passed by value. It could be passed " ErrorPath errorPath;
"as a const reference which is usually faster and recommended in C++.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal); if (var && var->scope() && var->scope()->function && var->scope()->function->functionPointerUsage) {
id += "Callback";
errorPath.emplace_front(var->scope()->function->functionPointerUsage, "Function pointer used here.");
msg += " However it seems that '" + var->scope()->function->name() + "' is a callback function.";
}
if (var)
errorPath.emplace_back(var->nameToken(), msg);
msg += "\nParameter '$symbol' is passed by value. It could be passed as a const reference which is usually faster and recommended in C++.";
reportError(errorPath, Severity::performance, id.c_str(), msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
} }
static bool isUnusedVariable(const Variable *var) static bool isUnusedVariable(const Variable *var)

View File

@ -241,7 +241,7 @@ private:
void clarifyStatementError(const Token* tok); void clarifyStatementError(const Token* tok);
void cstyleCastError(const Token *tok); void cstyleCastError(const Token *tok);
void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt); void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt);
void passedByValueError(const Token *tok, const std::string &parname, bool inconclusive); void passedByValueError(const Variable* var, bool inconclusive);
void constVariableError(const Variable *var, const Function *function); void constVariableError(const Variable *var, const Function *function);
void constStatementError(const Token *tok, const std::string &type, bool inconclusive); void constStatementError(const Token *tok, const std::string &type, bool inconclusive);
void signedCharArrayIndexError(const Token *tok); void signedCharArrayIndexError(const Token *tok);
@ -314,7 +314,7 @@ private:
c.checkComparisonFunctionIsAlwaysTrueOrFalseError(nullptr, "isless","varName",false); c.checkComparisonFunctionIsAlwaysTrueOrFalseError(nullptr, "isless","varName",false);
c.checkCastIntToCharAndBackError(nullptr, "func_name"); c.checkCastIntToCharAndBackError(nullptr, "func_name");
c.cstyleCastError(nullptr); c.cstyleCastError(nullptr);
c.passedByValueError(nullptr, "parametername", false); c.passedByValueError(nullptr, false);
c.constVariableError(nullptr, nullptr); c.constVariableError(nullptr, nullptr);
c.constStatementError(nullptr, "type", false); c.constStatementError(nullptr, "type", false);
c.signedCharArrayIndexError(nullptr); c.signedCharArrayIndexError(nullptr);

View File

@ -9916,6 +9916,16 @@ private:
check("std::map<int, int> m;\n" // #10817 check("std::map<int, int> m;\n" // #10817
"void f(const decltype(m)::const_iterator i) {}"); "void f(const decltype(m)::const_iterator i) {}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("int (*pf) (std::vector<int>) = nullptr;\n" // #12118
"int f(std::vector<int> v) {\n"
" return v.size();\n"
"}\n"
"void g() {\n"
" pf = f;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:2]: (performance) Function parameter 'v' should be passed by const reference. However it seems that 'f' is a callback function.\n",
errout.str());
} }
void checkComparisonFunctionIsAlwaysTrueOrFalse() { void checkComparisonFunctionIsAlwaysTrueOrFalse() {