Skip to content

Commit

Permalink
Fix #12118 FP passedByValue for callbacks (danmar#5591)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrchr-github authored Oct 31, 2023
1 parent 7618e10 commit bbaa7be
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 12 deletions.
2 changes: 1 addition & 1 deletion cli/cppcheckexecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
// 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
int CppCheckExecutor::executeCommand(std::string exe, std::vector<std::string> args, std::string redirect, std::string &output_)
{
Expand Down
2 changes: 1 addition & 1 deletion gui/checkthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
#endif

// 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();

Expand Down
24 changes: 16 additions & 8 deletions lib/checkother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1366,7 +1366,7 @@ void CheckOther::checkPassByReference()

const bool isConst = var->isConst();
if (isConst) {
passedByValueError(var->nameToken(), var->name(), inconclusive);
passedByValueError(var, inconclusive);
continue;
}

Expand All @@ -1375,18 +1375,26 @@ void CheckOther::checkPassByReference()
continue;

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",
"$symbol:" + parname + "\n"
"Function parameter '$symbol' should be passed by const reference.\n"
"Parameter '$symbol' is passed by value. It could be passed "
"as a const reference which is usually faster and recommended in C++.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
std::string id = "passedByValue";
std::string msg = "$symbol:" + (var ? var->name() : "") + "\n"
"Function parameter '$symbol' should be passed by const reference.";
ErrorPath errorPath;
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)
Expand Down
4 changes: 2 additions & 2 deletions lib/checkother.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ class CPPCHECKLIB CheckOther : public Check {
void clarifyStatementError(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 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 constStatementError(const Token *tok, const std::string &type, bool inconclusive);
void signedCharArrayIndexError(const Token *tok);
Expand Down Expand Up @@ -314,7 +314,7 @@ class CPPCHECKLIB CheckOther : public Check {
c.checkComparisonFunctionIsAlwaysTrueOrFalseError(nullptr, "isless","varName",false);
c.checkCastIntToCharAndBackError(nullptr, "func_name");
c.cstyleCastError(nullptr);
c.passedByValueError(nullptr, "parametername", false);
c.passedByValueError(nullptr, false);
c.constVariableError(nullptr, nullptr);
c.constStatementError(nullptr, "type", false);
c.signedCharArrayIndexError(nullptr);
Expand Down
10 changes: 10 additions & 0 deletions test/testother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9916,6 +9916,16 @@ class TestOther : public TestFixture {
check("std::map<int, int> m;\n" // #10817
"void f(const decltype(m)::const_iterator i) {}");
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() {
Expand Down

0 comments on commit bbaa7be

Please sign in to comment.