Support char literals in CheckCondition::checkIncorrectLogicOperator() (#5912)

This commit is contained in:
PKEuS 2016-05-24 15:08:07 +02:00
parent 06a594a9e0
commit f2ae295f1e
3 changed files with 46 additions and 22 deletions

View File

@ -603,7 +603,7 @@ static inline T getvalue(const int test, const T value1, const T value2)
return 0; return 0;
} }
static bool parseComparison(const Token *comp, bool *not1, std::string *op, std::string *value, const Token **expr) static bool parseComparison(const Token *comp, bool *not1, std::string *op, std::string *value, const Token **expr, bool* inconclusive)
{ {
*not1 = false; *not1 = false;
while (comp && comp->str() == "!") { while (comp && comp->str() == "!") {
@ -636,8 +636,10 @@ static bool parseComparison(const Token *comp, bool *not1, std::string *op, std:
*expr = comp; *expr = comp;
} }
*inconclusive = *inconclusive || ((*value)[0] == '\'' && !(*op == "!=" || *op == "=="));
// Only float and int values are currently handled // Only float and int values are currently handled
if (!MathLib::isInt(*value) && !MathLib::isFloat(*value)) if (!MathLib::isInt(*value) && !MathLib::isFloat(*value) && (*value)[0] != '\'')
return false; return false;
return true; return true;
@ -679,7 +681,7 @@ void CheckCondition::checkIncorrectLogicOperator()
isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) { isOppositeCond(true, _tokenizer->isCPP(), tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) {
const bool alwaysTrue(tok->str() == "||"); const bool alwaysTrue(tok->str() == "||");
incorrectLogicOperatorError(tok, tok->expressionString(), alwaysTrue); incorrectLogicOperatorError(tok, tok->expressionString(), alwaysTrue, false);
continue; continue;
} }
@ -710,7 +712,7 @@ void CheckCondition::checkIncorrectLogicOperator()
const std::string cond1 = expr1 + " " + tok->str() + " (" + expr2 + " " + tok->astOperand2()->str() + " " + expr3 + ")"; const std::string cond1 = expr1 + " " + tok->str() + " (" + expr2 + " " + tok->astOperand2()->str() + " " + expr3 + ")";
const std::string cond2 = expr1 + " " + tok->str() + " " + expr3; const std::string cond2 = expr1 + " " + tok->str() + " " + expr3;
redundantConditionError(tok, tok2->expressionString() + ". '" + cond1 + "' is equivalent to '" + cond2 + "'"); redundantConditionError(tok, tok2->expressionString() + ". '" + cond1 + "' is equivalent to '" + cond2 + "'", false);
continue; continue;
} }
} }
@ -723,18 +725,23 @@ void CheckCondition::checkIncorrectLogicOperator()
// Comparison #2 (RHS) // Comparison #2 (RHS)
const Token *comp2 = tok->astOperand2(); const Token *comp2 = tok->astOperand2();
bool inconclusive = false;
// Parse LHS // Parse LHS
bool not1; bool not1;
std::string op1, value1; std::string op1, value1;
const Token *expr1; const Token *expr1;
if (!parseComparison(comp1, &not1, &op1, &value1, &expr1)) if (!parseComparison(comp1, &not1, &op1, &value1, &expr1, &inconclusive))
continue; continue;
// Parse RHS // Parse RHS
bool not2; bool not2;
std::string op2, value2; std::string op2, value2;
const Token *expr2; const Token *expr2;
if (!parseComparison(comp2, &not2, &op2, &value2, &expr2)) if (!parseComparison(comp2, &not2, &op2, &value2, &expr2, &inconclusive))
continue;
if (inconclusive && !_settings->inconclusive)
continue; continue;
if (isSameExpression(_tokenizer->isCPP(), true, comp1, comp2, _settings->library.functionpure)) if (isSameExpression(_tokenizer->isCPP(), true, comp1, comp2, _settings->library.functionpure))
@ -799,40 +806,40 @@ void CheckCondition::checkIncorrectLogicOperator()
const std::string cond2str = conditionString(not2, expr2, op2, value2); const std::string cond2str = conditionString(not2, expr2, op2, value2);
if (printWarning && (alwaysTrue || alwaysFalse)) { if (printWarning && (alwaysTrue || alwaysFalse)) {
const std::string text = cond1str + " " + tok->str() + " " + cond2str; const std::string text = cond1str + " " + tok->str() + " " + cond2str;
incorrectLogicOperatorError(tok, text, alwaysTrue); incorrectLogicOperatorError(tok, text, alwaysTrue, inconclusive);
} else if (printStyle && secondTrue) { } else if (printStyle && secondTrue) {
const std::string text = "If '" + cond1str + "', the comparison '" + cond2str + const std::string text = "If '" + cond1str + "', the comparison '" + cond2str +
"' is always " + (secondTrue ? "true" : "false") + "."; "' is always " + (secondTrue ? "true" : "false") + ".";
redundantConditionError(tok, text); redundantConditionError(tok, text, inconclusive);
} else if (printStyle && firstTrue) { } else if (printStyle && firstTrue) {
//const std::string text = "The comparison " + cond1str + " is always " + //const std::string text = "The comparison " + cond1str + " is always " +
// (firstTrue ? "true" : "false") + " when " + // (firstTrue ? "true" : "false") + " when " +
// cond2str + "."; // cond2str + ".";
const std::string text = "If '" + cond2str + "', the comparison '" + cond1str + const std::string text = "If '" + cond2str + "', the comparison '" + cond1str +
"' is always " + (firstTrue ? "true" : "false") + "."; "' is always " + (firstTrue ? "true" : "false") + ".";
redundantConditionError(tok, text); redundantConditionError(tok, text, inconclusive);
} }
} }
} }
} }
void CheckCondition::incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always) void CheckCondition::incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always, bool inconclusive)
{ {
if (always) if (always)
reportError(tok, Severity::warning, "incorrectLogicOperator", reportError(tok, Severity::warning, "incorrectLogicOperator",
"Logical disjunction always evaluates to true: " + condition + ".\n" "Logical disjunction always evaluates to true: " + condition + ".\n"
"Logical disjunction always evaluates to true: " + condition + ". " "Logical disjunction always evaluates to true: " + condition + ". "
"Are these conditions necessary? Did you intend to use && instead? Are the numbers correct? Are you comparing the correct variables?", CWE571, false); "Are these conditions necessary? Did you intend to use && instead? Are the numbers correct? Are you comparing the correct variables?", CWE571, inconclusive);
else else
reportError(tok, Severity::warning, "incorrectLogicOperator", reportError(tok, Severity::warning, "incorrectLogicOperator",
"Logical conjunction always evaluates to false: " + condition + ".\n" "Logical conjunction always evaluates to false: " + condition + ".\n"
"Logical conjunction always evaluates to false: " + condition + ". " "Logical conjunction always evaluates to false: " + condition + ". "
"Are these conditions necessary? Did you intend to use || instead? Are the numbers correct? Are you comparing the correct variables?", CWE570, false); "Are these conditions necessary? Did you intend to use || instead? Are the numbers correct? Are you comparing the correct variables?", CWE570, inconclusive);
} }
void CheckCondition::redundantConditionError(const Token *tok, const std::string &text) void CheckCondition::redundantConditionError(const Token *tok, const std::string &text, bool inconclusive)
{ {
reportError(tok, Severity::style, "redundantCondition", "Redundant condition: " + text, CWE398, false); reportError(tok, Severity::style, "redundantCondition", "Redundant condition: " + text, CWE398, inconclusive);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -117,8 +117,8 @@ private:
void oppositeInnerConditionError(const Token *tok1, const Token* tok2); void oppositeInnerConditionError(const Token *tok1, const Token* tok2);
void incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always); void incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always, bool inconclusive);
void redundantConditionError(const Token *tok, const std::string &text); void redundantConditionError(const Token *tok, const std::string &text, bool inconclusive);
void moduloAlwaysTrueFalseError(const Token* tok, const std::string& maxVal); void moduloAlwaysTrueFalseError(const Token* tok, const std::string& maxVal);
@ -137,8 +137,8 @@ private:
c.multiConditionError(nullptr,1); c.multiConditionError(nullptr,1);
c.mismatchingBitAndError(nullptr, 0xf0, 0, 1); c.mismatchingBitAndError(nullptr, 0xf0, 0, 1);
c.oppositeInnerConditionError(nullptr, 0); c.oppositeInnerConditionError(nullptr, 0);
c.incorrectLogicOperatorError(nullptr, "foo > 3 && foo < 4", true); c.incorrectLogicOperatorError(nullptr, "foo > 3 && foo < 4", true, false);
c.redundantConditionError(nullptr, "If x > 11 the condition x > 10 is always true."); c.redundantConditionError(nullptr, "If x > 11 the condition x > 10 is always true.", false);
c.moduloAlwaysTrueFalseError(nullptr, "1"); c.moduloAlwaysTrueFalseError(nullptr, "1");
c.clarifyConditionError(nullptr, true, false); c.clarifyConditionError(nullptr, true, false);
c.alwaysTrueFalseError(nullptr, true); c.alwaysTrueFalseError(nullptr, true);

