@@ -304,6 +304,15 @@ static const Token * skipValueInConditionalExpression(const Token * const valuet
304304 return nullptr ;
305305}
306306
307+ static bool isEscapeScope (const Token* tok, TokenList * tokenlist)
308+ {
309+ if (!Token::simpleMatch (tok, " {" ))
310+ return false ;
311+ const Token * termTok = Token::findmatch (tok, " return|continue|break|throw|goto" , tok->link ());
312+ return (termTok && termTok->scope () == tok->scope ()) ||
313+ (tokenlist && tokenlist->getSettings ()->library .isScopeNoReturn (tok->link (), nullptr ));
314+ }
315+
307316static bool bailoutSelfAssignment (const Token * const tok)
308317{
309318 const Token *parent = tok;
@@ -1089,6 +1098,104 @@ static void valueFlowBitAnd(TokenList *tokenlist)
10891098 }
10901099}
10911100
1101+ static void valueFlowTerminatingCondition (TokenList *tokenlist, SymbolDatabase* symboldatabase, const Settings *settings)
1102+ {
1103+ const bool cpp = symboldatabase->isCPP ();
1104+ typedef std::pair<const Token*, const Scope*> Condition;
1105+ for (const Scope * scope : symboldatabase->functionScopes ) {
1106+ std::vector<Condition> conds;
1107+ for (const Token* tok = scope->bodyStart ; tok != scope->bodyEnd ; tok = tok->next ()) {
1108+ if (!Token::simpleMatch (tok, " if (" ))
1109+ continue ;
1110+ // Skip known values
1111+ if (tok->next ()->hasKnownValue ())
1112+ continue ;
1113+ const Token * condTok = tok->next ();
1114+ if (!Token::simpleMatch (condTok->link (), " ) {" ))
1115+ continue ;
1116+ const Token * blockTok = condTok->link ()->tokAt (1 );
1117+ // Check if the block terminates early
1118+ if (!isEscapeScope (blockTok, tokenlist))
1119+ continue ;
1120+ // Check if any variables are modified in scope
1121+ bool bail = false ;
1122+ for (const Token * tok2=condTok->next ();tok2 != condTok->link ();tok2 = tok2->next ()) {
1123+ const Variable * var = tok2->variable ();
1124+ if (!var)
1125+ continue ;
1126+ const Token * endToken = var->scope ()->bodyEnd ;
1127+ if (!var->isLocal () && !var->isConst () && !var->isArgument ()) {
1128+ bail = true ;
1129+ break ;
1130+ }
1131+ if (var->isStatic () && !var->isConst ()) {
1132+ bail = true ;
1133+ break ;
1134+ }
1135+ if (!var->isConst () && var->declEndToken () && isVariableChanged (var->declEndToken ()->next (), endToken, tok2->varId (), false , settings, cpp)) {
1136+ bail = true ;
1137+ break ;
1138+ }
1139+ }
1140+ if (bail)
1141+ continue ;
1142+ // TODO: Handle multiple conditions
1143+ if (Token::Match (condTok->astOperand2 (), " %oror%|%or%|&|&&" ))
1144+ continue ;
1145+ const Scope * condScope = nullptr ;
1146+ for (const Scope * parent = condTok->scope ();parent;parent = parent->nestedIn ) {
1147+ if (parent->type == Scope::eIf ||
1148+ parent->type == Scope::eSwitch) {
1149+ condScope = parent;
1150+ break ;
1151+ }
1152+ }
1153+ conds.emplace_back (condTok->astOperand2 (), condScope);
1154+
1155+ }
1156+ for (Condition cond:conds) {
1157+ if (!cond.first )
1158+ continue ;
1159+ for (Token* tok = cond.first ->next (); tok != scope->bodyEnd ; tok = tok->next ()) {
1160+ if (tok == cond.first )
1161+ continue ;
1162+ if (!Token::Match (tok, " %comp%" ))
1163+ continue ;
1164+ // Skip known values
1165+ if (tok->hasKnownValue ())
1166+ continue ;
1167+ if (cond.second ) {
1168+ bool bail = true ;
1169+ for (const Scope * parent = tok->scope ()->nestedIn ;parent;parent = parent->nestedIn ) {
1170+ if (parent == cond.second ) {
1171+ bail = false ;
1172+ break ;
1173+ }
1174+ }
1175+ if (bail)
1176+ continue ;
1177+ }
1178+ ErrorPath errorPath;
1179+ if (isOppositeCond (true , cpp, tok, cond.first , settings->library , true , &errorPath)) {
1180+ ValueFlow::Value val (1 );
1181+ val.setKnown ();
1182+ val.condition = cond.first ;
1183+ val.errorPath = errorPath;
1184+ val.errorPath .emplace_back (cond.first , " Assuming condition '" + cond.first ->expressionString () + " ' is false" );
1185+ setTokenValue (tok, val, tokenlist->getSettings ());
1186+ } else if (isSameExpression (cpp, true , tok, cond.first , settings->library , true , &errorPath)) {
1187+ ValueFlow::Value val (0 );
1188+ val.setKnown ();
1189+ val.condition = cond.first ;
1190+ val.errorPath = errorPath;
1191+ val.errorPath .emplace_back (cond.first , " Assuming condition '" + cond.first ->expressionString () + " ' is false" );
1192+ setTokenValue (tok, val, tokenlist->getSettings ());
1193+ }
1194+ }
1195+ }
1196+ }
1197+ }
1198+
10921199static bool getExpressionRange (const Token *expr, MathLib::bigint *minvalue, MathLib::bigint *maxvalue)
10931200{
10941201 if (expr->hasKnownIntValue ()) {
@@ -1688,14 +1795,6 @@ static bool evalAssignment(ValueFlow::Value &lhsValue, const std::string &assign
16881795 return true ;
16891796}
16901797
1691- static bool isEscapeScope (const Token* tok, TokenList * tokenlist)
1692- {
1693- if (!Token::simpleMatch (tok, " {" ))
1694- return false ;
1695- return Token::findmatch (tok, " return|continue|break|throw|goto" , tok->link ()) ||
1696- (tokenlist && tokenlist->getSettings ()->library .isScopeNoReturn (tok->link (), nullptr ));
1697- }
1698-
16991798static bool valueFlowForward (Token * const startToken,
17001799 const Token * const endToken,
17011800 const Variable * const var,
@@ -4012,6 +4111,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
40124111 values = getTotalValues (tokenlist);
40134112 valueFlowRightShift (tokenlist);
40144113 valueFlowOppositeCondition (symboldatabase, settings);
4114+ valueFlowTerminatingCondition (tokenlist, symboldatabase, settings);
40154115 valueFlowBeforeCondition (tokenlist, symboldatabase, errorLogger, settings);
40164116 valueFlowAfterMove (tokenlist, symboldatabase, errorLogger, settings);
40174117 valueFlowAfterAssign (tokenlist, symboldatabase, errorLogger, settings);
0 commit comments