Improved check (#6391): Detect identical code in both branches of ternary operator
This commit is contained in:
parent
bb9ce68354
commit
267552779d
|
@ -87,7 +87,7 @@ bool isSameExpression(const Token *tok1, const Token *tok2, const std::set<std::
|
||||||
tok1 = tok1->astOperand2();
|
tok1 = tok1->astOperand2();
|
||||||
if (tok2->str() == "." && tok2->astOperand1() && tok2->astOperand1()->str() == "this")
|
if (tok2->str() == "." && tok2->astOperand1() && tok2->astOperand1()->str() == "this")
|
||||||
tok2 = tok2->astOperand2();
|
tok2 = tok2->astOperand2();
|
||||||
if (tok1->str() != tok2->str() || tok1->varId() != tok2->varId())
|
if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str())
|
||||||
return false;
|
return false;
|
||||||
if (tok1->str() == "." && tok1->originalName() != tok2->originalName())
|
if (tok1->str() == "." && tok1->originalName() != tok2->originalName())
|
||||||
return false;
|
return false;
|
||||||
|
@ -2303,6 +2303,7 @@ void CheckOther::checkDuplicateExpression()
|
||||||
|
|
||||||
std::list<Scope>::const_iterator scope;
|
std::list<Scope>::const_iterator scope;
|
||||||
std::list<const Function*> constFunctions;
|
std::list<const Function*> constFunctions;
|
||||||
|
const std::set<std::string> temp; // Can be used as dummy for isSameExpression()
|
||||||
getConstFunctions(symbolDatabase, constFunctions);
|
getConstFunctions(symbolDatabase, constFunctions);
|
||||||
|
|
||||||
for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
|
for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
|
||||||
|
@ -2350,6 +2351,9 @@ void CheckOther::checkDuplicateExpression()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") {
|
||||||
|
if (isSameExpression(tok->astOperand1(), tok->astOperand2(), temp))
|
||||||
|
duplicateExpressionTernaryError(tok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2367,6 +2371,13 @@ void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2,
|
||||||
"determine if it is correct.");
|
"determine if it is correct.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckOther::duplicateExpressionTernaryError(const Token *tok)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::style, "duplicateExpressionTernary", "Same expression in both branches of ternary operator.\n"
|
||||||
|
"Finding the same expression in both branches of ternary operator is suspicious as "
|
||||||
|
"the same code is executed regardless of the condition.");
|
||||||
|
}
|
||||||
|
|
||||||
void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname)
|
void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::warning,
|
reportError(tok, Severity::warning,
|
||||||
|
|
|
@ -271,6 +271,7 @@ private:
|
||||||
void duplicateIfError(const Token *tok1, const Token *tok2);
|
void duplicateIfError(const Token *tok1, const Token *tok2);
|
||||||
void duplicateBranchError(const Token *tok1, const Token *tok2);
|
void duplicateBranchError(const Token *tok1, const Token *tok2);
|
||||||
void duplicateExpressionError(const Token *tok1, const Token *tok2, const std::string &op);
|
void duplicateExpressionError(const Token *tok1, const Token *tok2, const std::string &op);
|
||||||
|
void duplicateExpressionTernaryError(const Token *tok);
|
||||||
void alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
void alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
||||||
void alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
void alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
||||||
void duplicateBreakError(const Token *tok, bool inconclusive);
|
void duplicateBreakError(const Token *tok, bool inconclusive);
|
||||||
|
@ -331,6 +332,7 @@ private:
|
||||||
c.clarifyStatementError(0);
|
c.clarifyStatementError(0);
|
||||||
c.duplicateBranchError(0, 0);
|
c.duplicateBranchError(0, 0);
|
||||||
c.duplicateExpressionError(0, 0, "&&");
|
c.duplicateExpressionError(0, 0, "&&");
|
||||||
|
c.duplicateExpressionTernaryError(0);
|
||||||
c.duplicateBreakError(0, false);
|
c.duplicateBreakError(0, false);
|
||||||
c.unreachableCodeError(0, false);
|
c.unreachableCodeError(0, false);
|
||||||
c.unsignedLessThanZeroError(0, "varname", false);
|
c.unsignedLessThanZeroError(0, "varname", false);
|
||||||
|
|
|
@ -140,6 +140,7 @@ private:
|
||||||
TEST_CASE(duplicateExpression4); // ticket #3354 (++)
|
TEST_CASE(duplicateExpression4); // ticket #3354 (++)
|
||||||
TEST_CASE(duplicateExpression5); // ticket #3749 (macros with same values)
|
TEST_CASE(duplicateExpression5); // ticket #3749 (macros with same values)
|
||||||
TEST_CASE(duplicateExpression6); // ticket #4639
|
TEST_CASE(duplicateExpression6); // ticket #4639
|
||||||
|
TEST_CASE(duplicateExpressionTernary); // #6391
|
||||||
|
|
||||||
TEST_CASE(checkSignOfUnsignedVariable);
|
TEST_CASE(checkSignOfUnsignedVariable);
|
||||||
TEST_CASE(checkSignOfPointer);
|
TEST_CASE(checkSignOfPointer);
|
||||||
|
@ -4322,6 +4323,23 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void duplicateExpressionTernary() { // #6391
|
||||||
|
check("void f() {\n"
|
||||||
|
" return A ? x : x;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) Same expression in both branches of ternary operator.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" if( a ? (b ? false:false): false ) ;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) Same expression in both branches of ternary operator.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" return A ? x : z;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void check_signOfUnsignedVariable(const char code[], bool inconclusive=false) {
|
void check_signOfUnsignedVariable(const char code[], bool inconclusive=false) {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
Loading…
Reference in New Issue