View File

@ -84,10 +84,12 @@ private:
TEST_CASE(checkInvalidTestForOverflow); TEST_CASE(checkInvalidTestForOverflow);
} }
void check(const char code[], const char* filename = "test.cpp") { void check(const char code[], const char* filename = "test.cpp", bool inconclusive = false) {
// Clear the error buffer.. // Clear the error buffer..
errout.str(""); errout.str("");
settings0.inconclusive = inconclusive;
CheckCondition checkCondition; CheckCondition checkCondition;
// Tokenize.. // Tokenize..
@ -946,13 +948,28 @@ private:
void incorrectLogicOperator6() { // char literals void incorrectLogicOperator6() { // char literals
check("void f(char x) {\n" check("void f(char x) {\n"
" if (x == '1' || x == '2') {}\n" " if (x == '1' || x == '2') {}\n"
"}"); "}", "test.cpp", true);
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void f(char x) {\n" check("void f(char x) {\n"
" if (x == '1' && x == '2') {}\n" " if (x == '1' && x == '2') {}\n"
"}"); "}", "test.cpp", true);
TODO_ASSERT_EQUALS("error", "", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (warning) Logical conjunction always evaluates to false: x == '1' && x == '2'.\n", errout.str());
check("int f(char c) {\n"
" return (c >= 'a' && c <= 'z');\n"
"}", "test.cpp", true);
ASSERT_EQUALS("", errout.str());
check("int f(char c) {\n"
" return (c <= 'a' && c >= 'z');\n"
"}", "test.cpp", true);
ASSERT_EQUALS("[test.cpp:2]: (warning, inconclusive) Logical conjunction always evaluates to false: c <= 'a' && c >= 'z'.\n", errout.str());
check("int f(char c) {\n"
" return (c <= 'a' && c >= 'z');\n"
"}", "test.cpp", false);
ASSERT_EQUALS("", errout.str());
} }
void incorrectLogicOperator7() { // opposite expressions void incorrectLogicOperator7() { // opposite expressions