static bool parseComparison(const Token *comp, bool *not1, std::string *op, std::string *value, const Token **expr) { *not1 = false; while (comp && comp->str() == "!") { *not1 = !(*not1); comp = comp->astOperand1(); } if (!comp || !comp->isComparisonOp() || !comp->astOperand1() || !comp->astOperand2()) return false; if (comp->astOperand1()->isLiteral()) { *op = invertOperatorForOperandSwap(comp->str()); *value = comp->astOperand1()->str(); *expr = comp->astOperand2(); } else if (comp->astOperand2()->isLiteral()) { *op = comp->str(); *value = comp->astOperand2()->str(); *expr = comp->astOperand1(); } else { return false; } // Only float and int values are currently handled if (!MathLib::isInt(*value) && !MathLib::isFloat(*value)) return false; return true; }
static bool parseComparison(const Token *comp, bool *not1, std::string *op, std::string *value, const Token **expr, bool* inconclusive) { *not1 = false; while (comp && comp->str() == "!") { *not1 = !(*not1); comp = comp->astOperand1(); } if (!comp) return false; const Token* op1 = comp->astOperand1(); const Token* op2 = comp->astOperand2(); if (!comp->isComparisonOp() || !op1 || !op2) { *op = "!="; *value = "0"; *expr = comp; } else if (op1->isLiteral()) { if (op1->isExpandedMacro()) return false; *op = invertOperatorForOperandSwap(comp->str()); if (op1->enumerator() && op1->enumerator()->value_known) *value = MathLib::toString(op1->enumerator()->value); else *value = op1->str(); *expr = op2; } else if (comp->astOperand2()->isLiteral()) { if (op2->isExpandedMacro()) return false; *op = comp->str(); if (op2->enumerator() && op2->enumerator()->value_known) *value = MathLib::toString(op2->enumerator()->value); else *value = op2->str(); *expr = op1; } else { *op = "!="; *value = "0"; *expr = comp; } *inconclusive = *inconclusive || ((*value)[0] == '\'' && !(*op == "!=" || *op == "==")); // Only float and int values are currently handled if (!MathLib::isInt(*value) && !MathLib::isFloat(*value) && (*value)[0] != '\'') return false; return true; }
void CheckCondition::checkIncorrectLogicOperator() { bool style = _settings->isEnabled("style"); bool warning = _settings->isEnabled("warning"); if (!style && !warning) return; const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); const std::size_t functions = symbolDatabase->functionScopes.size(); for (std::size_t ii = 0; ii < functions; ++ii) { const Scope * scope = symbolDatabase->functionScopes[ii]; for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { // Opposite comparisons if (Token::Match(tok, "%oror%|&&") && tok->astOperand1() && tok->astOperand2() && (tok->astOperand1()->isName() || tok->astOperand2()->isName()) && isOppositeCond(tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) { const bool alwaysTrue(tok->str() == "||"); incorrectLogicOperatorError(tok, tok->expressionString(), alwaysTrue); } else if (Token::Match(tok, "&&|%oror%")) { // Comparison #1 (LHS) const Token *comp1 = tok->astOperand1(); if (comp1 && comp1->str() == tok->str()) comp1 = comp1->astOperand2(); // Comparison #2 (RHS) const Token *comp2 = tok->astOperand2(); if (!comp1 || !comp1->isComparisonOp() || !comp1->astOperand1() || !comp1->astOperand2()) continue; if (!comp2 || !comp2->isComparisonOp() || !comp2->astOperand1() || !comp2->astOperand2()) continue; std::string op1, value1; const Token *expr1; if (comp1->astOperand1()->isLiteral()) { op1 = invertOperatorForOperandSwap(comp1->str()); value1 = comp1->astOperand1()->str(); expr1 = comp1->astOperand2(); } else if (comp1->astOperand2()->isLiteral()) { op1 = comp1->str(); value1 = comp1->astOperand2()->str(); expr1 = comp1->astOperand1(); } else { continue; } std::string op2, value2; const Token *expr2; if (comp2->astOperand1()->isLiteral()) { op2 = invertOperatorForOperandSwap(comp2->str()); value2 = comp2->astOperand1()->str(); expr2 = comp2->astOperand2(); } else if (comp2->astOperand2()->isLiteral()) { op2 = comp2->str(); value2 = comp2->astOperand2()->str(); expr2 = comp2->astOperand1(); } else { continue; } // Only float and int values are currently handled if (!MathLib::isInt(value1) && !MathLib::isFloat(value1)) continue; if (!MathLib::isInt(value2) && !MathLib::isFloat(value2)) continue; if (isSameExpression(comp1, comp2, _settings->library.functionpure)) continue; // same expressions => only report that there are same expressions if (!isSameExpression(expr1, expr2, _settings->library.functionpure)) continue; const bool isfloat = astIsFloat(expr1, true) || MathLib::isFloat(value1) || astIsFloat(expr2, true) || MathLib::isFloat(value2); // don't check floating point equality comparisons. that is bad // and deserves different warnings. if (isfloat && (op1 == "==" || op1 == "!=" || op2 == "==" || op2 == "!=")) continue; // evaluate if expression is always true/false bool alwaysTrue = true, alwaysFalse = true; bool firstTrue = true, secondTrue = true; for (int test = 1; test <= 5; ++test) { // test: // 1 => testvalue is less than both value1 and value2 // 2 => testvalue is value1 // 3 => testvalue is between value1 and value2 // 4 => testvalue value2 // 5 => testvalue is larger than both value1 and value2 bool result1, result2; if (isfloat) { const double d1 = MathLib::toDoubleNumber(value1); const double d2 = MathLib::toDoubleNumber(value2); const double testvalue = getvalue<double>(test, d1, d2); result1 = checkFloatRelation(op1, testvalue, d1); result2 = checkFloatRelation(op2, testvalue, d2); } else { const MathLib::bigint i1 = MathLib::toLongNumber(value1); const MathLib::bigint i2 = MathLib::toLongNumber(value2); const MathLib::bigint testvalue = getvalue<MathLib::bigint>(test, i1, i2); result1 = checkIntRelation(op1, testvalue, i1); result2 = checkIntRelation(op2, testvalue, i2); } if (tok->str() == "&&") { alwaysTrue &= (result1 && result2); alwaysFalse &= !(result1 && result2); } else { alwaysTrue &= (result1 || result2); alwaysFalse &= !(result1 || result2); } firstTrue &= !(!result1 && result2); secondTrue &= !(result1 && !result2); } const std::string cond1str = (expr1->isName() ? expr1->str() : "EXPR") + " " + op1 + " " + value1; const std::string cond2str = (expr2->isName() ? expr2->str() : "EXPR") + " " + op2 + " " + value2; if (warning && (alwaysTrue || alwaysFalse)) { const std::string text = cond1str + " " + tok->str() + " " + cond2str; incorrectLogicOperatorError(tok, text, alwaysTrue); } else if (style && secondTrue) { const std::string text = "If " + cond1str + ", the comparison " + cond2str + " is always " + (secondTrue ? "true" : "false") + "."; redundantConditionError(tok, text); } else if (style && firstTrue) { //const std::string text = "The comparison " + cond1str + " is always " + // (firstTrue ? "true" : "false") + " when " + // cond2str + "."; const std::string text = "If " + cond2str + ", the comparison " + cond1str + " is always " + (firstTrue ? "true" : "false") + "."; redundantConditionError(tok, text); } } } } }