New check: Find suspicious case labels like 'case A||B:'
This commit is contained in:
parent
65db8b8b9f
commit
0ac4c3baf4
|
@ -1057,6 +1057,42 @@ void CheckOther::switchCaseFallThrough(const Token *tok)
|
||||||
"switchCaseFallThrough", "Switch falls through case without comment. 'break;' missing?");
|
"switchCaseFallThrough", "Switch falls through case without comment. 'break;' missing?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Check for statements like case A||B: in switch()
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void CheckOther::checkSuspiciousCaseInSwitch()
|
||||||
|
{
|
||||||
|
if (!_settings->inconclusive || !_settings->isEnabled("style"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
|
|
||||||
|
for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
|
||||||
|
if (i->type != Scope::eSwitch)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (const Token* tok = i->classStart->next(); tok != i->classEnd; tok = tok->next()) {
|
||||||
|
if (tok->str() == "case") {
|
||||||
|
for (const Token* tok2 = tok->next(); tok2; tok2 = tok2->next()) {
|
||||||
|
if (Token::Match(tok2, "[:;}{]"))
|
||||||
|
break;
|
||||||
|
if (Token::Match(tok2, "&&|%oror%"))
|
||||||
|
suspiciousCaseInSwitchError(tok, tok2->str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckOther::suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::warning, "suspiciousCase",
|
||||||
|
"Found suspicious case label in switch(). Operator '" + operatorString + "' probably doesn't work as intended.\n"
|
||||||
|
"Using an operator like '" + operatorString + "' in a case label is suspicious. Did you intend to use a bitwise operator, multiple case labels or if/else instead?", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// int x = 1;
|
// int x = 1;
|
||||||
// x = x; // <- redundant assignment to self
|
// x = x; // <- redundant assignment to self
|
||||||
|
|
|
@ -62,6 +62,7 @@ public:
|
||||||
checkOther.suspiciousSizeofCalculation();
|
checkOther.suspiciousSizeofCalculation();
|
||||||
checkOther.checkRedundantAssignment();
|
checkOther.checkRedundantAssignment();
|
||||||
checkOther.checkRedundantAssignmentInSwitch();
|
checkOther.checkRedundantAssignmentInSwitch();
|
||||||
|
checkOther.checkSuspiciousCaseInSwitch();
|
||||||
checkOther.checkAssignmentInAssert();
|
checkOther.checkAssignmentInAssert();
|
||||||
checkOther.checkSizeofForArrayParameter();
|
checkOther.checkSizeofForArrayParameter();
|
||||||
checkOther.checkSizeofForPointerSize();
|
checkOther.checkSizeofForPointerSize();
|
||||||
|
@ -186,6 +187,9 @@ public:
|
||||||
/** @brief %Check for assigning to the same variable twice in a switch statement*/
|
/** @brief %Check for assigning to the same variable twice in a switch statement*/
|
||||||
void checkRedundantAssignmentInSwitch();
|
void checkRedundantAssignmentInSwitch();
|
||||||
|
|
||||||
|
/** @brief %Check for code like 'case A||B:'*/
|
||||||
|
void checkSuspiciousCaseInSwitch();
|
||||||
|
|
||||||
/** @brief %Check for switch case fall through without comment */
|
/** @brief %Check for switch case fall through without comment */
|
||||||
void checkSwitchCaseFallThrough();
|
void checkSwitchCaseFallThrough();
|
||||||
|
|
||||||
|
@ -311,6 +315,7 @@ private:
|
||||||
void redundantCopyInSwitchError(const Token *tok1, const Token* tok2, const std::string &var);
|
void redundantCopyInSwitchError(const Token *tok1, const Token* tok2, const std::string &var);
|
||||||
void redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname);
|
void redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname);
|
||||||
void switchCaseFallThrough(const Token *tok);
|
void switchCaseFallThrough(const Token *tok);
|
||||||
|
void suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString);
|
||||||
void selfAssignmentError(const Token *tok, const std::string &varname);
|
void selfAssignmentError(const Token *tok, const std::string &varname);
|
||||||
void assignmentInAssertError(const Token *tok, const std::string &varname);
|
void assignmentInAssertError(const Token *tok, const std::string &varname);
|
||||||
void incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always);
|
void incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always);
|
||||||
|
@ -392,6 +397,7 @@ private:
|
||||||
c.redundantAssignmentInSwitchError(0, 0, "var");
|
c.redundantAssignmentInSwitchError(0, 0, "var");
|
||||||
c.redundantCopyInSwitchError(0, 0, "var");
|
c.redundantCopyInSwitchError(0, 0, "var");
|
||||||
c.switchCaseFallThrough(0);
|
c.switchCaseFallThrough(0);
|
||||||
|
c.suspiciousCaseInSwitchError(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);
|
||||||
|
@ -469,6 +475,7 @@ private:
|
||||||
"* look for calculations inside sizeof()\n"
|
"* look for calculations inside sizeof()\n"
|
||||||
"* look for suspicious calculations with sizeof()\n"
|
"* look for suspicious calculations with sizeof()\n"
|
||||||
"* assignment of a variable to itself\n"
|
"* assignment of a variable to itself\n"
|
||||||
|
"* Suspicious case labels in switch()\n"
|
||||||
"* mutual exclusion over || always evaluating to true\n"
|
"* mutual exclusion over || always evaluating to true\n"
|
||||||
"* Clarify calculation with parentheses\n"
|
"* Clarify calculation with parentheses\n"
|
||||||
"* using increment on boolean\n"
|
"* using increment on boolean\n"
|
||||||
|
|
|
@ -86,6 +86,8 @@ private:
|
||||||
TEST_CASE(switchFallThroughCase);
|
TEST_CASE(switchFallThroughCase);
|
||||||
TEST_CASE(unreachableCode);
|
TEST_CASE(unreachableCode);
|
||||||
|
|
||||||
|
TEST_CASE(suspiciousCase);
|
||||||
|
|
||||||
TEST_CASE(selfAssignment);
|
TEST_CASE(selfAssignment);
|
||||||
TEST_CASE(trac1132);
|
TEST_CASE(trac1132);
|
||||||
TEST_CASE(testMisusedScopeObjectDoesNotPickFunction1);
|
TEST_CASE(testMisusedScopeObjectDoesNotPickFunction1);
|
||||||
|
@ -2726,6 +2728,31 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void suspiciousCase() {
|
||||||
|
check("void foo() {\n"
|
||||||
|
" switch(a) {\n"
|
||||||
|
" case A&&B:\n"
|
||||||
|
" foo();\n"
|
||||||
|
" case (A||B):\n"
|
||||||
|
" foo();\n"
|
||||||
|
" case 1||5:\n"
|
||||||
|
" foo();\n"
|
||||||
|
" }\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Found suspicious case label in switch(). Operator '&&' probably doesn't work as intended.\n"
|
||||||
|
"[test.cpp:5]: (warning, inconclusive) Found suspicious case label in switch(). Operator '||' probably doesn't work as intended.\n"
|
||||||
|
"[test.cpp:7]: (warning, inconclusive) Found suspicious case label in switch(). Operator '||' probably doesn't work as intended.\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo() {\n"
|
||||||
|
" switch(a) {\n"
|
||||||
|
" case 1:\n"
|
||||||
|
" a=A&&B;\n"
|
||||||
|
" }\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void selfAssignment() {
|
void selfAssignment() {
|
||||||
check("void foo()\n"
|
check("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
|
Loading…
Reference in New Issue