Skip to content

Commit bbaa7be

Browse files
Fix #12118 FP passedByValue for callbacks (#5591)
1 parent 7618e10 commit bbaa7be

5 files changed

Lines changed: 30 additions & 12 deletions

File tree

cli/cppcheckexecutor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ bool CppCheckExecutor::tryLoadLibrary(Library& destination, const std::string& b
580580
/**
581581
* Execute a shell command and read the output from it. Returns true if command terminated successfully.
582582
*/
583-
// cppcheck-suppress passedByValue - used as callback so we need to preserve the signature
583+
// cppcheck-suppress passedByValueCallback - used as callback so we need to preserve the signature
584584
// NOLINTNEXTLINE(performance-unnecessary-value-param) - used as callback so we need to preserve the signature
585585
int CppCheckExecutor::executeCommand(std::string exe, std::vector<std::string> args, std::string redirect, std::string &output_)
586586
{

gui/checkthread.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
#endif
5757

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

lib/checkother.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,7 @@ void CheckOther::checkPassByReference()
13661366

13671367
const bool isConst = var->isConst();
13681368
if (isConst) {
1369-
passedByValueError(var->nameToken(), var->name(), inconclusive);
1369+
passedByValueError(var, inconclusive);
13701370
continue;
13711371
}
13721372

@@ -1375,18 +1375,26 @@ void CheckOther::checkPassByReference()
13751375
continue;
13761376

13771377
if (canBeConst(var, mSettings)) {
1378-
passedByValueError(var->nameToken(), var->name(), inconclusive);
1378+
passedByValueError(var, inconclusive);
13791379
}
13801380
}
13811381
}
13821382

1383-
void CheckOther::passedByValueError(const Token *tok, const std::string &parname, bool inconclusive)
1383+
void CheckOther::passedByValueError(const Variable* var, bool inconclusive)
13841384
{
1385-
reportError(tok, Severity::performance, "passedByValue",
1386-
"$symbol:" + parname + "\n"
1387-
"Function parameter '$symbol' should be passed by const reference.\n"
1388-
"Parameter '$symbol' is passed by value. It could be passed "
1389-
"as a const reference which is usually faster and recommended in C++.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
1385+
std::string id = "passedByValue";
1386+
std::string msg = "$symbol:" + (var ? var->name() : "") + "\n"
1387+
"Function parameter '$symbol' should be passed by const reference.";
1388+
ErrorPath errorPath;
1389+
if (var && var->scope() && var->scope()->function && var->scope()->function->functionPointerUsage) {
1390+
id += "Callback";
1391+
errorPath.emplace_front(var->scope()->function->functionPointerUsage, "Function pointer used here.");
1392+
msg += " However it seems that '" + var->scope()->function->name() + "' is a callback function.";
1393+
}
1394+
if (var)
1395+
errorPath.emplace_back(var->nameToken(), msg);
1396+
msg += "\nParameter '$symbol' is passed by value. It could be passed as a const reference which is usually faster and recommended in C++.";
1397+
reportError(errorPath, Severity::performance, id.c_str(), msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
13901398
}
13911399

13921400
static bool isUnusedVariable(const Variable *var)

lib/checkother.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ class CPPCHECKLIB CheckOther : public Check {
241241
void clarifyStatementError(const Token* tok);
242242
void cstyleCastError(const Token *tok);
243243
void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt);
244-
void passedByValueError(const Token *tok, const std::string &parname, bool inconclusive);
244+
void passedByValueError(const Variable* var, bool inconclusive);
245245
void constVariableError(const Variable *var, const Function *function);
246246
void constStatementError(const Token *tok, const std::string &type, bool inconclusive);
247247
void signedCharArrayIndexError(const Token *tok);
@@ -314,7 +314,7 @@ class CPPCHECKLIB CheckOther : public Check {
314314
c.checkComparisonFunctionIsAlwaysTrueOrFalseError(nullptr, "isless","varName",false);
315315
c.checkCastIntToCharAndBackError(nullptr, "func_name");
316316
c.cstyleCastError(nullptr);
317-
c.passedByValueError(nullptr, "parametername", false);
317+
c.passedByValueError(nullptr, false);
318318
c.constVariableError(nullptr, nullptr);
319319
c.constStatementError(nullptr, "type", false);
320320
c.signedCharArrayIndexError(nullptr);

test/testother.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9916,6 +9916,16 @@ class TestOther : public TestFixture {
99169916
check("std::map<int, int> m;\n" // #10817
99179917
"void f(const decltype(m)::const_iterator i) {}");
99189918
ASSERT_EQUALS("", errout.str());
9919+
9920+
check("int (*pf) (std::vector<int>) = nullptr;\n" // #12118
9921+
"int f(std::vector<int> v) {\n"
9922+
" return v.size();\n"
9923+
"}\n"
9924+
"void g() {\n"
9925+
" pf = f;\n"
9926+
"}\n");
9927+
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",
9928+
errout.str());
99199929
}
99209930

99219931
void checkComparisonFunctionIsAlwaysTrueOrFalse() {

0 commit comments

Comments
 (0)