Fixed #4104 (New check: comma separated statements in return statement from a function)
This commit is contained in:
parent
03f28e9c65
commit
d85c8e6782
|
@ -1877,6 +1877,46 @@ void CheckOther::variableScopeError(const Token *tok, const std::string &varname
|
||||||
"When you see this message it is always safe to reduce the variable scope 1 level.");
|
"When you see this message it is always safe to reduce the variable scope 1 level.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckOther::checkCommaSeparatedReturn()
|
||||||
|
{
|
||||||
|
if (!_settings->isEnabled("style"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const Token *tok = _tokenizer->tokens(); tok ; tok = tok->next()) {
|
||||||
|
if (Token::Match(tok ,"return")) {
|
||||||
|
|
||||||
|
while (tok->str() != ";") {
|
||||||
|
|
||||||
|
if (tok->str() == "(")
|
||||||
|
tok=tok->link();
|
||||||
|
|
||||||
|
if (!tok->isExpandedMacro() && tok->str() == ",")
|
||||||
|
commaSeparatedReturnError(tok);
|
||||||
|
|
||||||
|
tok=tok->next();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckOther::commaSeparatedReturnError(const Token *tok)
|
||||||
|
{
|
||||||
|
reportError(tok,
|
||||||
|
Severity::style,
|
||||||
|
"commaSeparatedReturn",
|
||||||
|
"Comma is used in return statement. The comma can easily be misread as a ';'.\n"
|
||||||
|
"Comma is used in return statement. When comma is used in a return statement it can "
|
||||||
|
"easily be misread as a semicolon. For example in the code below the value "
|
||||||
|
"of 'b' is returned if the condition is true, but it is easy to think that 'a+1' is "
|
||||||
|
"returned:\n"
|
||||||
|
" if (x)\n"
|
||||||
|
" return a + 1,\n"
|
||||||
|
" b++;\n"
|
||||||
|
"However it can be useful to use comma in macros. Cppcheck does not warn when such a "
|
||||||
|
"macro is then used in a return statement, It is less likely such code is misunderstood.");
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Check for constant function parameters
|
// Check for constant function parameters
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
checkOther.checkSuspiciousStringCompare();
|
checkOther.checkSuspiciousStringCompare();
|
||||||
checkOther.checkVarFuncNullUB();
|
checkOther.checkVarFuncNullUB();
|
||||||
checkOther.checkNanInArithmeticExpression();
|
checkOther.checkNanInArithmeticExpression();
|
||||||
|
checkOther.checkCommaSeparatedReturn();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Run checks against the simplified token list */
|
/** @brief Run checks against the simplified token list */
|
||||||
|
@ -144,6 +145,9 @@ public:
|
||||||
void checkVariableScope();
|
void checkVariableScope();
|
||||||
static bool checkInnerScope(const Token *tok, const Variable* var, bool& used);
|
static bool checkInnerScope(const Token *tok, const Variable* var, bool& used);
|
||||||
|
|
||||||
|
/** @brief %Check for comma separated statements in return */
|
||||||
|
void checkCommaSeparatedReturn();
|
||||||
|
|
||||||
/** @brief %Check for constant function parameter */
|
/** @brief %Check for constant function parameter */
|
||||||
void checkConstantFunctionParameter();
|
void checkConstantFunctionParameter();
|
||||||
|
|
||||||
|
@ -319,6 +323,7 @@ private:
|
||||||
void redundantCopyError(const Token *tok, const std::string &varname);
|
void redundantCopyError(const Token *tok, const std::string &varname);
|
||||||
void incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean);
|
void incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean);
|
||||||
void varFuncNullUBError(const Token *tok);
|
void varFuncNullUBError(const Token *tok);
|
||||||
|
void commaSeparatedReturnError(const Token *tok);
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
||||||
CheckOther c(0, settings, errorLogger);
|
CheckOther c(0, settings, errorLogger);
|
||||||
|
@ -383,6 +388,7 @@ private:
|
||||||
c.incompleteArrayFillError(0, "buffer", "memset", false);
|
c.incompleteArrayFillError(0, "buffer", "memset", false);
|
||||||
c.varFuncNullUBError(0);
|
c.varFuncNullUBError(0);
|
||||||
c.nanInArithmeticExpressionError(0);
|
c.nanInArithmeticExpressionError(0);
|
||||||
|
c.commaSeparatedReturnError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string myName() {
|
static std::string myName() {
|
||||||
|
@ -445,7 +451,8 @@ private:
|
||||||
"* Array filled incompletely using memset/memcpy/memmove.\n"
|
"* Array filled incompletely using memset/memcpy/memmove.\n"
|
||||||
"* redundant get and set function of user id (--std=posix).\n"
|
"* redundant get and set function of user id (--std=posix).\n"
|
||||||
"* Passing NULL pointer to function with variable number of arguments leads to UB on some platforms.\n"
|
"* Passing NULL pointer to function with variable number of arguments leads to UB on some platforms.\n"
|
||||||
"* NaN (not a number) value used in arithmetic expression.\n";
|
"* NaN (not a number) value used in arithmetic expression.\n"
|
||||||
|
"* comma in return statement (the comma can easily be misread as a semicolon).\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkExpressionRange(const std::list<const Function*> &constFunctions,
|
void checkExpressionRange(const std::list<const Function*> &constFunctions,
|
||||||
|
|
|
@ -172,6 +172,8 @@ private:
|
||||||
TEST_CASE(checkCastIntToCharAndBack); // ticket #160
|
TEST_CASE(checkCastIntToCharAndBack); // ticket #160
|
||||||
|
|
||||||
TEST_CASE(checkSleepTimeIntervall)
|
TEST_CASE(checkSleepTimeIntervall)
|
||||||
|
|
||||||
|
TEST_CASE(checkCommaSeparatedReturn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], const char *filename = NULL, bool experimental = false, bool inconclusive = true, bool posix = false, bool runSimpleChecks=true) {
|
void check(const char code[], const char *filename = NULL, bool experimental = false, bool inconclusive = true, bool posix = false, bool runSimpleChecks=true) {
|
||||||
|
@ -6232,6 +6234,20 @@ private:
|
||||||
"}",NULL,false,false,true);
|
"}",NULL,false,false,true);
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (error) The argument of usleep must be less than 1000000.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (error) The argument of usleep must be less than 1000000.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkCommaSeparatedReturn() {
|
||||||
|
check("int fun(int a) {\n"
|
||||||
|
" if (a < 0)\n"
|
||||||
|
" return a++ , 0;\n"
|
||||||
|
"}", NULL, false, false, false, false);
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Comma is used in return statement. The comma can easily be misread as a ';'.\n", errout.str());
|
||||||
|
|
||||||
|
check("int fun(int a) {\n"
|
||||||
|
" if (a < 0)\n"
|
||||||
|
" return a=a+5,1; \n"
|
||||||
|
"}", NULL, false, false, false, false);
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (style) Comma is used in return statement. The comma can easily be misread as a ';'.\n", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestOther)
|
REGISTER_TEST(TestOther)
|
||||||
|
|
Loading…
Reference in New Issue