@@ -641,6 +641,187 @@ static std::string conditionString(bool not1, const Token *expr1, const std::str
641641 (expr1->isName () ? expr1->str () : std::string (" EXPR" ));
642642}
643643
644+ void CheckCondition::checkIncorrectCondition ()
645+ {
646+ const bool printStyle = _settings->isEnabled (" style" );
647+ const bool printWarning = _settings->isEnabled (" warning" );
648+ if (!printWarning && !printStyle)
649+ return ;
650+
651+ const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase ();
652+ const std::size_t functions = symbolDatabase->functionScopes .size ();
653+ for (std::size_t ii = 0 ; ii < functions; ++ii) {
654+ const Scope * scope = symbolDatabase->functionScopes [ii];
655+
656+ for (const Token* tok = scope->classStart ->next (); tok != scope->classEnd ; tok = tok->next ()) {
657+ if (!Token::Match (tok, " %oror%|&&" ) || !tok->astOperand1 () || !tok->astOperand2 ())
658+ continue ;
659+
660+ // Opposite comparisons around || or && => always true or always false
661+ if ((tok->astOperand1 ()->isName () || tok->astOperand2 ()->isName ()) &&
662+ isIncorrectCond (true , _tokenizer->isCPP (), tok->astOperand1 (), tok->astOperand2 (), _settings->library .functionpure )) {
663+
664+ const bool alwaysTrue (tok->str () == " ||" );
665+ incorrectConditionError (tok, tok->expressionString (), alwaysTrue);
666+ continue ;
667+ }
668+
669+
670+ // 'A && (!A || B)' is equivalent with 'A && B'
671+ // 'A || (!A && B)' is equivalent with 'A || B'
672+ if (printStyle &&
673+ ((tok->str () == " ||" && tok->astOperand2 ()->str () == " &&" ) ||
674+ (tok->str () == " &&" && tok->astOperand2 ()->str () == " ||" ))) {
675+ const Token* tok2 = tok->astOperand2 ()->astOperand1 ();
676+ if (isIncorrectCond (true , _tokenizer->isCPP (), tok->astOperand1 (), tok2, _settings->library .functionpure )) {
677+ std::string expr1 (tok->astOperand1 ()->expressionString ());
678+ std::string expr2 (tok->astOperand2 ()->astOperand1 ()->expressionString ());
679+ std::string expr3 (tok->astOperand2 ()->astOperand2 ()->expressionString ());
680+
681+ if (expr1.length () + expr2.length () + expr3.length () > 50U ) {
682+ if (expr1[0 ] == ' !' && expr2[0 ] != ' !' ) {
683+ expr1 = " !A" ;
684+ expr2 = " A" ;
685+ } else {
686+ expr1 = " A" ;
687+ expr2 = " !A" ;
688+ }
689+
690+ expr3 = " B" ;
691+ }
692+
693+ const std::string cond1 = expr1 + " " + tok->str () + " (" + expr2 + " " + tok->astOperand2 ()->str () + " " + expr3 + " )" ;
694+ const std::string cond2 = expr1 + " " + tok->str () + " " + expr3;
695+
696+ redundantConditionError (tok, tok2->expressionString () + " . '" + cond1 + " ' is equivalent to '" + cond2 + " '" );
697+ continue ;
698+ }
699+ }
700+
701+ // Comparison #1 (LHS)
702+ const Token *comp1 = tok->astOperand1 ();
703+ if (comp1 && comp1->str () == tok->str ())
704+ comp1 = comp1->astOperand2 ();
705+
706+ // Comparison #2 (RHS)
707+ const Token *comp2 = tok->astOperand2 ();
708+
709+ // Parse LHS
710+ bool not1;
711+ std::string op1, value1;
712+ const Token *expr1;
713+ if (!parseComparison (comp1, ¬1, &op1, &value1, &expr1))
714+ continue ;
715+
716+ // Parse RHS
717+ bool not2;
718+ std::string op2, value2;
719+ const Token *expr2;
720+ if (!parseComparison (comp2, ¬2, &op2, &value2, &expr2))
721+ continue ;
722+
723+ if (isSameExpression (_tokenizer->isCPP (), comp1, comp2, _settings->library .functionpure ))
724+ continue ; // same expressions => only report that there are same expressions
725+ if (!isSameExpression (_tokenizer->isCPP (), expr1, expr2, _settings->library .functionpure )) {
726+ if ((tok->astOperand1 ()->isConstOp () && tok->astOperand2 ()->isConstOp ()) &&
727+ isIncorrectCond (true , _tokenizer->isCPP (), tok->astOperand1 (), tok->astOperand2 (), _settings->library .functionpure )) {
728+
729+ const bool alwaysTrue (tok->str () == " ||" );
730+ incorrectConditionError (tok, tok->expressionString (), alwaysTrue);
731+ }
732+ continue ;
733+ }
734+
735+ const bool isfloat = astIsFloat (expr1, true ) || MathLib::isFloat (value1) || astIsFloat (expr2, true ) || MathLib::isFloat (value2);
736+
737+ // don't check floating point equality comparisons. that is bad
738+ // and deserves different warnings.
739+ if (isfloat && (op1 == " ==" || op1 == " !=" || op2 == " ==" || op2 == " !=" ))
740+ continue ;
741+
742+ const double d1 = (isfloat) ? MathLib::toDoubleNumber (value1) : 0 ;
743+ const double d2 = (isfloat) ? MathLib::toDoubleNumber (value2) : 0 ;
744+ const MathLib::bigint i1 = (isfloat) ? 0 : MathLib::toLongNumber (value1);
745+ const MathLib::bigint i2 = (isfloat) ? 0 : MathLib::toLongNumber (value2);
746+ const bool useUnsignedInt = (std::numeric_limits<MathLib::bigint>::max ()==i1)||(std::numeric_limits<MathLib::bigint>::max ()==i2);
747+ const MathLib::biguint u1 = (useUnsignedInt) ? MathLib::toLongNumber (value1) : 0 ;
748+ const MathLib::biguint u2 = (useUnsignedInt) ? MathLib::toLongNumber (value2) : 0 ;
749+ // evaluate if expression is always true/false
750+ bool alwaysTrue = true , alwaysFalse = true ;
751+ bool firstTrue = true , secondTrue = true ;
752+ for (int test = 1 ; test <= 5 ; ++test) {
753+ // test:
754+ // 1 => testvalue is less than both value1 and value2
755+ // 2 => testvalue is value1
756+ // 3 => testvalue is between value1 and value2
757+ // 4 => testvalue value2
758+ // 5 => testvalue is larger than both value1 and value2
759+ bool result1, result2;
760+ if (isfloat) {
761+ const double testvalue = getvalue<double >(test, d1, d2);
762+ result1 = checkFloatRelation (op1, testvalue, d1);
763+ result2 = checkFloatRelation (op2, testvalue, d2);
764+ } else if (useUnsignedInt) {
765+ const MathLib::biguint testvalue = getvalue<MathLib::biguint>(test, u1, u2);
766+ result1 = checkIntRelation (op1, testvalue, u1);
767+ result2 = checkIntRelation (op2, testvalue, u2);
768+ } else {
769+ const MathLib::bigint testvalue = getvalue<MathLib::bigint>(test, i1, i2);
770+ result1 = checkIntRelation (op1, testvalue, i1);
771+ result2 = checkIntRelation (op2, testvalue, i2);
772+ }
773+ if (not1)
774+ result1 = !result1;
775+ if (not2)
776+ result2 = !result2;
777+ if (tok->str () == " &&" ) {
778+ alwaysTrue &= (result1 && result2);
779+ alwaysFalse &= !(result1 && result2);
780+ } else {
781+ alwaysTrue &= (result1 || result2);
782+ alwaysFalse &= !(result1 || result2);
783+ }
784+ firstTrue &= !(!result1 && result2);
785+ secondTrue &= !(result1 && !result2);
786+ }
787+
788+ const std::string cond1str = conditionString (not1, expr1, op1, value1);
789+ const std::string cond2str = conditionString (not2, expr2, op2, value2);
790+ if (printWarning && (alwaysTrue || alwaysFalse)) {
791+ const std::string text = cond1str + " " + tok->str () + " " + cond2str;
792+ incorrectConditionError (tok, text, alwaysTrue);
793+ } else if (printStyle && secondTrue) {
794+ const std::string text = " If '" + cond1str + " ', the comparison '" + cond2str +
795+ " ' is always " + (secondTrue ? " true" : " false" ) + " ." ;
796+ redundantConditionError (tok, text);
797+ } else if (printStyle && firstTrue) {
798+ // const std::string text = "The comparison " + cond1str + " is always " +
799+ // (firstTrue ? "true" : "false") + " when " +
800+ // cond2str + ".";
801+ const std::string text = " If '" + cond2str + " ', the comparison '" + cond1str +
802+ " ' is always " + (firstTrue ? " true" : " false" ) + " ." ;
803+ redundantConditionError (tok, text);
804+ }
805+ }
806+ }
807+ }
808+
809+ void CheckCondition::incorrectConditionError (const Token *tok, const std::string &condition, bool always)
810+ {
811+ if (always)
812+ reportError (tok, Severity::warning, " IncorrectCondition" ,
813+ " Condition always evaluates to true: " + condition + " .\n "
814+ " Condition always evaluates to true: " + condition + " . "
815+ " Are these conditions necessary? Did you intend to use && instead? Are the numbers correct? Are you comparing the correct variables?" );
816+ else
817+ reportError (tok, Severity::warning, " IncorrectCondition" ,
818+ " Condition always evaluates to false: " + condition + " .\n "
819+ " Condition always evaluates to false: " + condition + " . "
820+ " Are these conditions necessary? Did you intend to use || instead? Are the numbers correct? Are you comparing the correct variables?" );
821+ }
822+
823+
824+
644825void CheckCondition::checkIncorrectLogicOperator ()
645826{
646827 const bool printStyle = _settings->isEnabled (" style" );
@@ -813,6 +994,7 @@ void CheckCondition::incorrectLogicOperatorError(const Token *tok, const std::st
813994 " Are these conditions necessary? Did you intend to use || instead? Are the numbers correct? Are you comparing the correct variables?" );
814995}
815996
997+
816998void CheckCondition::redundantConditionError (const Token *tok, const std::string &text)
817999{
8181000 reportError (tok, Severity::style, " redundantCondition" , " Redundant condition: " + text);
0 commit comments