LCOV - code coverage report
Current view: top level - lib - checkcondition.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 1236 1323 93.4 %
Date: 2024-04-28 12:00:40 Functions: 74 74 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Cppcheck - A tool for static C/C++ code analysis
       3             :  * Copyright (C) 2007-2024 Cppcheck team.
       4             :  *
       5             :  * This program is free software: you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation, either version 3 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             :  */
      18             : 
      19             : //---------------------------------------------------------------------------
      20             : // Check for condition mismatches
      21             : //---------------------------------------------------------------------------
      22             : 
      23             : #include "checkcondition.h"
      24             : 
      25             : #include "astutils.h"
      26             : #include "library.h"
      27             : #include "platform.h"
      28             : #include "settings.h"
      29             : #include "symboldatabase.h"
      30             : #include "token.h"
      31             : #include "tokenize.h"
      32             : #include "utils.h"
      33             : #include "vfvalue.h"
      34             : 
      35             : #include "checkother.h" // comparisonNonZeroExpressionLessThanZero and testIfNonZeroExpressionIsPositive
      36             : 
      37             : #include <algorithm>
      38             : #include <limits>
      39             : #include <list>
      40             : #include <set>
      41             : #include <sstream>
      42             : #include <utility>
      43             : #include <vector>
      44             : 
      45             : // CWE ids used
      46             : static const CWE uncheckedErrorConditionCWE(391U);
      47             : static const CWE CWE398(398U);   // Indicator of Poor Code Quality
      48             : static const CWE CWE570(570U);   // Expression is Always False
      49             : static const CWE CWE571(571U);   // Expression is Always True
      50             : 
      51             : //---------------------------------------------------------------------------
      52             : 
      53             : // Register this check class (by creating a static instance of it)
      54             : namespace {
      55             :     CheckCondition instance;
      56             : }
      57             : 
      58         999 : bool CheckCondition::diag(const Token* tok, bool insert)
      59             : {
      60         999 :     if (!tok)
      61          48 :         return false;
      62         951 :     const Token* parent = tok->astParent();
      63         951 :     bool hasParent = false;
      64        1043 :     while (Token::Match(parent, "!|&&|%oror%")) {
      65         154 :         if (mCondDiags.count(parent) != 0) {
      66          62 :             hasParent = true;
      67          62 :             break;
      68             :         }
      69          92 :         parent = parent->astParent();
      70             :     }
      71         951 :     if (mCondDiags.count(tok) == 0 && !hasParent) {
      72         775 :         if (insert)
      73         246 :             mCondDiags.insert(tok);
      74         775 :         return false;
      75             :     }
      76         176 :     return true;
      77             : }
      78             : 
      79          51 : bool CheckCondition::isAliased(const std::set<int> &vars) const
      80             : {
      81        1652 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
      82        1601 :         if (Token::Match(tok, "= & %var% ;") && vars.find(tok->tokAt(2)->varId()) != vars.end())
      83           0 :             return true;
      84             :     }
      85          51 :     return false;
      86             : }
      87             : 
      88        3215 : void CheckCondition::assignIf()
      89             : {
      90        3215 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("assignIf"))
      91        2320 :         return;
      92             : 
      93         895 :     logChecker("CheckCondition::assignIf"); // style
      94             : 
      95      286104 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
      96      285210 :         if (tok->str() != "=")
      97      282796 :             continue;
      98             : 
      99        2414 :         if (Token::Match(tok->tokAt(-2), "[;{}] %var% =")) {
     100        1684 :             const Variable *var = tok->previous()->variable();
     101        1684 :             if (var == nullptr)
     102           1 :                 continue;
     103             : 
     104        1683 :             char bitop = '\0';
     105        1683 :             MathLib::bigint num = 0;
     106             : 
     107        1683 :             if (Token::Match(tok->next(), "%num% [&|]")) {
     108           8 :                 bitop = tok->strAt(2).at(0);
     109           8 :                 num = MathLib::toBigNumber(tok->next()->str());
     110             :             } else {
     111        1675 :                 const Token *endToken = Token::findsimplematch(tok, ";");
     112             : 
     113             :                 // Casting address
     114        1675 :                 if (endToken && Token::Match(endToken->tokAt(-4), "* ) & %any% ;"))
     115           1 :                     endToken = nullptr;
     116             : 
     117        1675 :                 if (endToken && Token::Match(endToken->tokAt(-2), "[&|] %num% ;")) {
     118          27 :                     bitop = endToken->strAt(-2).at(0);
     119          27 :                     num = MathLib::toBigNumber(endToken->previous()->str());
     120             :                 }
     121             :             }
     122             : 
     123        1683 :             if (bitop == '\0')
     124        1648 :                 continue;
     125             : 
     126          35 :             if (num < 0 && bitop == '|')
     127           1 :                 continue;
     128             : 
     129          34 :             assignIfParseScope(tok, tok->tokAt(4), var->declarationId(), var->isLocal(), bitop, num);
     130             :         }
     131             :     }
     132             : }
     133             : 
     134          10 : static bool isParameterChanged(const Token *partok)
     135             : {
     136          10 :     bool addressOf = Token::Match(partok, "[(,] &");
     137          10 :     int argumentNumber = 0;
     138             :     const Token *ftok;
     139          14 :     for (ftok = partok; ftok && ftok->str() != "("; ftok = ftok->previous()) {
     140           4 :         if (ftok->str() == ")")
     141           0 :             ftok = ftok->link();
     142           4 :         else if (argumentNumber == 0U && ftok->str() == "&")
     143           0 :             addressOf = true;
     144           4 :         else if (ftok->str() == ",")
     145           0 :             argumentNumber++;
     146             :     }
     147          10 :     ftok = ftok ? ftok->previous() : nullptr;
     148          10 :     if (!(ftok && ftok->function()))
     149           6 :         return true;
     150           4 :     const Variable *par = ftok->function()->getArgumentVar(argumentNumber);
     151           4 :     if (!par)
     152           0 :         return true;
     153           4 :     if (par->isConst())
     154           0 :         return false;
     155           4 :     if (addressOf || par->isReference() || par->isPointer())
     156           1 :         return true;
     157           3 :     return false;
     158             : }
     159             : 
     160             : /** parse scopes recursively */
     161          55 : bool CheckCondition::assignIfParseScope(const Token * const assignTok,
     162             :                                         const Token * const startTok,
     163             :                                         const nonneg int varid,
     164             :                                         const bool islocal,
     165             :                                         const char bitop,
     166             :                                         const MathLib::bigint num)
     167             : {
     168          55 :     bool ret = false;
     169             : 
     170         245 :     for (const Token *tok2 = startTok; tok2; tok2 = tok2->next()) {
     171         245 :         if ((bitop == '&') && Token::Match(tok2->tokAt(2), "%varid% %cop% %num% ;", varid) && tok2->strAt(3) == std::string(1U, bitop)) {
     172           1 :             const MathLib::bigint num2 = MathLib::toBigNumber(tok2->strAt(4));
     173           1 :             if (0 == (num & num2))
     174           1 :                 mismatchingBitAndError(assignTok, num, tok2, num2);
     175             :         }
     176         244 :         if (Token::Match(tok2, "%varid% =", varid)) {
     177           2 :             return true;
     178             :         }
     179         242 :         if (bitop == '&' && Token::Match(tok2, "%varid% &= %num% ;", varid)) {
     180           1 :             const MathLib::bigint num2 = MathLib::toBigNumber(tok2->strAt(2));
     181           1 :             if (0 == (num & num2))
     182           1 :                 mismatchingBitAndError(assignTok, num, tok2, num2);
     183             :         }
     184         242 :         if (Token::Match(tok2, "++|-- %varid%", varid) || Token::Match(tok2, "%varid% ++|--", varid))
     185           2 :             return true;
     186         240 :         if (Token::Match(tok2, "[(,] &| %varid% [,)]", varid) && isParameterChanged(tok2))
     187           3 :             return true;
     188         237 :         if (tok2->str() == "}")
     189          38 :             return false;
     190         199 :         if (Token::Match(tok2, "break|continue|return"))
     191           4 :             ret = true;
     192         199 :         if (ret && tok2->str() == ";")
     193           4 :             return false;
     194         195 :         if (!islocal && Token::Match(tok2, "%name% (") && !Token::simpleMatch(tok2->next()->link(), ") {"))
     195           1 :             return true;
     196         194 :         if (Token::Match(tok2, "if|while (")) {
     197          26 :             if (!islocal && tok2->str() == "while")
     198           1 :                 continue;
     199          25 :             if (tok2->str() == "while") {
     200             :                 // is variable changed in loop?
     201           6 :                 const Token *bodyStart = tok2->linkAt(1)->next();
     202           6 :                 const Token *bodyEnd   = bodyStart ? bodyStart->link() : nullptr;
     203           6 :                 if (!bodyEnd || bodyEnd->str() != "}" || isVariableChanged(bodyStart, bodyEnd, varid, !islocal, *mSettings))
     204           2 :                     continue;
     205             :             }
     206             : 
     207             :             // parse condition
     208          23 :             const Token * const end = tok2->next()->link();
     209         152 :             for (; tok2 != end; tok2 = tok2->next()) {
     210         132 :                 if (Token::Match(tok2, "[(,] &| %varid% [,)]", varid)) {
     211           2 :                     return true;
     212             :                 }
     213         130 :                 if (Token::Match(tok2,"&&|%oror%|( %varid% ==|!= %num% &&|%oror%|)", varid)) {
     214          15 :                     const Token *vartok = tok2->next();
     215          15 :                     const MathLib::bigint num2 = MathLib::toBigNumber(vartok->strAt(2));
     216          15 :                     if ((num & num2) != ((bitop=='&') ? num2 : num)) {
     217          14 :                         const std::string& op(vartok->strAt(1));
     218          14 :                         const bool alwaysTrue = op == "!=";
     219          28 :                         const std::string condition(vartok->str() + op + vartok->strAt(2));
     220          14 :                         assignIfError(assignTok, tok2, condition, alwaysTrue);
     221             :                     }
     222             :                 }
     223         130 :                 if (Token::Match(tok2, "%varid% %op%", varid) && tok2->next()->isAssignmentOp()) {
     224           1 :                     return true;
     225             :                 }
     226             :             }
     227             : 
     228          20 :             const bool ret1 = assignIfParseScope(assignTok, end->tokAt(2), varid, islocal, bitop, num);
     229          20 :             bool ret2 = false;
     230          20 :             if (Token::simpleMatch(end->next()->link(), "} else {"))
     231           1 :                 ret2 = assignIfParseScope(assignTok, end->next()->link()->tokAt(3), varid, islocal, bitop, num);
     232          20 :             if (ret1 || ret2)
     233           1 :                 return true;
     234             :         }
     235             :     }
     236           1 :     return false;
     237             : }
     238             : 
     239          18 : void CheckCondition::assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result)
     240             : {
     241          18 :     if (tok2 && diag(tok2->tokAt(2)))
     242           1 :         return;
     243          34 :     std::list<const Token *> locations = { tok1, tok2 };
     244          17 :     reportError(locations,
     245             :                 Severity::style,
     246             :                 "assignIfError",
     247          34 :                 "Mismatching assignment and comparison, comparison '" + condition + "' is always " + std::string(bool_to_string(result)) + ".", CWE398, Certainty::normal);
     248             : }
     249             : 
     250             : 
     251           6 : void CheckCondition::mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2)
     252             : {
     253          12 :     std::list<const Token *> locations = { tok1, tok2 };
     254             : 
     255           6 :     std::ostringstream msg;
     256             :     msg << "Mismatching bitmasks. Result is always 0 ("
     257           6 :         << "X = Y & 0x" << std::hex << num1 << "; Z = X & 0x" << std::hex << num2 << "; => Z=0).";
     258             : 
     259           6 :     reportError(locations,
     260             :                 Severity::style,
     261             :                 "mismatchingBitAnd",
     262          12 :                 msg.str(), CWE398, Certainty::normal);
     263           6 : }
     264             : 
     265             : 
     266          29 : static void getnumchildren(const Token *tok, std::list<MathLib::bigint> &numchildren)
     267             : {
     268          29 :     if (tok->astOperand1() && tok->astOperand1()->isNumber())
     269           0 :         numchildren.push_back(MathLib::toBigNumber(tok->astOperand1()->str()));
     270          29 :     else if (tok->astOperand1() && tok->str() == tok->astOperand1()->str())
     271           2 :         getnumchildren(tok->astOperand1(), numchildren);
     272          29 :     if (tok->astOperand2() && tok->astOperand2()->isNumber())
     273          27 :         numchildren.push_back(MathLib::toBigNumber(tok->astOperand2()->str()));
     274           2 :     else if (tok->astOperand2() && tok->str() == tok->astOperand2()->str())
     275           0 :         getnumchildren(tok->astOperand2(), numchildren);
     276          29 : }
     277             : 
     278             : /* Return whether tok is in the body for a function returning a boolean. */
     279           7 : static bool inBooleanFunction(const Token *tok)
     280             : {
     281           7 :     const Scope *scope = tok ? tok->scope() : nullptr;
     282           8 :     while (scope && scope->isLocal())
     283           1 :         scope = scope->nestedIn;
     284           7 :     if (scope && scope->type == Scope::eFunction) {
     285           7 :         const Function *func = scope->function;
     286           7 :         if (func) {
     287           7 :             const Token *ret = func->retDef;
     288           9 :             while (Token::Match(ret, "static|const"))
     289           2 :                 ret = ret->next();
     290           7 :             return Token::Match(ret, "bool|_Bool");
     291             :         }
     292             :     }
     293           0 :     return false;
     294             : }
     295             : 
     296           6 : static bool isOperandExpanded(const Token *tok)
     297             : {
     298           6 :     if (tok->isExpandedMacro() || tok->isEnumerator())
     299           4 :         return true;
     300           2 :     if (tok->astOperand1() && isOperandExpanded(tok->astOperand1()))
     301           1 :         return true;
     302           1 :     if (tok->astOperand2() && isOperandExpanded(tok->astOperand2()))
     303           0 :         return true;
     304           1 :     return false;
     305             : }
     306             : 
     307        3215 : void CheckCondition::checkBadBitmaskCheck()
     308             : {
     309        3215 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("badBitmaskCheck"))
     310        2321 :         return;
     311             : 
     312         894 :     logChecker("CheckCondition::checkBadBitmaskCheck"); // style
     313             : 
     314      286104 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
     315      285210 :         if (tok->str() == "|" && tok->astOperand1() && tok->astOperand2() && tok->astParent()) {
     316         163 :             const Token* parent = tok->astParent();
     317         325 :             const bool isBoolean = Token::Match(parent, "&&|%oror%") ||
     318         324 :                                    (parent->str() == "?" && parent->astOperand1() == tok) ||
     319         338 :                                    (parent->str() == "=" && parent->astOperand2() == tok && parent->astOperand1() && parent->astOperand1()->variable() && Token::Match(parent->astOperand1()->variable()->typeStartToken(), "bool|_Bool")) ||
     320         497 :                                    (parent->str() == "(" && Token::Match(parent->astOperand1(), "if|while")) ||
     321         162 :                                    (parent->str() == "return" && parent->astOperand1() == tok && inBooleanFunction(tok));
     322             : 
     323         309 :             const bool isTrue = (tok->astOperand1()->hasKnownIntValue() && tok->astOperand1()->values().front().intvalue != 0) ||
     324         146 :                                 (tok->astOperand2()->hasKnownIntValue() && tok->astOperand2()->values().front().intvalue != 0);
     325             : 
     326         163 :             if (isBoolean && isTrue)
     327          10 :                 badBitmaskCheckError(tok);
     328             : 
     329             :             // If there are #ifdef in the expression don't warn about redundant | to avoid FP
     330         163 :             const auto& startStop = tok->findExpressionStartEndTokens();
     331         163 :             if (mTokenizer->hasIfdef(startStop.first, startStop.second))
     332         157 :                 continue;
     333             : 
     334         162 :             const bool isZero1 = (tok->astOperand1()->hasKnownIntValue() && tok->astOperand1()->values().front().intvalue == 0);
     335         162 :             const bool isZero2 = (tok->astOperand2()->hasKnownIntValue() && tok->astOperand2()->values().front().intvalue == 0);
     336         162 :             if (!isZero1 && !isZero2)
     337         156 :                 continue;
     338             : 
     339           6 :             if (!tok->isExpandedMacro() &&
     340           9 :                 !(isZero1 && isOperandExpanded(tok->astOperand1())) &&
     341           3 :                 !(isZero2 && isOperandExpanded(tok->astOperand2())))
     342           1 :                 badBitmaskCheckError(tok, /*isNoOp*/ true);
     343             :         }
     344             :     }
     345             : }
     346             : 
     347          15 : void CheckCondition::badBitmaskCheckError(const Token *tok, bool isNoOp)
     348             : {
     349          15 :     if (isNoOp)
     350           1 :         reportError(tok, Severity::style, "badBitmaskCheck", "Operator '|' with one operand equal to zero is redundant.", CWE571, Certainty::normal);
     351             :     else
     352          14 :         reportError(tok, Severity::warning, "badBitmaskCheck", "Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'?", CWE571, Certainty::normal);
     353          15 : }
     354             : 
     355        3215 : void CheckCondition::comparison()
     356             : {
     357        3215 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("comparisonError"))
     358        2321 :         return;
     359             : 
     360         894 :     logChecker("CheckCondition::comparison"); // style
     361             : 
     362      286104 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
     363      285210 :         if (!tok->isComparisonOp())
     364      285183 :             continue;
     365             : 
     366        1634 :         const Token *expr1 = tok->astOperand1();
     367        1634 :         const Token *expr2 = tok->astOperand2();
     368        1634 :         if (!expr1 || !expr2)
     369           2 :             continue;
     370        1632 :         if (expr1->isNumber())
     371          61 :             std::swap(expr1,expr2);
     372        1632 :         if (!expr2->isNumber())
     373         485 :             continue;
     374        1147 :         const MathLib::bigint num2 = MathLib::toBigNumber(expr2->str());
     375        1147 :         if (num2 < 0)
     376          72 :             continue;
     377        1075 :         if (!Token::Match(expr1,"[&|]"))
     378        1048 :             continue;
     379          54 :         std::list<MathLib::bigint> numbers;
     380          27 :         getnumchildren(expr1, numbers);
     381          54 :         for (const MathLib::bigint num1 : numbers) {
     382          27 :             if (num1 < 0)
     383           0 :                 continue;
     384          27 :             if (Token::Match(tok, "==|!=")) {
     385          20 :                 if ((expr1->str() == "&" && (num1 & num2) != num2) ||
     386           9 :                     (expr1->str() == "|" && (num1 | num2) != num2)) {
     387           7 :                     const std::string& op(tok->str());
     388           7 :                     comparisonError(expr1, expr1->str(), num1, op, num2, op != "==");
     389             :                 }
     390          16 :             } else if (expr1->str() == "&") {
     391           8 :                 const bool or_equal = Token::Match(tok, ">=|<=");
     392           8 :                 const std::string& op(tok->str());
     393           8 :                 if ((Token::Match(tok, ">=|<")) && (num1 < num2)) {
     394           2 :                     comparisonError(expr1, expr1->str(), num1, op, num2, !or_equal);
     395           6 :                 } else if ((Token::Match(tok, "<=|>")) && (num1 <= num2)) {
     396           2 :                     comparisonError(expr1, expr1->str(), num1, op, num2, or_equal);
     397             :                 }
     398           8 :             } else if (expr1->str() == "|") {
     399          16 :                 if ((expr1->astOperand1()->valueType()) &&
     400           8 :                     (expr1->astOperand1()->valueType()->sign == ValueType::Sign::UNSIGNED)) {
     401           4 :                     const bool or_equal = Token::Match(tok, ">=|<=");
     402           4 :                     const std::string& op(tok->str());
     403           4 :                     if ((Token::Match(tok, ">=|<")) && (num1 >= num2)) {
     404             :                         //"(a | 0x07) >= 7U" is always true for unsigned a
     405             :                         //"(a | 0x07) < 7U" is always false for unsigned a
     406           2 :                         comparisonError(expr1, expr1->str(), num1, op, num2, or_equal);
     407           2 :                     } else if ((Token::Match(tok, "<=|>")) && (num1 > num2)) {
     408             :                         //"(a | 0x08) <= 7U" is always false for unsigned a
     409             :                         //"(a | 0x07) > 6U" is always true for unsigned a
     410           2 :                         comparisonError(expr1, expr1->str(), num1, op, num2, !or_equal);
     411             :                     }
     412             :                 }
     413             :             }
     414             :         }
     415             :     }
     416             : }
     417             : 
     418          19 : void CheckCondition::comparisonError(const Token *tok, const std::string &bitop, MathLib::bigint value1, const std::string &op, MathLib::bigint value2, bool result)
     419             : {
     420          38 :     std::ostringstream expression;
     421          19 :     expression << std::hex << "(X " << bitop << " 0x" << value1 << ") " << op << " 0x" << value2;
     422             : 
     423          38 :     const std::string errmsg("Expression '" + expression.str() + "' is always " + bool_to_string(result) + ".\n"
     424          57 :                              "The expression '" + expression.str() + "' is always " + bool_to_string(result) +
     425             :                              ". Check carefully constants and operators used, these errors might be hard to "
     426             :                              "spot sometimes. In case of complex expression it might help to split it to "
     427          38 :                              "separate expressions.");
     428             : 
     429          19 :     reportError(tok, Severity::style, "comparisonError", errmsg, CWE398, Certainty::normal);
     430          19 : }
     431             : 
     432          66 : bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const
     433             : {
     434          66 :     if (!cond1 || !cond2)
     435           0 :         return false;
     436             : 
     437             :     // same expressions
     438          66 :     if (isSameExpression(true, cond1, cond2, *mSettings, pure, false))
     439          14 :         return true;
     440             : 
     441             :     // bitwise overlap for example 'x&7' and 'x==1'
     442          52 :     if (cond1->str() == "&" && cond1->astOperand1() && cond2->astOperand2()) {
     443           8 :         const Token *expr1 = cond1->astOperand1();
     444           8 :         const Token *num1  = cond1->astOperand2();
     445           8 :         if (!num1) // unary operator&
     446           1 :             return false;
     447           7 :         if (!num1->isNumber())
     448           1 :             std::swap(expr1,num1);
     449           7 :         if (!num1->isNumber() || MathLib::isNegative(num1->str()))
     450           1 :             return false;
     451             : 
     452           6 :         if (!Token::Match(cond2, "&|==") || !cond2->astOperand1() || !cond2->astOperand2())
     453           0 :             return false;
     454           6 :         const Token *expr2 = cond2->astOperand1();
     455           6 :         const Token *num2  = cond2->astOperand2();
     456           6 :         if (!num2->isNumber())
     457           0 :             std::swap(expr2,num2);
     458           6 :         if (!num2->isNumber() || MathLib::isNegative(num2->str()))
     459           0 :             return false;
     460             : 
     461           6 :         if (!isSameExpression(true, expr1, expr2, *mSettings, pure, false))
     462           0 :             return false;
     463             : 
     464           6 :         const MathLib::bigint value1 = MathLib::toBigNumber(num1->str());
     465           6 :         const MathLib::bigint value2 = MathLib::toBigNumber(num2->str());
     466           6 :         if (cond2->str() == "&")
     467           3 :             return ((value1 & value2) == value2);
     468           3 :         return ((value1 & value2) > 0);
     469             :     }
     470          44 :     return false;
     471             : }
     472             : 
     473        3215 : void CheckCondition::duplicateCondition()
     474             : {
     475        3215 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateCondition"))
     476        2321 :         return;
     477             : 
     478         894 :     logChecker("CheckCondition::duplicateCondition"); // style
     479             : 
     480         894 :     const SymbolDatabase *const symbolDatabase = mTokenizer->getSymbolDatabase();
     481             : 
     482       10198 :     for (const Scope &scope : symbolDatabase->scopeList) {
     483        9304 :         if (scope.type != Scope::eIf)
     484        9196 :             continue;
     485             : 
     486        1389 :         const Token* tok2 = scope.classDef->next();
     487        1389 :         if (!tok2)
     488           0 :             continue;
     489        1389 :         const Token* cond1 = tok2->astOperand2();
     490        1389 :         if (!cond1)
     491           0 :             continue;
     492        1389 :         if (cond1->hasKnownIntValue())
     493         368 :             continue;
     494             : 
     495        1021 :         tok2 = tok2->link();
     496        1021 :         if (!Token::simpleMatch(tok2, ") {"))
     497           0 :             continue;
     498        1021 :         tok2 = tok2->linkAt(1);
     499        1021 :         if (!Token::simpleMatch(tok2, "} if ("))
     500         913 :             continue;
     501         108 :         const Token *cond2 = tok2->tokAt(2)->astOperand2();
     502         108 :         if (!cond2)
     503           0 :             continue;
     504             : 
     505         216 :         ErrorPath errorPath;
     506         191 :         if (!findExpressionChanged(cond1, scope.classDef->next(), cond2, *mSettings) &&
     507          83 :             isSameExpression(true, cond1, cond2, *mSettings, true, true, &errorPath))
     508           8 :             duplicateConditionError(cond1, cond2, std::move(errorPath));
     509             :     }
     510             : }
     511             : 
     512          12 : void CheckCondition::duplicateConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath)
     513             : {
     514          12 :     if (diag(tok1) & diag(tok2))
     515           3 :         return;
     516           9 :     errorPath.emplace_back(tok1, "First condition");
     517           9 :     errorPath.emplace_back(tok2, "Second condition");
     518             : 
     519          18 :     std::string msg = "The if condition is the same as the previous if condition";
     520             : 
     521           9 :     reportError(errorPath, Severity::style, "duplicateCondition", msg, CWE398, Certainty::normal);
     522             : }
     523             : 
     524        3215 : void CheckCondition::multiCondition()
     525             : {
     526        3215 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("multiCondition"))
     527        2321 :         return;
     528             : 
     529         894 :     logChecker("CheckCondition::multiCondition"); // style
     530             : 
     531         894 :     const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
     532             : 
     533       10198 :     for (const Scope &scope : symbolDatabase->scopeList) {
     534        9304 :         if (scope.type != Scope::eIf)
     535        7915 :             continue;
     536             : 
     537        1389 :         const Token * const cond1 = scope.classDef->next()->astOperand2();
     538        1389 :         if (!cond1)
     539           0 :             continue;
     540             : 
     541        1389 :         const Token * tok2 = scope.classDef->next();
     542             : 
     543             :         // Check each 'else if'
     544             :         for (;;) {
     545        1455 :             tok2 = tok2->link();
     546        1455 :             if (!Token::simpleMatch(tok2, ") {"))
     547           2 :                 break;
     548        1453 :             tok2 = tok2->linkAt(1);
     549        1453 :             if (!Token::simpleMatch(tok2, "} else { if ("))
     550        1387 :                 break;
     551          66 :             tok2 = tok2->tokAt(4);
     552             : 
     553          66 :             if (tok2->astOperand2()) {
     554         132 :                 ErrorPath errorPath;
     555          84 :                 if (isOverlappingCond(cond1, tok2->astOperand2(), true) &&
     556          18 :                     !findExpressionChanged(cond1, cond1, tok2->astOperand2(), *mSettings))
     557          17 :                     overlappingElseIfConditionError(tok2->astOperand2(), cond1->linenr());
     558          49 :                 else if (isOppositeCond(
     559         101 :                              true, cond1, tok2->astOperand2(), *mSettings, true, true, &errorPath) &&
     560           3 :                          !findExpressionChanged(cond1, cond1, tok2->astOperand2(), *mSettings))
     561           2 :                     oppositeElseIfConditionError(cond1, tok2->astOperand2(), std::move(errorPath));
     562             :             }
     563          66 :         }
     564             :     }
     565             : }
     566             : 
     567          21 : void CheckCondition::overlappingElseIfConditionError(const Token *tok, nonneg int line1)
     568             : {
     569          21 :     if (diag(tok))
     570           0 :         return;
     571          21 :     std::ostringstream errmsg;
     572          21 :     errmsg << "Expression is always false because 'else if' condition matches previous condition at line "
     573          21 :            << line1 << ".";
     574             : 
     575          21 :     reportError(tok, Severity::style, "multiCondition", errmsg.str(), CWE398, Certainty::normal);
     576             : }
     577             : 
     578           2 : void CheckCondition::oppositeElseIfConditionError(const Token *ifCond, const Token *elseIfCond, ErrorPath errorPath)
     579             : {
     580           2 :     if (diag(ifCond) & diag(elseIfCond))
     581           0 :         return;
     582           2 :     std::ostringstream errmsg;
     583           2 :     errmsg << "Expression is always true because 'else if' condition is opposite to previous condition at line "
     584           2 :            << ifCond->linenr() << ".";
     585             : 
     586           2 :     errorPath.emplace_back(ifCond, "first condition");
     587           2 :     errorPath.emplace_back(elseIfCond, "else if condition is opposite to first condition");
     588             : 
     589           2 :     reportError(errorPath, Severity::style, "multiCondition", errmsg.str(), CWE398, Certainty::normal);
     590             : }
     591             : 
     592             : //---------------------------------------------------------------------------
     593             : // - Opposite inner conditions => always false
     594             : // - (TODO) Same/Overlapping inner condition => always true
     595             : // - same condition after early exit => always false
     596             : //---------------------------------------------------------------------------
     597             : 
     598         613 : static bool isNonConstFunctionCall(const Token *ftok, const Library &library)
     599             : {
     600         613 :     if (library.isFunctionConst(ftok))
     601         122 :         return false;
     602         491 :     const Token *obj = ftok->next()->astOperand1();
     603         569 :     while (obj && obj->str() == ".")
     604          78 :         obj = obj->astOperand1();
     605         491 :     if (!obj)
     606           0 :         return true;
     607         491 :     if (obj->variable() && obj->variable()->isConst())
     608          15 :         return false;
     609         476 :     if (ftok->function() && ftok->function()->isConst())
     610           0 :         return false;
     611         476 :     return true;
     612             : }
     613             : 
     614        3215 : void CheckCondition::multiCondition2()
     615             : {
     616        3215 :     if (!mSettings->severity.isEnabled(Severity::warning))
     617        2336 :         return;
     618             : 
     619         879 :     logChecker("CheckCondition::multiCondition2"); // warning
     620             : 
     621         879 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     622             : 
     623       10119 :     for (const Scope &scope : symbolDatabase->scopeList) {
     624        9240 :         const Token *condTok = nullptr;
     625        9240 :         if (scope.type == Scope::eIf || scope.type == Scope::eWhile)
     626        1385 :             condTok = scope.classDef->next()->astOperand2();
     627        7855 :         else if (scope.type == Scope::eFor) {
     628         104 :             condTok = scope.classDef->next()->astOperand2();
     629         104 :             if (!condTok || condTok->str() != ";")
     630        8154 :                 continue;
     631          98 :             condTok = condTok->astOperand2();
     632          98 :             if (!condTok || condTok->str() != ";")
     633           0 :                 continue;
     634          98 :             condTok = condTok->astOperand1();
     635             :         }
     636        9234 :         if (!condTok)
     637        7754 :             continue;
     638        1480 :         const Token * const cond1 = condTok;
     639             : 
     640        1480 :         if (!Token::simpleMatch(scope.classDef->linkAt(1), ") {"))
     641           0 :             continue;
     642             : 
     643        1480 :         bool functionCall = false;
     644        1480 :         bool nonConstFunctionCall = false;
     645        1480 :         bool nonlocal = false; // nonlocal variable used in condition
     646        1480 :         std::set<int> vars; // variables used in condition
     647        1480 :         visitAstNodes(condTok,
     648        5879 :                       [&](const Token *cond) {
     649        5879 :             if (Token::Match(cond, "%name% (")) {
     650         528 :                 functionCall = true;
     651         528 :                 nonConstFunctionCall = isNonConstFunctionCall(cond, mSettings->library);
     652         528 :                 if (nonConstFunctionCall)
     653         394 :                     return ChildrenToVisit::done;
     654             :             }
     655             : 
     656        5485 :             if (cond->varId()) {
     657        1526 :                 vars.insert(cond->varId());
     658        1526 :                 const Variable *var = cond->variable();
     659        1526 :                 if (!nonlocal && var) {
     660        1432 :                     if (!(var->isLocal() || var->isArgument()))
     661          76 :                         nonlocal = true;
     662        1356 :                     else if ((var->isPointer() || var->isReference()) && !Token::Match(cond->astParent(), "%oror%|&&|!"))
     663             :                         // TODO: if var is pointer check what it points at
     664         217 :                         nonlocal = true;
     665             :                 }
     666        3959 :             } else if (!nonlocal && cond->isName()) {
     667             :                 // varid is 0. this is possibly a nonlocal variable..
     668         286 :                 nonlocal = Token::Match(cond->astParent(), "%cop%|(|[") || Token::Match(cond, "%name% .") || (cond->isCpp() && cond->str() == "this");
     669             :             } else {
     670        3673 :                 return ChildrenToVisit::op1_and_op2;
     671             :             }
     672        1812 :             return ChildrenToVisit::none;
     673             :         });
     674             : 
     675        1480 :         if (nonConstFunctionCall)
     676         394 :             continue;
     677             : 
     678        2172 :         std::vector<const Variable*> varsInCond;
     679        1086 :         visitAstNodes(condTok,
     680        9515 :                       [&varsInCond](const Token *cond) {
     681        4175 :             if (cond->variable()) {
     682        1373 :                 const Variable *var = cond->variable();
     683        1373 :                 if (std::find(varsInCond.cbegin(), varsInCond.cend(), var) == varsInCond.cend())
     684        1221 :                     varsInCond.push_back(var);
     685             :             }
     686        4175 :             return ChildrenToVisit::op1_and_op2;
     687             :         });
     688             : 
     689             :         // parse until second condition is reached..
     690             :         enum MULTICONDITIONTYPE { INNER, AFTER };
     691             :         const Token *tok;
     692             : 
     693             :         // Parse inner condition first and then early return condition
     694        2172 :         std::vector<MULTICONDITIONTYPE> types = {MULTICONDITIONTYPE::INNER};
     695        1086 :         if (Token::Match(scope.bodyStart, "{ return|throw|continue|break"))
     696         189 :             types.push_back(MULTICONDITIONTYPE::AFTER);
     697        2361 :         for (const MULTICONDITIONTYPE type:types) {
     698        1275 :             if (type == MULTICONDITIONTYPE::AFTER) {
     699         189 :                 tok = scope.bodyEnd->next();
     700             :             } else {
     701        1086 :                 tok = scope.bodyStart;
     702             :             }
     703        1275 :             const Token * const endToken = tok->scope()->bodyEnd;
     704             : 
     705        4651 :             for (; tok && tok != endToken; tok = tok->next()) {
     706        3855 :                 if (isExpressionChangedAt(cond1, tok, 0, false, *mSettings))
     707          26 :                     break;
     708        3829 :                 if (Token::Match(tok, "if|return")) {
     709         390 :                     const Token * condStartToken = tok->str() == "if" ? tok->next() : tok;
     710         390 :                     const Token * condEndToken = tok->str() == "if" ? condStartToken->link() : Token::findsimplematch(condStartToken, ";");
     711             :                     // Does condition modify tracked variables?
     712         390 :                     if (findExpressionChanged(cond1, condStartToken, condEndToken, *mSettings))
     713           5 :                         break;
     714             : 
     715             :                     // Condition..
     716         385 :                     const Token *cond2 = tok->str() == "if" ? condStartToken->astOperand2() : condStartToken->astOperand1();
     717         385 :                     const bool isReturnVar = (tok->str() == "return" && !Token::Match(cond2, "%cop%"));
     718             : 
     719         770 :                     ErrorPath errorPath;
     720             : 
     721         385 :                     if (type == MULTICONDITIONTYPE::INNER) {
     722         297 :                         visitAstNodes(cond1, [&](const Token* firstCondition) {
     723         343 :                             if (!firstCondition)
     724           0 :                                 return ChildrenToVisit::none;
     725         343 :                             if (firstCondition->str() == "&&") {
     726          24 :                                 if (!isOppositeCond(false, firstCondition, cond2, *mSettings, true, true))
     727          23 :                                     return ChildrenToVisit::op1_and_op2;
     728             :                             }
     729         320 :                             if (!firstCondition->hasKnownIntValue()) {
     730         292 :                                 if (!isReturnVar && isOppositeCond(false, firstCondition, cond2, *mSettings, true, true, &errorPath)) {
     731          40 :                                     if (!isAliased(vars))
     732          40 :                                         oppositeInnerConditionError(firstCondition, cond2, errorPath);
     733         252 :                                 } else if (!isReturnVar && isSameExpression(true, firstCondition, cond2, *mSettings, true, true, &errorPath)) {
     734           4 :                                     identicalInnerConditionError(firstCondition, cond2, errorPath);
     735             :                                 }
     736             :                             }
     737         320 :                             return ChildrenToVisit::none;
     738             :                         });
     739             :                     } else {
     740          88 :                         visitAstNodes(cond2, [&](const Token *secondCondition) {
     741          92 :                             if (secondCondition->str() == "||" || secondCondition->str() == "&&")
     742           5 :                                 return ChildrenToVisit::op1_and_op2;
     743             : 
     744         164 :                             if ((!cond1->hasKnownIntValue() || !secondCondition->hasKnownIntValue()) &&
     745          77 :                                 isSameExpression(true, cond1, secondCondition, *mSettings, true, true, &errorPath)) {
     746          11 :                                 if (!isAliased(vars) && !mTokenizer->hasIfdef(cond1, secondCondition)) {
     747          10 :                                     identicalConditionAfterEarlyExitError(cond1, secondCondition, errorPath);
     748          10 :                                     return ChildrenToVisit::done;
     749             :                                 }
     750             :                             }
     751          77 :                             return ChildrenToVisit::none;
     752             :                         });
     753             :                     }
     754             :                 }
     755        4151 :                 if (Token::Match(tok, "%name% (") &&
     756         327 :                     isVariablesChanged(tok, tok->linkAt(1), 0, varsInCond, *mSettings)) {
     757          38 :                     break;
     758             :                 }
     759        3786 :                 if (Token::Match(tok, "%type% (") && nonlocal && isNonConstFunctionCall(tok, mSettings->library)) // non const function call -> bailout if there are nonlocal variables
     760          82 :                     break;
     761        3704 :                 if (Token::Match(tok, "case|break|continue|return|throw") && tok->scope() == endToken->scope())
     762         228 :                     break;
     763        3476 :                 if (Token::Match(tok, "[;{}] %name% :"))
     764           0 :                     break;
     765             :                 // bailout if loop is seen.
     766             :                 // TODO: handle loops better.
     767        3476 :                 if (Token::Match(tok, "for|while|do")) {
     768          13 :                     const Token *tok1 = tok->next();
     769             :                     const Token *tok2;
     770          13 :                     if (Token::simpleMatch(tok, "do {")) {
     771           1 :                         if (!Token::simpleMatch(tok->linkAt(1), "} while ("))
     772           8 :                             break;
     773           1 :                         tok2 = tok->linkAt(1)->linkAt(2);
     774          12 :                     } else if (Token::Match(tok, "if|while (")) {
     775           7 :                         tok2 = tok->linkAt(1);
     776           7 :                         if (Token::simpleMatch(tok2, ") {"))
     777           7 :                             tok2 = tok2->linkAt(1);
     778           7 :                         if (!tok2)
     779           0 :                             break;
     780             :                     } else {
     781             :                         // Incomplete code
     782           5 :                         break;
     783             :                     }
     784           8 :                     const bool changed = std::any_of(vars.cbegin(), vars.cend(), [&](int varid) {
     785           8 :                         return isVariableChanged(tok1, tok2, varid, nonlocal, *mSettings);
     786             :                     });
     787           8 :                     if (changed)
     788           3 :                         break;
     789             :                 }
     790        7111 :                 if ((tok->varId() && vars.find(tok->varId()) != vars.end()) ||
     791        7219 :                     (!tok->varId() && nonlocal) ||
     792         108 :                     (functionCall && tok->variable() && !tok->variable()->isLocal())) {
     793         778 :                     if (Token::Match(tok, "%name% %assign%|++|--"))
     794          54 :                         break;
     795         724 :                     if (Token::Match(tok->astParent(), "*|.|[")) {
     796          51 :                         const Token *parent = tok;
     797         151 :                         while (Token::Match(parent->astParent(), ".|[") || (parent->astParent() && parent->astParent()->isUnaryOp("*")))
     798          49 :                             parent = parent->astParent();
     799          51 :                         if (Token::Match(parent->astParent(), "%assign%|++|--"))
     800          25 :                             break;
     801             :                     }
     802         699 :                     if (tok->isCpp() && Token::Match(tok, "%name% <<") && (!tok->valueType() || !tok->valueType()->isIntegral()))
     803           1 :                         break;
     804         698 :                     if (isLikelyStreamRead(tok->next()) || isLikelyStreamRead(tok->previous()))
     805           1 :                         break;
     806         697 :                     if (Token::Match(tok, "%name% [")) {
     807           1 :                         const Token *tok2 = tok->linkAt(1);
     808           1 :                         while (Token::simpleMatch(tok2, "] ["))
     809           0 :                             tok2 = tok2->linkAt(1);
     810           1 :                         if (Token::Match(tok2, "] %assign%|++|--"))
     811           0 :                             break;
     812             :                     }
     813         697 :                     if (Token::Match(tok->previous(), "++|--|& %name%"))
     814           3 :                         break;
     815         694 :                     if (tok->variable() &&
     816         829 :                         !tok->variable()->isConst() &&
     817         135 :                         Token::Match(tok, "%name% . %name% (")) {
     818           6 :                         const Function* function = tok->tokAt(2)->function();
     819           6 :                         if (!function || !function->isConst())
     820           4 :                             break;
     821             :                     }
     822         690 :                     if (Token::Match(tok->previous(), "[(,] *|& %name% [,)]") && isParameterChanged(tok))
     823           4 :                         break;
     824             :                 }
     825             :             }
     826             :         }
     827             :     }
     828             : }
     829             : 
     830          52 : static std::string innerSmtString(const Token * tok)
     831             : {
     832          52 :     if (!tok)
     833           8 :         return "if";
     834          44 :     if (!tok->astTop())
     835           0 :         return "if";
     836          44 :     const Token * top = tok->astTop();
     837          44 :     if (top->str() == "(" && top->astOperand1())
     838          42 :         return top->astOperand1()->str();
     839           2 :     return top->str();
     840             : }
     841             : 
     842          44 : void CheckCondition::oppositeInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath)
     843             : {
     844          44 :     if (diag(tok1) & diag(tok2))
     845           0 :         return;
     846          88 :     const std::string s1(tok1 ? tok1->expressionString() : "x");
     847          88 :     const std::string s2(tok2 ? tok2->expressionString() : "!x");
     848          88 :     const std::string innerSmt = innerSmtString(tok2);
     849          44 :     errorPath.emplace_back(tok1, "outer condition: " + s1);
     850          44 :     errorPath.emplace_back(tok2, "opposite inner condition: " + s2);
     851             : 
     852          88 :     const std::string msg("Opposite inner '" + innerSmt + "' condition leads to a dead code block.\n"
     853         132 :                           "Opposite inner '" + innerSmt + "' condition leads to a dead code block (outer condition is '" + s1 + "' and inner condition is '" + s2 + "').");
     854          44 :     reportError(errorPath, Severity::warning, "oppositeInnerCondition", msg, CWE398, Certainty::normal);
     855             : }
     856             : 
     857           8 : void CheckCondition::identicalInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath)
     858             : {
     859           8 :     if (diag(tok1) & diag(tok2))
     860           0 :         return;
     861          16 :     const std::string s1(tok1 ? tok1->expressionString() : "x");
     862          16 :     const std::string s2(tok2 ? tok2->expressionString() : "x");
     863          16 :     const std::string innerSmt = innerSmtString(tok2);
     864           8 :     errorPath.emplace_back(tok1, "outer condition: " + s1);
     865           8 :     errorPath.emplace_back(tok2, "identical inner condition: " + s2);
     866             : 
     867          16 :     const std::string msg("Identical inner '" + innerSmt + "' condition is always true.\n"
     868          24 :                           "Identical inner '" + innerSmt + "' condition is always true (outer condition is '" + s1 + "' and inner condition is '" + s2 + "').");
     869           8 :     reportError(errorPath, Severity::warning, "identicalInnerCondition", msg, CWE398, Certainty::normal);
     870             : }
     871             : 
     872          14 : void CheckCondition::identicalConditionAfterEarlyExitError(const Token *cond1, const Token* cond2, ErrorPath errorPath)
     873             : {
     874          14 :     if (diag(cond1) & diag(cond2))
     875           0 :         return;
     876             : 
     877          14 :     const bool isReturnValue = cond2 && Token::simpleMatch(cond2->astParent(), "return");
     878             : 
     879          28 :     const std::string cond(cond1 ? cond1->expressionString() : "x");
     880          14 :     const std::string value = (cond2 && cond2->valueType() && cond2->valueType()->type == ValueType::Type::BOOL) ? "false" : "0";
     881             : 
     882          14 :     errorPath.emplace_back(cond1, "If condition '" + cond + "' is true, the function will return/exit");
     883          14 :     errorPath.emplace_back(cond2, (isReturnValue ? "Returning identical expression '" : "Testing identical condition '") + cond + "'");
     884             : 
     885          14 :     reportError(errorPath,
     886             :                 Severity::warning,
     887             :                 "identicalConditionAfterEarlyExit",
     888             :                 isReturnValue
     889          55 :                 ? ("Identical condition and return expression '" + cond + "', return value is always " + value)
     890          27 :                 : ("Identical condition '" + cond + "', second condition is always false"),
     891             :                 CWE398,
     892             :                 Certainty::normal);
     893             : }
     894             : 
     895             : //---------------------------------------------------------------------------
     896             : //    if ((x != 1) || (x != 3))            // expression always true
     897             : //    if ((x == 1) && (x == 3))            // expression always false
     898             : //    if ((x < 1)  && (x > 3))             // expression always false
     899             : //    if ((x > 3)  || (x < 10))            // expression always true
     900             : //    if ((x > 5)  && (x != 1))            // second comparison always true
     901             : //
     902             : //    Check for suspect logic for an expression consisting of 2 comparison
     903             : //    expressions with a shared variable and constants and a logical operator
     904             : //    between them.
     905             : //
     906             : //    Suggest a different logical operator when the logical operator between
     907             : //    the comparisons is probably wrong.
     908             : //
     909             : //    Inform that second comparison is always true when first comparison is true.
     910             : //---------------------------------------------------------------------------
     911             : 
     912          30 : static std::string invertOperatorForOperandSwap(std::string s)
     913             : {
     914          30 :     if (s[0] == '<')
     915          15 :         s[0] = '>';
     916          15 :     else if (s[0] == '>')
     917          12 :         s[0] = '<';
     918          30 :     return s;
     919             : }
     920             : 
     921             : template<typename T>
     922           8 : static int sign(const T v) {
     923           8 :     return static_cast<int>(v > 0) - static_cast<int>(v < 0);
     924             : }
     925             : 
     926             : // returns 1 (-1) if the first (second) condition is sufficient, 0 if indeterminate
     927             : template<typename T>
     928          24 : static int sufficientCondition(std::string op1, const bool not1, const T value1, std::string op2, const bool not2, const T value2, const bool isAnd) {
     929          96 :     auto transformOp = [](std::string& op, const bool invert) {
     930          48 :         if (invert) {
     931           1 :             if (op == "==")
     932           0 :                 op = "!=";
     933           1 :             else if (op == "!=")
     934           1 :                 op = "==";
     935           0 :             else if (op == "<")
     936           0 :                 op = ">=";
     937           0 :             else if (op == ">")
     938           0 :                 op = "<=";
     939           0 :             else if (op == "<=")
     940           0 :                 op = ">";
     941           0 :             else if (op == ">=")
     942           0 :                 op = "<";
     943             :         }
     944             :     };
     945          24 :     transformOp(op1, not1);
     946          24 :     transformOp(op2, not2);
     947          24 :     int res = 0;
     948          24 :     bool equal = false;
     949          24 :     if (op1 == op2) {
     950           8 :         equal = true;
     951           8 :         if (op1 == ">" || op1 == ">=")
     952           4 :             res = sign(value1 - value2);
     953           4 :         else if (op1 == "<" || op1 == "<=")
     954           4 :             res = -sign(value1 - value2);
     955             :     } else { // not equal
     956          16 :         if (op1 == "!=")
     957           2 :             res = 1;
     958          14 :         else if (op2 == "!=")
     959           9 :             res = -1;
     960           5 :         else if (op1 == "==")
     961           0 :             res = -1;
     962           5 :         else if (op2 == "==")
     963           5 :             res = 1;
     964           0 :         else if (op1 == ">" && op2 == ">=")
     965           0 :             res = sign(value1 - (value2 - 1));
     966           0 :         else if (op1 == ">=" && op2 == ">")
     967           0 :             res = sign((value1 - 1) - value2);
     968           0 :         else if (op1 == "<" && op2 == "<=")
     969           0 :             res = -sign(value1 - (value2 + 1));
     970           0 :         else if (op1 == "<=" && op2 == "<")
     971           0 :             res = -sign((value1 + 1) - value2);
     972             :     }
     973          24 :     return res * (isAnd == equal ? 1 : -1);
     974             : }
     975             : 
     976             : template<typename T>
     977         600 : static bool checkIntRelation(const std::string &op, const T value1, const T value2)
     978             : {
     979        1323 :     return (op == "==" && value1 == value2) ||
     980        1159 :            (op == "!=" && value1 != value2) ||
     981         944 :            (op == ">" && value1 >  value2) ||
     982         798 :            (op == ">=" && value1 >= value2) ||
     983        1657 :            (op == "<" && value1 <  value2) ||
     984         967 :            (op == "<=" && value1 <= value2);
     985             : }
     986             : 
     987         130 : static bool checkFloatRelation(const std::string &op, const double value1, const double value2)
     988             : {
     989         288 :     return (op == ">" && value1 >  value2) ||
     990         230 :            (op == ">=" && value1 >= value2) ||
     991         405 :            (op == "<" && value1 <  value2) ||
     992         230 :            (op == "<=" && value1 <= value2);
     993             : }
     994             : 
     995             : template<class T>
     996          60 : static T getvalue3(const T value1, const T value2)
     997             : {
     998          60 :     const T min = std::min(value1, value2);
     999          60 :     if (min== std::numeric_limits<T>::max())
    1000           0 :         return min;
    1001          60 :     return min + 1; // see #5895
    1002             : }
    1003             : 
    1004             : template<>
    1005          13 : double getvalue3(const double value1, const double value2)
    1006             : {
    1007          13 :     return (value1 + value2) / 2.0;
    1008             : }
    1009             : 
    1010             : 
    1011             : template<class T>
    1012         365 : static inline T getvalue(const int test, const T value1, const T value2)
    1013             : {
    1014             :     // test:
    1015             :     // 1 => return value that is less than both value1 and value2
    1016             :     // 2 => return value1
    1017             :     // 3 => return value that is between value1 and value2
    1018             :     // 4 => return value2
    1019             :     // 5 => return value that is larger than both value1 and value2
    1020         365 :     switch (test) {
    1021          73 :     case 1:
    1022          73 :         return std::numeric_limits<T>::lowest();
    1023          73 :     case 2:
    1024          73 :         return value1;
    1025          73 :     case 3:
    1026          73 :         return getvalue3<T>(value1, value2);
    1027          73 :     case 4:
    1028          73 :         return value2;
    1029          73 :     case 5:
    1030          73 :         return std::numeric_limits<T>::max();
    1031             :     }
    1032           0 :     return 0;
    1033             : }
    1034             : 
    1035         700 : static bool parseComparison(const Token *comp, bool &not1, std::string &op, std::string &value, const Token *&expr, bool &inconclusive)
    1036             : {
    1037         700 :     not1 = false;
    1038         755 :     while (comp && comp->str() == "!") {
    1039          55 :         not1 = !(not1);
    1040          55 :         comp = comp->astOperand1();
    1041             :     }
    1042             : 
    1043         700 :     if (!comp)
    1044           0 :         return false;
    1045             : 
    1046         700 :     const Token* op1 = comp->astOperand1();
    1047         700 :     const Token* op2 = comp->astOperand2();
    1048         700 :     if (!comp->isComparisonOp() || !op1 || !op2) {
    1049         219 :         op = "!=";
    1050         219 :         value = "0";
    1051         219 :         expr = comp;
    1052         481 :     } else if (op1->isLiteral()) {
    1053          30 :         if (op1->isExpandedMacro())
    1054           0 :             return false;
    1055          30 :         op = invertOperatorForOperandSwap(comp->str());
    1056          30 :         if (op1->enumerator() && op1->enumerator()->value_known)
    1057           0 :             value = std::to_string(op1->enumerator()->value);
    1058             :         else
    1059          30 :             value = op1->str();
    1060          30 :         expr = op2;
    1061         451 :     } else if (comp->astOperand2()->isLiteral()) {
    1062         367 :         if (op2->isExpandedMacro())
    1063           1 :             return false;
    1064         366 :         op = comp->str();
    1065         366 :         if (op2->enumerator() && op2->enumerator()->value_known)
    1066           5 :             value = std::to_string(op2->enumerator()->value);
    1067             :         else
    1068         361 :             value = op2->str();
    1069         366 :         expr = op1;
    1070             :     } else {
    1071          84 :         op = "!=";
    1072          84 :         value = "0";
    1073          84 :         expr = comp;
    1074             :     }
    1075             : 
    1076         699 :     inconclusive = inconclusive || ((value)[0] == '\'' && !(op == "!=" || op == "=="));
    1077             : 
    1078             :     // Only float and int values are currently handled
    1079         699 :     return MathLib::isInt(value) || MathLib::isFloat(value) || (value[0] == '\'');
    1080             : }
    1081             : 
    1082         196 : static std::string conditionString(bool not1, const Token *expr1, const std::string &op, const std::string &value1)
    1083             : {
    1084         196 :     if (expr1->astParent()->isComparisonOp())
    1085         380 :         return std::string(not1 ? "!(" : "") + expr1->expressionString() +
    1086         380 :                " " +
    1087         380 :                op +
    1088         380 :                " " +
    1089         190 :                value1 +
    1090         380 :                (not1 ? ")" : "");
    1091             : 
    1092          12 :     return std::string(not1 ? "!" : "") + expr1->expressionString();
    1093             : }
    1094             : 
    1095         144 : static std::string conditionString(const Token * tok)
    1096             : {
    1097         144 :     if (!tok)
    1098           0 :         return "";
    1099         144 :     if (tok->isComparisonOp()) {
    1100          68 :         bool inconclusive = false;
    1101             :         bool not_;
    1102          68 :         std::string op, value;
    1103             :         const Token *expr;
    1104          68 :         if (parseComparison(tok, not_, op, value, expr, inconclusive) && expr->isName()) {
    1105          50 :             return conditionString(not_, expr, op, value);
    1106             :         }
    1107             :     }
    1108          94 :     if (Token::Match(tok, "%cop%|&&|%oror%")) {
    1109          56 :         if (tok->astOperand2())
    1110         106 :             return conditionString(tok->astOperand1()) + " " + tok->str() + " " + conditionString(tok->astOperand2());
    1111           6 :         return tok->str() + "(" + conditionString(tok->astOperand1()) + ")";
    1112             : 
    1113             :     }
    1114          38 :     return tok->expressionString();
    1115             : }
    1116             : 
    1117          36 : static bool isIfConstexpr(const Token* tok) {
    1118          36 :     const Token* const top = tok->astTop();
    1119          36 :     return top && Token::simpleMatch(top->astOperand1(), "if") && top->astOperand1()->isConstexpr();
    1120             : }
    1121             : 
    1122        3215 : void CheckCondition::checkIncorrectLogicOperator()
    1123             : {
    1124        3215 :     const bool printStyle = mSettings->severity.isEnabled(Severity::style);
    1125        3215 :     const bool printWarning = mSettings->severity.isEnabled(Severity::warning);
    1126        3215 :     if (!printWarning && !printStyle && !mSettings->isPremiumEnabled("incorrectLogicOperator"))
    1127        2320 :         return;
    1128         894 :     const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
    1129             : 
    1130         894 :     logChecker("CheckCondition::checkIncorrectLogicOperator"); // style,warning
    1131             : 
    1132         894 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    1133        7335 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    1134             : 
    1135      224425 :         for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
    1136      217984 :             if (!Token::Match(tok, "%oror%|&&") || !tok->astOperand1() || !tok->astOperand2())
    1137      217911 :                 continue;
    1138             : 
    1139             : 
    1140             :             // 'A && (!A || B)' is equivalent to 'A && B'
    1141             :             // 'A || (!A && B)' is equivalent to 'A || B'
    1142             :             // 'A && (A || B)' is equivalent to 'A'
    1143             :             // 'A || (A && B)' is equivalent to 'A'
    1144         978 :             if (printStyle &&
    1145         737 :                 ((tok->str() == "||" && tok->astOperand2()->str() == "&&") ||
    1146         531 :                  (tok->str() == "&&" && tok->astOperand2()->str() == "||"))) {
    1147          19 :                 const Token* tok2 = tok->astOperand2()->astOperand1();
    1148          19 :                 if (isOppositeCond(true, tok->astOperand1(), tok2, *mSettings, true, false)) {
    1149          16 :                     std::string expr1(tok->astOperand1()->expressionString());
    1150          16 :                     std::string expr2(tok->astOperand2()->astOperand1()->expressionString());
    1151          16 :                     std::string expr3(tok->astOperand2()->astOperand2()->expressionString());
    1152             :                     // make copy for later because the original string might get overwritten
    1153          16 :                     const std::string expr1VerboseMsg = expr1;
    1154          16 :                     const std::string expr2VerboseMsg = expr2;
    1155          16 :                     const std::string expr3VerboseMsg = expr3;
    1156             : 
    1157           8 :                     if (expr1.length() + expr2.length() + expr3.length() > 50U) {
    1158           2 :                         if (expr1[0] == '!' && expr2[0] != '!') {
    1159           2 :                             expr1 = "!A";
    1160           2 :                             expr2 = "A";
    1161             :                         } else {
    1162           0 :                             expr1 = "A";
    1163           0 :                             expr2 = "!A";
    1164             :                         }
    1165             : 
    1166           2 :                         expr3 = "B";
    1167             :                     }
    1168             : 
    1169          24 :                     const std::string cond1 = expr1 + " " + tok->str() + " (" + expr2 + " " + tok->astOperand2()->str() + " " + expr3 + ")";
    1170          24 :                     const std::string cond2 = expr1 + " " + tok->str() + " " + expr3;
    1171             : 
    1172          24 :                     const std::string cond1VerboseMsg = expr1VerboseMsg + " " + tok->str() + " " + expr2VerboseMsg + " " + tok->astOperand2()->str() + " " + expr3VerboseMsg;
    1173          24 :                     const std::string cond2VerboseMsg = expr1VerboseMsg + " " + tok->str() + " " + expr3VerboseMsg;
    1174             :                     // for the --verbose message, transform the actual condition and print it
    1175          16 :                     const std::string msg = tok2->expressionString() + ". '" + cond1 + "' is equivalent to '" + cond2 + "'\n"
    1176          24 :                                             "The condition '" + cond1VerboseMsg + "' is equivalent to '" + cond2VerboseMsg + "'.";
    1177           8 :                     redundantConditionError(tok, msg, false);
    1178           8 :                     continue;
    1179             :                 }
    1180          11 :                 if (isSameExpression(false, tok->astOperand1(), tok2, *mSettings, true, true)) {
    1181           4 :                     std::string expr1(tok->astOperand1()->expressionString());
    1182           4 :                     std::string expr2(tok->astOperand2()->astOperand1()->expressionString());
    1183           4 :                     std::string expr3(tok->astOperand2()->astOperand2()->expressionString());
    1184             :                     // make copy for later because the original string might get overwritten
    1185           4 :                     const std::string expr1VerboseMsg = expr1;
    1186           4 :                     const std::string expr2VerboseMsg = expr2;
    1187           4 :                     const std::string expr3VerboseMsg = expr3;
    1188             : 
    1189           2 :                     if (expr1.length() + expr2.length() + expr3.length() > 50U) {
    1190           0 :                         expr1 = "A";
    1191           0 :                         expr2 = "A";
    1192           0 :                         expr3 = "B";
    1193             :                     }
    1194             : 
    1195           6 :                     const std::string cond1 = expr1 + " " + tok->str() + " (" + expr2 + " " + tok->astOperand2()->str() + " " + expr3 + ")";
    1196           4 :                     const std::string cond2 = std::move(expr1);
    1197             : 
    1198           6 :                     const std::string cond1VerboseMsg = expr1VerboseMsg + " " + tok->str() + " " + expr2VerboseMsg + " " + tok->astOperand2()->str() + " " + expr3VerboseMsg;
    1199           2 :                     const std::string& cond2VerboseMsg = expr1VerboseMsg;
    1200             :                     // for the --verbose message, transform the actual condition and print it
    1201           4 :                     const std::string msg = tok2->expressionString() + ". '" + cond1 + "' is equivalent to '" + cond2 + "'\n"
    1202           6 :                                             "The condition '" + cond1VerboseMsg + "' is equivalent to '" + cond2VerboseMsg + "'.";
    1203           2 :                     redundantConditionError(tok, msg, false);
    1204           2 :                     continue;
    1205             :                 }
    1206             :             }
    1207             : 
    1208             :             // Comparison #1 (LHS)
    1209         316 :             const Token *comp1 = tok->astOperand1();
    1210         316 :             if (comp1->str() == tok->str())
    1211          16 :                 comp1 = comp1->astOperand2();
    1212             : 
    1213             :             // Comparison #2 (RHS)
    1214         316 :             const Token *comp2 = tok->astOperand2();
    1215             : 
    1216         316 :             bool inconclusive = false;
    1217         316 :             bool parseable = true;
    1218             : 
    1219             :             // Parse LHS
    1220             :             bool not1;
    1221         316 :             std::string op1, value1;
    1222         316 :             const Token *expr1 = nullptr;
    1223         316 :             parseable &= (parseComparison(comp1, not1, op1, value1, expr1, inconclusive));
    1224             : 
    1225             :             // Parse RHS
    1226             :             bool not2;
    1227         316 :             std::string op2, value2;
    1228         316 :             const Token *expr2 = nullptr;
    1229         316 :             parseable &= (parseComparison(comp2, not2, op2, value2, expr2, inconclusive));
    1230             : 
    1231         316 :             if (inconclusive && !printInconclusive)
    1232           1 :                 continue;
    1233             : 
    1234         628 :             const bool isUnknown = (expr1 && expr1->valueType() && expr1->valueType()->type == ValueType::UNKNOWN_TYPE) ||
    1235         313 :                                    (expr2 && expr2->valueType() && expr2->valueType()->type == ValueType::UNKNOWN_TYPE);
    1236         315 :             if (isUnknown)
    1237           2 :                 continue;
    1238             : 
    1239         313 :             const bool isfloat = astIsFloat(expr1, true) || MathLib::isFloat(value1) || astIsFloat(expr2, true) || MathLib::isFloat(value2);
    1240             : 
    1241         313 :             ErrorPath errorPath;
    1242             : 
    1243             :             // Opposite comparisons around || or && => always true or always false
    1244         313 :             const bool isLogicalOr(tok->str() == "||");
    1245         313 :             if (!isfloat && isOppositeCond(isLogicalOr, tok->astOperand1(), tok->astOperand2(), *mSettings, true, true, &errorPath)) {
    1246          36 :                 if (!isIfConstexpr(tok)) {
    1247          35 :                     const bool alwaysTrue(isLogicalOr);
    1248          35 :                     incorrectLogicOperatorError(tok, conditionString(tok), alwaysTrue, inconclusive, errorPath);
    1249             :                 }
    1250          36 :                 continue;
    1251             :             }
    1252             : 
    1253         277 :             if (!parseable)
    1254           2 :                 continue;
    1255             : 
    1256         275 :             if (isSameExpression(true, comp1, comp2, *mSettings, true, true))
    1257           4 :                 continue; // same expressions => only report that there are same expressions
    1258         271 :             if (!isSameExpression(true, expr1, expr2, *mSettings, true, true))
    1259         194 :                 continue;
    1260             : 
    1261             : 
    1262             :             // don't check floating point equality comparisons. that is bad
    1263             :             // and deserves different warnings.
    1264          77 :             if (isfloat && (op1 == "==" || op1 == "!=" || op2 == "==" || op2 == "!="))
    1265           4 :                 continue;
    1266             : 
    1267             : 
    1268          73 :             const double d1 = (isfloat) ? MathLib::toDoubleNumber(value1) : 0;
    1269          73 :             const double d2 = (isfloat) ? MathLib::toDoubleNumber(value2) : 0;
    1270          73 :             const MathLib::bigint i1 = (isfloat) ? 0 : MathLib::toBigNumber(value1);
    1271          73 :             const MathLib::bigint i2 = (isfloat) ? 0 : MathLib::toBigNumber(value2);
    1272          73 :             const bool useUnsignedInt = (std::numeric_limits<MathLib::bigint>::max()==i1) || (std::numeric_limits<MathLib::bigint>::max()==i2);
    1273          73 :             const MathLib::biguint u1 = (useUnsignedInt) ? MathLib::toBigNumber(value1) : 0;
    1274          73 :             const MathLib::biguint u2 = (useUnsignedInt) ? MathLib::toBigNumber(value2) : 0;
    1275             :             // evaluate if expression is always true/false
    1276          73 :             bool alwaysTrue = true, alwaysFalse = true;
    1277          73 :             bool firstTrue = true, secondTrue = true;
    1278          73 :             const bool isAnd = tok->str() == "&&";
    1279         438 :             for (int test = 1; test <= 5; ++test) {
    1280             :                 // test:
    1281             :                 // 1 => testvalue is less than both value1 and value2
    1282             :                 // 2 => testvalue is value1
    1283             :                 // 3 => testvalue is between value1 and value2
    1284             :                 // 4 => testvalue value2
    1285             :                 // 5 => testvalue is larger than both value1 and value2
    1286             :                 bool result1, result2;
    1287         365 :                 if (isfloat) {
    1288          65 :                     const auto testvalue = getvalue<double>(test, d1, d2);
    1289          65 :                     result1 = checkFloatRelation(op1, testvalue, d1);
    1290          65 :                     result2 = checkFloatRelation(op2, testvalue, d2);
    1291         300 :                 } else if (useUnsignedInt) {
    1292           5 :                     const auto testvalue = getvalue<MathLib::biguint>(test, u1, u2);
    1293           5 :                     result1 = checkIntRelation(op1, testvalue, u1);
    1294           5 :                     result2 = checkIntRelation(op2, testvalue, u2);
    1295             :                 } else {
    1296         295 :                     const auto testvalue = getvalue<MathLib::bigint>(test, i1, i2);
    1297         295 :                     result1 = checkIntRelation(op1, testvalue, i1);
    1298         295 :                     result2 = checkIntRelation(op2, testvalue, i2);
    1299             :                 }
    1300         365 :                 if (not1)
    1301          20 :                     result1 = !result1;
    1302         365 :                 if (not2)
    1303          10 :                     result2 = !result2;
    1304         365 :                 if (isAnd) {
    1305         165 :                     alwaysTrue &= (result1 && result2);
    1306         165 :                     alwaysFalse &= !(result1 && result2);
    1307             :                 } else {
    1308         200 :                     alwaysTrue &= (result1 || result2);
    1309         200 :                     alwaysFalse &= !(result1 || result2);
    1310             :                 }
    1311         365 :                 firstTrue &= !(!result1 && result2);
    1312         365 :                 secondTrue &= !(result1 && !result2);
    1313             :             }
    1314             : 
    1315         146 :             const std::string cond1str = conditionString(not1, expr1, op1, value1);
    1316         146 :             const std::string cond2str = conditionString(not2, expr2, op2, value2);
    1317          73 :             if (printWarning && (alwaysTrue || alwaysFalse)) {
    1318          32 :                 const std::string text = cond1str + " " + tok->str() + " " + cond2str;
    1319          16 :                 incorrectLogicOperatorError(tok, text, alwaysTrue, inconclusive, std::move(errorPath));
    1320          57 :             } else if (printStyle && (firstTrue || secondTrue)) {
    1321             :                 // cppcheck-suppress accessMoved - TODO: FP - see #12174
    1322          24 :                 const int which = isfloat ? sufficientCondition(std::move(op1), not1, d1, std::move(op2), not2, d2, isAnd) : sufficientCondition(std::move(op1), not1, i1, std::move(op2), not2, i2, isAnd);
    1323          48 :                 std::string text;
    1324          24 :                 if (which != 0) {
    1325          24 :                     text = "The condition '" + (which == 1 ? cond2str : cond1str) + "' is redundant since '" + (which == 1 ? cond1str : cond2str) + "' is sufficient.";
    1326             :                 } else
    1327           0 :                     text = "If '" + (secondTrue ? cond1str : cond2str) + "', the comparison '" + (secondTrue ? cond2str : cond1str) + "' is always true.";
    1328          24 :                 redundantConditionError(tok, text, inconclusive);
    1329             :             }
    1330             :         }
    1331             :     }
    1332             : }
    1333             : 
    1334          55 : void CheckCondition::incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always, bool inconclusive, ErrorPath errors)
    1335             : {
    1336          55 :     if (diag(tok))
    1337           0 :         return;
    1338          55 :     errors.emplace_back(tok, "");
    1339          55 :     if (always)
    1340          36 :         reportError(errors, Severity::warning, "incorrectLogicOperator",
    1341          36 :                     "Logical disjunction always evaluates to true: " + condition + ".\n"
    1342          36 :                     "Logical disjunction always evaluates to true: " + condition + ". "
    1343          18 :                     "Are these conditions necessary? Did you intend to use && instead? Are the numbers correct? Are you comparing the correct variables?", CWE571, inconclusive ? Certainty::inconclusive : Certainty::normal);
    1344             :     else
    1345          74 :         reportError(errors, Severity::warning, "incorrectLogicOperator",
    1346          74 :                     "Logical conjunction always evaluates to false: " + condition + ".\n"
    1347          74 :                     "Logical conjunction always evaluates to false: " + condition + ". "
    1348          37 :                     "Are these conditions necessary? Did you intend to use || instead? Are the numbers correct? Are you comparing the correct variables?", CWE570, inconclusive ? Certainty::inconclusive : Certainty::normal);
    1349             : }
    1350             : 
    1351          38 : void CheckCondition::redundantConditionError(const Token *tok, const std::string &text, bool inconclusive)
    1352             : {
    1353          38 :     if (diag(tok))
    1354           0 :         return;
    1355          38 :     reportError(tok, Severity::style, "redundantCondition", "Redundant condition: " + text, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
    1356             : }
    1357             : 
    1358             : //-----------------------------------------------------------------------------
    1359             : // Detect "(var % val1) > val2" where val2 is >= val1.
    1360             : //-----------------------------------------------------------------------------
    1361        3215 : void CheckCondition::checkModuloAlwaysTrueFalse()
    1362             : {
    1363        3215 :     if (!mSettings->severity.isEnabled(Severity::warning))
    1364        2336 :         return;
    1365             : 
    1366         879 :     logChecker("CheckCondition::checkModuloAlwaysTrueFalse"); // warning
    1367             : 
    1368         879 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    1369        7306 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    1370      224119 :         for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
    1371      217692 :             if (!tok->isComparisonOp())
    1372      216126 :                 continue;
    1373             :             const Token *num, *modulo;
    1374        1566 :             if (Token::simpleMatch(tok->astOperand1(), "%") && Token::Match(tok->astOperand2(), "%num%")) {
    1375          12 :                 modulo = tok->astOperand1();
    1376          12 :                 num = tok->astOperand2();
    1377        1554 :             } else if (Token::Match(tok->astOperand1(), "%num%") && Token::simpleMatch(tok->astOperand2(), "%")) {
    1378           0 :                 num = tok->astOperand1();
    1379           0 :                 modulo = tok->astOperand2();
    1380             :             } else {
    1381        1554 :                 continue;
    1382             :             }
    1383             : 
    1384          23 :             if (Token::Match(modulo->astOperand2(), "%num%") &&
    1385          11 :                 MathLib::isLessEqual(modulo->astOperand2()->str(), num->str()))
    1386           9 :                 moduloAlwaysTrueFalseError(tok, modulo->astOperand2()->str());
    1387             :         }
    1388             :     }
    1389             : }
    1390             : 
    1391          13 : void CheckCondition::moduloAlwaysTrueFalseError(const Token* tok, const std::string& maxVal)
    1392             : {
    1393          13 :     if (diag(tok))
    1394           0 :         return;
    1395          13 :     reportError(tok, Severity::warning, "moduloAlwaysTrueFalse",
    1396          26 :                 "Comparison of modulo result is predetermined, because it is always less than " + maxVal + ".", CWE398, Certainty::normal);
    1397             : }
    1398             : 
    1399           8 : static int countPar(const Token *tok1, const Token *tok2)
    1400             : {
    1401           8 :     int par = 0;
    1402          30 :     for (const Token *tok = tok1; tok && tok != tok2; tok = tok->next()) {
    1403          22 :         if (tok->str() == "(")
    1404           2 :             ++par;
    1405          20 :         else if (tok->str() == ")")
    1406           2 :             --par;
    1407          18 :         else if (tok->str() == ";")
    1408           0 :             return -1;
    1409             :     }
    1410           8 :     return par;
    1411             : }
    1412             : 
    1413             : //---------------------------------------------------------------------------
    1414             : // Clarify condition '(x = a < 0)' into '((x = a) < 0)' or '(x = (a < 0))'
    1415             : // Clarify condition '(a & b == c)' into '((a & b) == c)' or '(a & (b == c))'
    1416             : //---------------------------------------------------------------------------
    1417        3215 : void CheckCondition::clarifyCondition()
    1418             : {
    1419        3215 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("clarifyCondition"))
    1420        2321 :         return;
    1421             : 
    1422         894 :     logChecker("CheckCondition::clarifyCondition"); // style
    1423             : 
    1424         894 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    1425        7335 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    1426      224425 :         for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
    1427      217984 :             if (Token::Match(tok, "( %name% [=&|^]")) {
    1428         221 :                 for (const Token *tok2 = tok->tokAt(3); tok2; tok2 = tok2->next()) {
    1429         221 :                     if (tok2->str() == "(" || tok2->str() == "[")
    1430          17 :                         tok2 = tok2->link();
    1431         204 :                     else if (tok2->isComparisonOp()) {
    1432             :                         // This might be a template
    1433           4 :                         if (!tok2->isC() && tok2->link())
    1434           0 :                             break;
    1435           4 :                         if (Token::simpleMatch(tok2->astParent(), "?"))
    1436           1 :                             break;
    1437           3 :                         clarifyConditionError(tok, tok->strAt(2) == "=", false);
    1438           3 :                         break;
    1439         200 :                     } else if (!tok2->isName() && !tok2->isNumber() && tok2->str() != ".")
    1440          98 :                         break;
    1441             :                 }
    1442      218798 :             } else if (tok->tokType() == Token::eBitOp && !tok->isUnaryOp("&")) {
    1443         275 :                 if (tok->astOperand2() && tok->astOperand2()->variable() && tok->astOperand2()->variable()->nameToken() == tok->astOperand2())
    1444           8 :                     continue;
    1445             : 
    1446             :                 // using boolean result in bitwise operation ! x [&|^]
    1447         267 :                 const ValueType* vt1 = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr;
    1448         267 :                 const ValueType* vt2 = tok->astOperand2() ? tok->astOperand2()->valueType() : nullptr;
    1449         267 :                 if (vt1 && vt1->type == ValueType::BOOL && !Token::Match(tok->astOperand1(), "%name%|(|[|::|.") && countPar(tok->astOperand1(), tok) == 0)
    1450           3 :                     clarifyConditionError(tok, false, true);
    1451         264 :                 else if (vt2 && vt2->type == ValueType::BOOL && !Token::Match(tok->astOperand2(), "%name%|(|[|::|.") && countPar(tok, tok->astOperand2()) == 0)
    1452           3 :                     clarifyConditionError(tok, false, true);
    1453             :             }
    1454             :         }
    1455             :     }
    1456             : }
    1457             : 
    1458          13 : void CheckCondition::clarifyConditionError(const Token *tok, bool assign, bool boolop)
    1459             : {
    1460          26 :     std::string errmsg;
    1461             : 
    1462          13 :     if (assign)
    1463           5 :         errmsg = "Suspicious condition (assignment + comparison); Clarify expression with parentheses.";
    1464             : 
    1465           8 :     else if (boolop)
    1466             :         errmsg = "Boolean result is used in bitwise operation. Clarify expression with parentheses.\n"
    1467             :                  "Suspicious expression. Boolean result is used in bitwise operation. The operator '!' "
    1468             :                  "and the comparison operators have higher precedence than bitwise operators. "
    1469           6 :                  "It is recommended that the expression is clarified with parentheses.";
    1470             :     else
    1471             :         errmsg = "Suspicious condition (bitwise operator + comparison); Clarify expression with parentheses.\n"
    1472             :                  "Suspicious condition. Comparison operators have higher precedence than bitwise operators. "
    1473           2 :                  "Please clarify the condition with parentheses.";
    1474             : 
    1475          13 :     reportError(tok,
    1476             :                 Severity::style,
    1477             :                 "clarifyCondition",
    1478          26 :                 errmsg, CWE398, Certainty::normal);
    1479          13 : }
    1480             : 
    1481        3215 : void CheckCondition::alwaysTrueFalse()
    1482             : {
    1483        3215 :     if (!mSettings->severity.isEnabled(Severity::style) &&
    1484        5536 :         !mSettings->isPremiumEnabled("alwaysTrue") &&
    1485        2321 :         !mSettings->isPremiumEnabled("alwaysFalse"))
    1486        2321 :         return;
    1487             : 
    1488         894 :     logChecker("CheckCondition::alwaysTrueFalse"); // style
    1489             : 
    1490         894 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    1491        7335 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    1492      222819 :         for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
    1493             :             // don't write false positives when templates are used or inside of asserts or non-evaluated contexts
    1494      275448 :             if (tok->link() && (Token::simpleMatch(tok, "<") ||
    1495       59070 :                                 Token::Match(tok->previous(), "static_assert|assert|ASSERT|sizeof|decltype ("))) {
    1496         540 :                 tok = tok->link();
    1497      216196 :                 continue;
    1498             :             }
    1499      215838 :             if (!tok->hasKnownIntValue())
    1500      203474 :                 continue;
    1501       12364 :             if (Token::Match(tok->previous(), "%name% (") && tok->previous()->function()) {
    1502          10 :                 const Function* f = tok->previous()->function();
    1503          10 :                 if (f->functionScope && Token::Match(f->functionScope->bodyStart, "{ return true|false ;"))
    1504           0 :                     continue;
    1505             :             }
    1506       12364 :             const Token* condition = nullptr;
    1507             :             {
    1508             :                 // is this a condition..
    1509       12364 :                 const Token *parent = tok->astParent();
    1510       12501 :                 while (Token::Match(parent, "%oror%|&&"))
    1511         137 :                     parent = parent->astParent();
    1512       12364 :                 if (!parent)
    1513        1178 :                     continue;
    1514       11186 :                 if (parent->str() == "?" && precedes(tok, parent))
    1515           5 :                     condition = parent;
    1516       11181 :                 else if (Token::Match(parent->previous(), "if|while ("))
    1517         484 :                     condition = parent->previous();
    1518       10697 :                 else if (Token::simpleMatch(parent, "return"))
    1519         168 :                     condition = parent;
    1520       10534 :                 else if (parent->str() == ";" && parent->astParent() && parent->astParent()->astParent() &&
    1521           5 :                          Token::simpleMatch(parent->astParent()->astParent()->previous(), "for ("))
    1522           5 :                     condition = parent->astParent()->astParent()->previous();
    1523       10524 :                 else if (Token::Match(tok, "%comp%"))
    1524          36 :                     condition = tok;
    1525             :                 else
    1526       10488 :                     continue;
    1527             :             }
    1528             :             // Skip already diagnosed values
    1529         698 :             if (diag(tok, false))
    1530         169 :                 continue;
    1531         529 :             if (condition->isConstexpr())
    1532           7 :                 continue;
    1533         522 :             if (!isUsedAsBool(tok, *mSettings))
    1534         114 :                 continue;
    1535         408 :             if (Token::simpleMatch(condition, "return") && Token::Match(tok, "%assign%"))
    1536           1 :                 continue;
    1537         407 :             if (Token::simpleMatch(tok->astParent(), "return") && Token::Match(tok, ".|%var%"))
    1538           7 :                 continue;
    1539         400 :             if (Token::Match(tok, "%num%|%bool%|%char%"))
    1540          38 :                 continue;
    1541         362 :             if (Token::Match(tok, "! %num%|%bool%|%char%"))
    1542           6 :                 continue;
    1543         356 :             if (Token::Match(tok, "%oror%|&&")) {
    1544          33 :                 bool bail = false;
    1545          53 :                 for (const Token* op : { tok->astOperand1(), tok->astOperand2() }) {
    1546          50 :                     if (op->hasKnownIntValue() && (!op->isLiteral() || op->isBoolean())) {
    1547          30 :                         bail = true;
    1548          30 :                         break;
    1549             :                     }
    1550             :                 }
    1551          33 :                 if (bail)
    1552          30 :                     continue;
    1553             :             }
    1554         326 :             if (Token::simpleMatch(tok, ":"))
    1555           0 :                 continue;
    1556         326 :             if (Token::Match(tok->astOperand1(), "%name% (") && Token::simpleMatch(tok->astParent(), "return"))
    1557           1 :                 continue;
    1558         562 :             if (tok->isComparisonOp() && isWithoutSideEffects(tok->astOperand1()) &&
    1559         237 :                 isSameExpression(true,
    1560             :                                  tok->astOperand1(),
    1561             :                                  tok->astOperand2(),
    1562         237 :                                  *mSettings,
    1563             :                                  true,
    1564             :                                  true))
    1565          14 :                 continue;
    1566         311 :             if (isConstVarExpression(tok, [](const Token* tok) {
    1567         638 :                 return Token::Match(tok, "[|(|&|+|-|*|/|%|^|>>|<<") && !Token::simpleMatch(tok, "( )");
    1568         622 :             }))
    1569          16 :                 continue;
    1570             : 
    1571             :             // there are specific warnings about nonzero expressions (pointer/unsigned)
    1572             :             // do not write alwaysTrueFalse for these comparisons.
    1573             :             {
    1574         295 :                 const ValueFlow::Value *zeroValue = nullptr;
    1575         295 :                 const Token *nonZeroExpr = nullptr;
    1576         585 :                 if (CheckOther::comparisonNonZeroExpressionLessThanZero(tok, zeroValue, nonZeroExpr, /*suppress*/ true) ||
    1577         290 :                     CheckOther::testIfNonZeroExpressionIsPositive(tok, zeroValue, nonZeroExpr))
    1578           9 :                     continue;
    1579             :             }
    1580             : 
    1581             :             // Don't warn when there are expanded macros..
    1582         286 :             bool isExpandedMacro = false;
    1583         286 :             visitAstNodes(tok, [&](const Token * tok2) {
    1584        1161 :                 if (!tok2)
    1585           0 :                     return ChildrenToVisit::none;
    1586        1161 :                 if (tok2->isExpandedMacro()) {
    1587          15 :                     isExpandedMacro = true;
    1588          15 :                     return ChildrenToVisit::done;
    1589             :                 }
    1590        1146 :                 return ChildrenToVisit::op1_and_op2;
    1591             :             });
    1592         286 :             if (isExpandedMacro)
    1593          15 :                 continue;
    1594         793 :             for (const Token *parent = tok; parent; parent = parent->astParent()) {
    1595         607 :                 if (parent->isExpandedMacro()) {
    1596          85 :                     isExpandedMacro = true;
    1597          85 :                     break;
    1598             :                 }
    1599             :             }
    1600         271 :             if (isExpandedMacro)
    1601          85 :                 continue;
    1602             : 
    1603             :             // don't warn when condition checks sizeof result
    1604         186 :             bool hasSizeof = false;
    1605         186 :             visitAstNodes(tok, [&](const Token * tok2) {
    1606         437 :                 if (!tok2)
    1607           0 :                     return ChildrenToVisit::none;
    1608         437 :                 if (tok2->isNumber())
    1609          99 :                     return ChildrenToVisit::none;
    1610         338 :                 if (Token::simpleMatch(tok2->previous(), "sizeof (")) {
    1611           4 :                     hasSizeof = true;
    1612           4 :                     return ChildrenToVisit::none;
    1613             :                 }
    1614         334 :                 if (tok2->isComparisonOp() || tok2->isArithmeticalOp()) {
    1615         126 :                     return ChildrenToVisit::op1_and_op2;
    1616             :                 }
    1617         208 :                 return ChildrenToVisit::none;
    1618             :             });
    1619         186 :             if (hasSizeof)
    1620           4 :                 continue;
    1621             : 
    1622         182 :             alwaysTrueFalseError(tok, condition, &tok->values().front());
    1623             :         }
    1624             :     }
    1625             : }
    1626             : 
    1627         186 : void CheckCondition::alwaysTrueFalseError(const Token* tok, const Token* condition, const ValueFlow::Value* value)
    1628             : {
    1629         186 :     const bool alwaysTrue = value && (value->intvalue != 0 || value->isImpossible());
    1630         372 :     const std::string expr = tok ? tok->expressionString() : std::string("x");
    1631         372 :     const std::string conditionStr = (Token::simpleMatch(condition, "return") ? "Return value" : "Condition");
    1632         558 :     const std::string errmsg = conditionStr + " '" + expr + "' is always " + bool_to_string(alwaysTrue);
    1633         372 :     const ErrorPath errorPath = getErrorPath(tok, value, errmsg);
    1634         186 :     reportError(errorPath,
    1635             :                 Severity::style,
    1636             :                 "knownConditionTrueFalse",
    1637             :                 errmsg,
    1638             :                 (alwaysTrue ? CWE571 : CWE570), Certainty::normal);
    1639         186 : }
    1640             : 
    1641        3215 : void CheckCondition::checkInvalidTestForOverflow()
    1642             : {
    1643             :     // Interesting blogs:
    1644             :     // https://www.airs.com/blog/archives/120
    1645             :     // https://kristerw.blogspot.com/2016/02/how-undefined-signed-overflow-enables.html
    1646             :     // https://research.checkpoint.com/2020/optout-compiler-undefined-behavior-optimizations/
    1647             : 
    1648             :     // x + c < x       ->   false
    1649             :     // x + c <= x      ->   false
    1650             :     // x + c > x       ->   true
    1651             :     // x + c >= x      ->   true
    1652             : 
    1653             :     // x + y < x       ->   y < 0
    1654             : 
    1655             : 
    1656        3215 :     if (!mSettings->severity.isEnabled(Severity::warning))
    1657        2336 :         return;
    1658             : 
    1659         879 :     logChecker("CheckCondition::checkInvalidTestForOverflow"); // warning
    1660             : 
    1661      285670 :     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
    1662      284791 :         if (!Token::Match(tok, "<|<=|>=|>") || !tok->isBinaryOp())
    1663      284208 :             continue;
    1664             : 
    1665         583 :         const Token *lhsTokens[2] = {tok->astOperand1(), tok->astOperand2()};
    1666        1749 :         for (const Token *lhs: lhsTokens) {
    1667        1166 :             std::string cmp = tok->str();
    1668        1166 :             if (lhs == tok->astOperand2())
    1669         583 :                 cmp[0] = (cmp[0] == '<') ? '>' : '<';
    1670             : 
    1671        1166 :             if (!Token::Match(lhs, "[+-]") || !lhs->isBinaryOp())
    1672        1135 :                 continue;
    1673             : 
    1674          31 :             const bool isSignedInteger = lhs->valueType() && lhs->valueType()->isIntegral() && lhs->valueType()->sign == ValueType::Sign::SIGNED;
    1675          31 :             const bool isPointer = lhs->valueType() && lhs->valueType()->pointer > 0;
    1676          31 :             if (!isSignedInteger && !isPointer)
    1677           6 :                 continue;
    1678             : 
    1679          25 :             const Token *exprTokens[2] = {lhs->astOperand1(), lhs->astOperand2()};
    1680          75 :             for (const Token *expr: exprTokens) {
    1681          50 :                 if (lhs->str() == "-" && expr == lhs->astOperand2())
    1682           9 :                     continue; // TODO?
    1683             : 
    1684          41 :                 if (expr->hasKnownIntValue())
    1685           9 :                     continue;
    1686             : 
    1687          32 :                 if (!isSameExpression(true,
    1688             :                                       expr,
    1689             :                                       lhs->astSibling(),
    1690          32 :                                       *mSettings,
    1691             :                                       true,
    1692             :                                       false))
    1693          12 :                     continue;
    1694             : 
    1695          20 :                 const Token * const other = expr->astSibling();
    1696             : 
    1697             :                 // x [+-] c cmp x
    1698          32 :                 if ((other->isNumber() && other->getKnownIntValue() > 0) ||
    1699          12 :                     (!other->isNumber() && other->valueType() && other->valueType()->isIntegral() && other->valueType()->sign == ValueType::Sign::UNSIGNED)) {
    1700             :                     bool result;
    1701          12 :                     if (lhs->str() == "+")
    1702           8 :                         result = (cmp == ">" || cmp == ">=");
    1703             :                     else
    1704           4 :                         result = (cmp == "<" || cmp == "<=");
    1705          12 :                     invalidTestForOverflow(tok, lhs->valueType(), bool_to_string(result));
    1706          12 :                     continue;
    1707             :                 }
    1708             : 
    1709             :                 // x + y cmp x
    1710           8 :                 if (lhs->str() == "+" && other->varId() > 0) {
    1711           8 :                     const std::string result = other->str() + cmp + "0";
    1712           4 :                     invalidTestForOverflow(tok, lhs->valueType(), result);
    1713           4 :                     continue;
    1714             :                 }
    1715             : 
    1716             :                 // x - y cmp x
    1717           4 :                 if (lhs->str() == "-" && other->varId() > 0) {
    1718           8 :                     std::string cmp2 = cmp;
    1719           4 :                     cmp2[0] = (cmp[0] == '<') ? '>' : '<';
    1720           8 :                     const std::string result = other->str() + cmp2 + "0";
    1721           4 :                     invalidTestForOverflow(tok, lhs->valueType(), result);
    1722           4 :                     continue;
    1723             :                 }
    1724             :             }
    1725             :         }
    1726             :     }
    1727             : }
    1728             : 
    1729          24 : void CheckCondition::invalidTestForOverflow(const Token* tok, const ValueType *valueType, const std::string &replace)
    1730             : {
    1731          48 :     const std::string expr = (tok ? tok->expressionString() : std::string("x + c < x"));
    1732          48 :     const std::string overflow = (valueType && valueType->pointer) ? "pointer overflow" : "signed integer overflow";
    1733             : 
    1734             :     std::string errmsg =
    1735          72 :         "Invalid test for overflow '" +  expr + "'; " + overflow + " is undefined behavior.";
    1736          24 :     if (replace == "false" || replace == "true")
    1737          16 :         errmsg += " Some mainstream compilers remove such overflow tests when optimising the code and assume it's always " + replace + ".";
    1738             :     else
    1739           8 :         errmsg += " Some mainstream compilers removes handling of overflows when optimising the code and change the code to '" + replace + "'.";
    1740          24 :     reportError(tok, Severity::warning, "invalidTestForOverflow", errmsg, uncheckedErrorConditionCWE, Certainty::normal);
    1741          24 : }
    1742             : 
    1743             : 
    1744        3215 : void CheckCondition::checkPointerAdditionResultNotNull()
    1745             : {
    1746        3215 :     if (!mSettings->severity.isEnabled(Severity::warning))
    1747        2335 :         return;
    1748             : 
    1749         879 :     logChecker("CheckCondition::checkPointerAdditionResultNotNull"); // warning
    1750             : 
    1751         879 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    1752        7306 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    1753             : 
    1754      230546 :         for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
    1755      224119 :             if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
    1756      222553 :                 continue;
    1757             : 
    1758             :             // Macros might have pointless safety checks
    1759        1566 :             if (tok->isExpandedMacro())
    1760          69 :                 continue;
    1761             : 
    1762             :             const Token *calcToken, *exprToken;
    1763        1497 :             if (tok->astOperand1()->str() == "+") {
    1764          19 :                 calcToken = tok->astOperand1();
    1765          19 :                 exprToken = tok->astOperand2();
    1766        1478 :             } else if (tok->astOperand2()->str() == "+") {
    1767           3 :                 calcToken = tok->astOperand2();
    1768           3 :                 exprToken = tok->astOperand1();
    1769             :             } else
    1770        1475 :                 continue;
    1771             : 
    1772             :             // pointer comparison against NULL (ptr+12==0)
    1773          22 :             if (calcToken->hasKnownIntValue())
    1774           1 :                 continue;
    1775          21 :             if (!calcToken->valueType() || calcToken->valueType()->pointer==0)
    1776          16 :                 continue;
    1777           5 :             if (!exprToken->hasKnownIntValue() || !exprToken->getValue(0))
    1778           4 :                 continue;
    1779             : 
    1780           1 :             pointerAdditionResultNotNullError(tok, calcToken);
    1781             :         }
    1782             :     }
    1783             : }
    1784             : 
    1785           5 : void CheckCondition::pointerAdditionResultNotNullError(const Token *tok, const Token *calc)
    1786             : {
    1787           5 :     const std::string s = calc ? calc->expressionString() : "ptr+1";
    1788           5 :     reportError(tok, Severity::warning, "pointerAdditionResultNotNull", "Comparison is wrong. Result of '" + s + "' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour.");
    1789           5 : }
    1790             : 
    1791        3215 : void CheckCondition::checkDuplicateConditionalAssign()
    1792             : {
    1793        3215 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateConditionalAssign"))
    1794        2321 :         return;
    1795             : 
    1796         894 :     logChecker("CheckCondition::checkDuplicateConditionalAssign"); // style
    1797             : 
    1798         894 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    1799        7335 :     for (const Scope *scope : symbolDatabase->functionScopes) {
    1800      230866 :         for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
    1801      224425 :             if (!Token::simpleMatch(tok, "if ("))
    1802      223033 :                 continue;
    1803        1392 :             if (!Token::simpleMatch(tok->next()->link(), ") {"))
    1804           3 :                 continue;
    1805        1389 :             const Token *blockTok = tok->next()->link()->next();
    1806        1389 :             const Token *condTok = tok->next()->astOperand2();
    1807        1389 :             const bool isBoolVar = Token::Match(condTok, "!| %var%");
    1808        1389 :             if (!isBoolVar && !Token::Match(condTok, "==|!="))
    1809         611 :                 continue;
    1810         778 :             if ((isBoolVar || condTok->str() == "!=") && Token::simpleMatch(blockTok->link(), "} else {"))
    1811          25 :                 continue;
    1812         753 :             if (!blockTok->next())
    1813           0 :                 continue;
    1814         753 :             const Token *assignTok = blockTok->next()->astTop();
    1815         753 :             if (!Token::simpleMatch(assignTok, "="))
    1816         707 :                 continue;
    1817          46 :             if (nextAfterAstRightmostLeaf(assignTok) != blockTok->link()->previous())
    1818           6 :                 continue;
    1819          40 :             bool isRedundant = false;
    1820          40 :             if (isBoolVar) {
    1821          12 :                 const bool isNegation = condTok->str() == "!";
    1822          12 :                 const Token* const varTok = isNegation ? condTok->next() : condTok;
    1823          12 :                 const ValueType* vt = varTok->variable() ? varTok->variable()->valueType() : nullptr;
    1824          12 :                 if (!(vt && vt->type == ValueType::Type::BOOL && !vt->pointer))
    1825           5 :                     continue;
    1826             : 
    1827           7 :                 if (!(assignTok->astOperand1() && assignTok->astOperand1()->varId() == varTok->varId()))
    1828           0 :                     continue;
    1829           7 :                 if (!(assignTok->astOperand2() && assignTok->astOperand2()->hasKnownIntValue()))
    1830           0 :                     continue;
    1831           7 :                 const MathLib::bigint val = assignTok->astOperand2()->getKnownIntValue();
    1832           7 :                 if (val < 0 || val > 1)
    1833           0 :                     continue;
    1834           7 :                 isRedundant = (isNegation && val == 0) || (!isNegation && val == 1);
    1835             :             } else { // comparison
    1836          28 :                 if (!isSameExpression(
    1837          28 :                         true, condTok->astOperand1(), assignTok->astOperand1(), *mSettings, true, true))
    1838          16 :                     continue;
    1839          12 :                 if (!isSameExpression(
    1840          12 :                         true, condTok->astOperand2(), assignTok->astOperand2(), *mSettings, true, true))
    1841           9 :                     continue;
    1842             :             }
    1843          10 :             duplicateConditionalAssignError(condTok, assignTok, isRedundant);
    1844             :         }
    1845             :     }
    1846             : }
    1847             : 
    1848          14 : void CheckCondition::duplicateConditionalAssignError(const Token *condTok, const Token* assignTok, bool isRedundant)
    1849             : {
    1850          28 :     ErrorPath errors;
    1851          28 :     std::string msg = "Duplicate expression for the condition and assignment.";
    1852          14 :     if (condTok && assignTok) {
    1853          10 :         if (condTok->str() == "==") {
    1854           2 :             msg = "Assignment '" + assignTok->expressionString() + "' is redundant with condition '" + condTok->expressionString() + "'.";
    1855           2 :             errors.emplace_back(condTok, "Condition '" + condTok->expressionString() + "'");
    1856           2 :             errors.emplace_back(assignTok, "Assignment '" + assignTok->expressionString() + "' is redundant");
    1857             :         } else {
    1858           8 :             msg = "The statement 'if (" + condTok->expressionString() + ") " + assignTok->expressionString();
    1859           8 :             msg += isRedundant ? "' is redundant." : "' is logically equivalent to '" + assignTok->expressionString() + "'.";
    1860           8 :             errors.emplace_back(assignTok, "Assignment '" + assignTok->expressionString() + "'");
    1861           8 :             errors.emplace_back(condTok, "Condition '" + condTok->expressionString() + "' is redundant");
    1862             :         }
    1863             :     }
    1864             : 
    1865          14 :     reportError(
    1866             :         errors, Severity::style, "duplicateConditionalAssign", msg, CWE398, Certainty::normal);
    1867          14 : }
    1868             : 
    1869             : 
    1870        3215 : void CheckCondition::checkAssignmentInCondition()
    1871             : {
    1872        3215 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("assignmentInCondition"))
    1873        2321 :         return;
    1874             : 
    1875         894 :     logChecker("CheckCondition::checkAssignmentInCondition"); // style
    1876             : 
    1877         894 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    1878        7335 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    1879      230866 :         for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
    1880      224425 :             if (tok->str() != "=")
    1881      222089 :                 continue;
    1882        2336 :             if (!tok->astParent())
    1883        2220 :                 continue;
    1884             : 
    1885             :             // Is this assignment of container/iterator?
    1886         116 :             if (!tok->valueType())
    1887          15 :                 continue;
    1888         101 :             if (tok->valueType()->pointer > 0)
    1889           8 :                 continue;
    1890          93 :             if (tok->valueType()->type != ValueType::Type::CONTAINER && tok->valueType()->type != ValueType::Type::ITERATOR)
    1891          56 :                 continue;
    1892             : 
    1893             :             // warn if this is a conditional expression..
    1894          37 :             if (Token::Match(tok->astParent()->previous(), "if|while ("))
    1895           1 :                 assignmentInCondition(tok);
    1896          36 :             else if (Token::Match(tok->astParent(), "%oror%|&&"))
    1897           0 :                 assignmentInCondition(tok);
    1898          36 :             else if (Token::simpleMatch(tok->astParent(), "?") && tok == tok->astParent()->astOperand1())
    1899           0 :                 assignmentInCondition(tok);
    1900             :         }
    1901             :     }
    1902             : }
    1903             : 
    1904           5 : void CheckCondition::assignmentInCondition(const Token *eq)
    1905             : {
    1906           5 :     std::string expr = eq ? eq->expressionString() : "x=y";
    1907             : 
    1908           5 :     reportError(
    1909             :         eq,
    1910             :         Severity::style,
    1911             :         "assignmentInCondition",
    1912          10 :         "Suspicious assignment in condition. Condition '" + expr + "' is always true.",
    1913             :         CWE571,
    1914          10 :         Certainty::normal);
    1915           5 : }
    1916             : 
    1917        3215 : void CheckCondition::checkCompareValueOutOfTypeRange()
    1918             : {
    1919        3215 :     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("compareValueOutOfTypeRange"))
    1920        2321 :         return;
    1921             : 
    1922         894 :     if (mSettings->platform.type == Platform::Type::Native ||
    1923          57 :         mSettings->platform.type == Platform::Type::Unspecified)
    1924         837 :         return;
    1925             : 
    1926          57 :     logChecker("CheckCondition::checkCompareValueOutOfTypeRange"); // style,platform
    1927             : 
    1928          57 :     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
    1929        5685 :     for (const Scope * scope : symbolDatabase->functionScopes) {
    1930      212477 :         for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
    1931      206849 :             if (!tok->isComparisonOp() || !tok->isBinaryOp())
    1932      206171 :                 continue;
    1933             : 
    1934        2034 :             for (int i = 0; i < 2; ++i) {
    1935        1356 :                 const Token * const valueTok = (i == 0) ? tok->astOperand1() : tok->astOperand2();
    1936        1356 :                 const Token * const typeTok = valueTok->astSibling();
    1937        1356 :                 if (!valueTok->hasKnownIntValue() || !typeTok->valueType() || typeTok->valueType()->pointer)
    1938         797 :                     continue;
    1939         559 :                 if (valueTok->getKnownIntValue() < 0 && valueTok->valueType() && valueTok->valueType()->sign != ValueType::Sign::SIGNED)
    1940           0 :                     continue;
    1941         559 :                 if (valueTok->valueType() && valueTok->valueType()->isTypeEqual(typeTok->valueType()))
    1942         440 :                     continue;
    1943         119 :                 int bits = 0;
    1944         119 :                 switch (typeTok->valueType()->type) {
    1945           0 :                 case ValueType::Type::BOOL:
    1946           0 :                     bits = 1;
    1947           0 :                     break;
    1948          27 :                 case ValueType::Type::CHAR:
    1949          27 :                     bits = mSettings->platform.char_bit;
    1950          27 :                     break;
    1951           1 :                 case ValueType::Type::SHORT:
    1952           1 :                     bits = mSettings->platform.short_bit;
    1953           1 :                     break;
    1954          26 :                 case ValueType::Type::INT:
    1955          26 :                     bits = mSettings->platform.int_bit;
    1956          26 :                     break;
    1957          49 :                 case ValueType::Type::LONG:
    1958          49 :                     bits = mSettings->platform.long_bit;
    1959          49 :                     break;
    1960          10 :                 case ValueType::Type::LONGLONG:
    1961          10 :                     bits = mSettings->platform.long_long_bit;
    1962          10 :                     break;
    1963           6 :                 default:
    1964           6 :                     break;
    1965             :                 }
    1966         119 :                 if (bits == 0 || bits >= 64)
    1967          50 :                     continue;
    1968             : 
    1969          69 :                 const auto typeMinValue = (typeTok->valueType()->sign == ValueType::Sign::UNSIGNED) ? 0 : (-(1LL << (bits-1)));
    1970          69 :                 const auto unsignedTypeMaxValue = (1LL << bits) - 1LL;
    1971             :                 long long typeMaxValue;
    1972          69 :                 if (typeTok->valueType()->sign != ValueType::Sign::SIGNED)
    1973          23 :                     typeMaxValue = unsignedTypeMaxValue;
    1974          46 :                 else if (bits >= mSettings->platform.int_bit && (!valueTok->valueType() || valueTok->valueType()->sign != ValueType::Sign::SIGNED))
    1975           5 :                     typeMaxValue = unsignedTypeMaxValue;
    1976             :                 else
    1977          41 :                     typeMaxValue = unsignedTypeMaxValue / 2;
    1978             : 
    1979          69 :                 bool result{};
    1980          69 :                 const auto kiv = valueTok->getKnownIntValue();
    1981          69 :                 if (tok->str() == "==")
    1982          39 :                     result = false;
    1983          30 :                 else if (tok->str() == "!=")
    1984           1 :                     result = true;
    1985          29 :                 else if (tok->str()[0] == '>' && i == 0)
    1986             :                     // num > var
    1987           4 :                     result = (kiv > 0);
    1988          25 :                 else if (tok->str()[0] == '>' && i == 1)
    1989             :                     // var > num
    1990          10 :                     result = (kiv < 0);
    1991          15 :                 else if (tok->str()[0] == '<' && i == 0)
    1992             :                     // num < var
    1993           4 :                     result = (kiv < 0);
    1994          11 :                 else if (tok->str()[0] == '<' && i == 1)
    1995             :                     // var < num
    1996          11 :                     result = (kiv > 0);
    1997             : 
    1998          69 :                 bool error = false;
    1999          69 :                 if (kiv < typeMinValue || kiv > typeMaxValue) {
    2000           7 :                     error = true;
    2001             :                 } else {
    2002          62 :                     switch (i) {
    2003          33 :                     case 0: // num cmp var
    2004          33 :                         if (kiv == typeMinValue) {
    2005           4 :                             if (tok->str() == "<=") {
    2006           1 :                                 result = true;
    2007           1 :                                 error = true;
    2008           3 :                             } else if (tok->str() == ">")
    2009           1 :                                 error = true;
    2010             :                         }
    2011          29 :                         else if (kiv == typeMaxValue && (tok->str() == ">=" || tok->str() == "<")) {
    2012           2 :                             error = true;
    2013             :                         }
    2014          33 :                         break;
    2015          29 :                     case 1: // var cmp num
    2016          29 :                         if (kiv == typeMinValue) {
    2017           8 :                             if (tok->str() == ">=") {
    2018           2 :                                 result = true;
    2019           2 :                                 error = true;
    2020           6 :                             } else if (tok->str() == "<")
    2021           1 :                                 error = true;
    2022             :                         }
    2023          21 :                         else if (kiv == typeMaxValue && (tok->str() == "<=" || tok->str() == ">")) {
    2024           3 :                             error = true;
    2025             :                         }
    2026          29 :                         break;
    2027             :                     }
    2028             :                 }
    2029          69 :                 if (error)
    2030          17 :                     compareValueOutOfTypeRangeError(valueTok, typeTok->valueType()->str(), kiv, result);
    2031             :             }
    2032             :         }
    2033             :     }
    2034             : }
    2035             : 
    2036          21 : void CheckCondition::compareValueOutOfTypeRangeError(const Token *comparison, const std::string &type, long long value, bool result)
    2037             : {
    2038          21 :     reportError(
    2039             :         comparison,
    2040             :         Severity::style,
    2041             :         "compareValueOutOfTypeRangeError",
    2042          42 :         "Comparing expression of type '" + type + "' against value " + std::to_string(value) + ". Condition is always " + bool_to_string(result) + ".",
    2043             :         CWE398,
    2044          42 :         Certainty::normal);
    2045          21 : }

Generated by: LCOV version 1.14