New check: Detect ineffective statements like '*foo++;' (Should be: '(*foo)++;')

This commit is contained in:
PKEuS 2012-08-23 12:28:40 -07:00
parent 674f7980d5
commit 1bcdf4ce3d
3 changed files with 112 additions and 45 deletions

View File

@ -230,7 +230,38 @@ void CheckOther::clarifyConditionError(const Token *tok, bool assign, bool boolo
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// if (bool & bool) -> if (bool && bool) // Clarify (meaningless) statements like *foo++; with parantheses.teStatement()
{
if (!_settings->isEnabled("style"))
return;
fovoid CheckOther::clarifyStatementves. This pattern only checks for string.
// Investifor (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "[{};] * %var%")) {
tok = tok->tokAt(3);
while (tok) {
if (tok->str() == "[")
tok = tok->link()->next();
if (Token::Match(tok, ".|:: %var%")) {
if (tok->strAt(2) == "(")
tok = tok->linkAt(2)->next();
else
tok = tok->tokAt(2);
} else
break;
}
if (Token::Match(tok, "++|-- [;,]"))
clarifyStatementError(tok);
}
}
}
void CheckOther::clarifyStatementError(const Token *tok)
{
reportError(tok, Severity::warning, "clarifyStatement", "Ineffective statement similar to '*A++;'. Did you intend to write '(*A)++;'?\n"
"A statement like '*A++;' might not do what you intended. 'operator*' is executed before postfix 'operator++'. "
"Thus, the dereference is meaningless. Did you intend to write '(*A)++;'?ossible unexpanded macro hiding for/while..
else if (tok->str() != "else" &&if (bool & bool) -> if (bool && bool)
// if (bool | bool) -> if (bool || bool) // if (bool | bool) -> if (bool || bool)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CheckOther::checkBitwiseOnBoolean() void CheckOther::checkBitwiseOnBoolean()
@ -2164,50 +2195,36 @@ void CheckOther::incorrectStringBooleanError(const Token *tok, const std::string
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// check for duplicate expressions in if statements // check for duplicate expressions in if statements
// if (a) { } else if (a) { } // if (a) { } else if (a) { }
//----------------------------------------------------------------------------- //----------------------------ok1->linkAt(3), ") {")) {
// get the expression from the token stream
expression = tok1->tokAt(4)->stringifyList(tok1->linkAt(3));
static bool expressionHasSideEffects(const Token *first, const Token *last) // try to look up the expression to check for duplicates
{ std::map<std::string, const Token *>::iterator it = expressionMap.find(expression);
for (const Token *tok = first; tok != last->next(); tok = tok->next()) {
// check for assignment
if (tok->isAssignmentOp())
return true;
// check for inc/dec // found a duplicate
else if (tok->type() == Token::eIncDecOp) if (it != expressionMap.end()) {
return true; // check for expressions that have side effects and ignore them
if (!expressionHasSideEffects(tok1->tokAt(4), tok1->linkAt(3)->previous()))
duplicateIfError(it->second, tok1->next());
}
// check for function call // not a duplicate expression so save it and its location
else if (Token::Match(tok, "%var% (") && else
!(Token::Match(tok, "c_str|string") || tok->isStandardType())) expressionMap.insert(std::make_pair(expression, tok1->next()));
return true;
// find the next else if (...) statement
tok1 = tok1->linkAt(3)->next()->link();
}
} }
return false;
} }
void CheckOther::checkDuplicateIf() void CheckOther::duplicateIf else if (Token::simpleMatch(tok->next()->link(), ") ;")) {
{ for (const Token* tok2 = tok->tokAt(2); tok2 != tok->linkAt(1); tok2 = tok2->next()) {
if (!_settings->isEnabled("style")) If", "Found duplicate if expressions.\n"
return; "Finding the same expression more than once is suspicious and might indicate "
"a cut and paste or logic error. Please examine this code carefully to determine "
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); "if it is next else if (...) statement
for (std::list<Scope>::const_iterator scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
const Token* const tok = scope->classDef;
// only check if statements
if (scope->type != Scope::eIf || !tok)
continue;
std::map<std::string, const Token*> expressionMap;
// get the expression from the token stream
std::string expression = tok->tokAt(2)->stringifyList(tok->next()->link());
// save the expression and its location
expressionMap.insert(std::make_pair(expression, tok));
// find the next else if (...) statement
const Token *tok1 = scope->classEnd; const Token *tok1 = scope->classEnd;
// check all the else if (...) statements // check all the else if (...) statements

View File

@ -83,6 +83,7 @@ public:
// Checks // Checks
checkOther.clarifyCalculation(); checkOther.clarifyCalculation();
checkOther.clarifyStatement();
checkOther.checkConstantFunctionParameter(); checkOther.checkConstantFunctionParameter();
checkOther.checkIncompleteStatement(); checkOther.checkIncompleteStatement();
@ -111,7 +112,8 @@ public:
/** @brief Clarify calculation for ".. a * b ? .." */ /** @brief Clarify calculation for ".. a * b ? .." */
void clarifyCalculation(); void clarifyCalculation();
/** @brief Suspicious condition (assignment+comparison) */ /** @brief Suspicious condition (assignment+comparison) Suspicious statement like '*A++;' */
void clarifyStatementignment+comparison) */
void clarifyCondition(); void clarifyCondition();
/** @brief Are there C-style pointer casts in a c++ file? */ /** @brief Are there C-style pointer casts in a c++ file? */
@ -247,7 +249,7 @@ public:
void checkNegativeBitwiseShift(); void checkNegativeBitwiseShift();
private: private:
// Error messages.. // Error messages.clarifyStatementError(const Token* tokor messages..
void clarifyCalculationError(const Token *tok, const std::string &op); void clarifyCalculationError(const Token *tok, const std::string &op);
void clarifyConditionError(const Token *tok, bool assign, bool boolop); void clarifyConditionError(const Token *tok, bool assign, bool boolop);
void sizeofsizeofError(const Token *tok); void sizeofsizeofError(const Token *tok);
@ -339,6 +341,7 @@ private:
c.redundantAssignmentInSwitchError(0, "varname"); c.redundantAssignmentInSwitchError(0, "varname");
c.redundantOperationInSwitchError(0, "varname"); c.redundantOperationInSwitchError(0, "varname");
c.switchCaseFallThrough(0); c.switchCaseFallThrough(0);
clarifyStatementError(0lThrough(0);
c.selfAssignmentError(0, "varname"); c.selfAssignmentError(0, "varname");
c.assignmentInAssertError(0, "varname"); c.assignmentInAssertError(0, "varname");
c.incorrectLogicOperatorError(0, "foo > 3 && foo < 4", true); c.incorrectLogicOperatorError(0, "foo > 3 && foo < 4", true);

View File

@ -116,7 +116,7 @@ private:
TEST_CASE(memsetZeroBytes); TEST_CASE(memsetZeroBytes);
TEST_CASE(sizeofForArrayParameter); TEST_CASE(sizeofForArrayParameter);
TEST_CASE(sizeofForNumericParameter); TEST_CASE(sizeofForNumericPar TEST_CASE(clarifyStatementParameter);
TEST_CASE(clarifyCalculation); TEST_CASE(clarifyCalculation);
@ -3030,8 +3030,14 @@ private:
"[test.cpp:3]: (warning) Comparison of modulo result is predetermined, because it is always less than 5.\n" "[test.cpp:3]: (warning) Comparison of modulo result is predetermined, because it is always less than 5.\n"
"[test.cpp:4]: (warning) Comparison of modulo result is predetermined, because it is always less than 5.\n" "[test.cpp:4]: (warning) Comparison of modulo result is predetermined, because it is always less than 5.\n"
"[test.cpp:5]: (warning) Comparison of modulo result is predetermined, because it is always less than 5.\n" "[test.cpp:5]: (warning) Comparison of modulo result is predetermined, because it is always less than 5.\n"
"[test.cpp:6]: (warning) Comparison of modulo result is predetermined, because icause it is always less than 5.\n" "[test.cpp:6]: (warning) Comparison of modu "}\n"
"[test.cpp:3]: (warning) Comparison of modulo result is predetermined, x > 5 && x != l conjunction always evaluates to false: x < 1 && x > 1.\n", errout.str()); );
ASSERT_EQUALS("", errout.str());
check("void f(i || x <= 3.\n", errout.str());
check("void f(int x) {\n"
x > 5 && x != l conjunction always evaluates to false: x < 1 && x > 1.\n", errout.str());
check("void "}\n" check("void "}\n"
); );
@ -3634,7 +3640,48 @@ sult is predetermined, because it is always less than 5.\n"
); );
ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational (<, >, <= or >=) operator.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison of a boolean value using relational (<, >, <= or >=) operator.\n", errout.str());
check("void f(bool x ) {\n" check("voidvoid clarifyStatement() {
check("char* f(char* c) {\n"
" *c++;\n"
" return c;n
void clarifyCondition1() {
check("void f() {\n"
Ineffective statement similar to '*A++;'. Did you intend to write '(*A)++;'?\n", errout.str());
check("char* f(char** c) {\n"
" *c[5]--;\n"
" return *c;n
void clarifyCondition1() {
check("void f() {\n"
Ineffective statement similar to '*A++;'. Did you intend to write '(*A)++;'?\n", errout.str());
check("void f(Foo f) {\n"
" *f.a++;n
void clarifyCondition1() {
check("void f() {\n"
Ineffective statement similar to '*A++;'. Did you intend to write '(*A)++;'?\n", errout.str());
check("void f(Foo f) {\n"
" *f.a[5].v[3]++;n
void clarifyCondition1() {
check("void f() {\n"
Ineffective statement similar to '*A++;'. Did you intend to write '(*A)++;'?\n", errout.str());
check("void f(Foo f) {\n"
" *f.a(1, 5).v[x + y]++;n
void clarifyCondition1() {
check("void f() {\n"
Ineffective statement similar to '*A++;'. Did you intend to write '(*A)++;'?\n", errout.str());
check("char* f(char* c) {\n"
" (*c)++;\n"
" return cl 0"
" bytes of \'p\'\n", errout.str());
check("void f(char* c) {\n"
" bar(*c++) check("void f(int x) {\n"
" if (x < 1 && x > 1check("void f(bool x ) {\n"
" if ( false <= x )\n" " if ( false <= x )\n"
" a++;\n" " a++;\n"
"}\n" "}\n"