@@ -1172,6 +1172,165 @@ static bool hasFunctionCall(const Token *tok)
11721172 return hasFunctionCall (tok->astOperand1 ()) || hasFunctionCall (tok->astOperand2 ());
11731173}
11741174
1175+ const Scope* PathAnalysis::findOuterScope (const Scope * scope)
1176+ {
1177+ if (!scope)
1178+ return nullptr ;
1179+ if (scope->isLocal () && scope->type != Scope::eSwitch)
1180+ return findOuterScope (scope->nestedIn );
1181+ return scope;
1182+ }
1183+
1184+ static const Token* getCondTok (const Token* tok)
1185+ {
1186+ if (!tok)
1187+ return nullptr ;
1188+ if (Token::simpleMatch (tok, " (" ))
1189+ return getCondTok (tok->previous ());
1190+ if (Token::simpleMatch (tok, " for" ) && Token::simpleMatch (tok->next ()->astOperand2 (), " ;" ) && tok->next ()->astOperand2 ()->astOperand2 ())
1191+ return tok->next ()->astOperand2 ()->astOperand2 ()->astOperand1 ();
1192+ if (Token::simpleMatch (tok->next ()->astOperand2 (), " ;" ))
1193+ return tok->next ()->astOperand2 ()->astOperand1 ();
1194+ return tok->next ()->astOperand2 ();
1195+ }
1196+
1197+ std::pair<bool , bool > PathAnalysis::checkCond (const Token * tok, bool & known)
1198+ {
1199+ if (tok->hasKnownIntValue ()) {
1200+ known = true ;
1201+ return std::make_pair (tok->values ().front ().intvalue , !tok->values ().front ().intvalue );
1202+ }
1203+ auto it = std::find_if (tok->values ().begin (), tok->values ().end (), [](const ValueFlow::Value& v) {
1204+ return v.isIntValue ();
1205+ });
1206+ // If all possible values are the same, then assume all paths have the same value
1207+ if (it != tok->values ().end () && std::all_of (it, tok->values ().end (), [&](const ValueFlow::Value& v) {
1208+ if (v.isIntValue ())
1209+ return v.intvalue == it->intvalue ;
1210+ return true ;
1211+ })) {
1212+ known = false ;
1213+ return std::make_pair (it->intvalue , !it->intvalue );
1214+ }
1215+ return std::make_pair (true , true );
1216+ }
1217+
1218+ PathAnalysis::Progress PathAnalysis::forwardRecursive (const Token* tok, Info info, const std::function<PathAnalysis::Progress(const Info&)>& f) const
1219+ {
1220+ if (!tok)
1221+ return Progress::Continue;
1222+ if (tok->astOperand1 () && forwardRecursive (tok->astOperand1 (), info, f) == Progress::Break)
1223+ return Progress::Break;
1224+ info.tok = tok;
1225+ if (f (info) == Progress::Break)
1226+ return Progress::Break;
1227+ if (tok->astOperand2 () && forwardRecursive (tok->astOperand2 (), info, f) == Progress::Break)
1228+ return Progress::Break;
1229+ return Progress::Continue;
1230+ }
1231+
1232+ PathAnalysis::Progress PathAnalysis::forwardRange (const Token* startToken, const Token* endToken, Info info, const std::function<PathAnalysis::Progress(const Info&)>& f) const
1233+ {
1234+ for (const Token *tok = startToken; tok && tok != endToken; tok = tok->next ()) {
1235+ if (Token::Match (tok, " asm|goto|break|continue" ))
1236+ return Progress::Break;
1237+ if (Token::Match (tok, " return|throw" )) {
1238+ forwardRecursive (tok, info, f);
1239+ return Progress::Break;
1240+ }
1241+ if (Token::simpleMatch (tok, " }" ) && Token::simpleMatch (tok->link ()->previous (), " ) {" ) && Token::Match (tok->link ()->linkAt (-1 )->previous (), " if|while|for (" )) {
1242+ const Token * blockStart = tok->link ()->linkAt (-1 )->previous ();
1243+ const Token * condTok = getCondTok (blockStart);
1244+ if (!condTok)
1245+ continue ;
1246+ info.errorPath .emplace_back (condTok, " Assuming condition is true." );
1247+ // Traverse a loop a second time
1248+ if (Token::Match (blockStart, " for|while (" )) {
1249+ const Token* endCond = blockStart->linkAt (1 );
1250+ bool traverseLoop = true ;
1251+ // Only traverse simple for loops
1252+ if (Token::simpleMatch (blockStart, " for" ) && !Token::Match (endCond->tokAt (-3 ), " ; ++|--|%var% %var%|++|-- ) {" ))
1253+ traverseLoop = false ;
1254+ // Traverse loop a second time
1255+ if (traverseLoop) {
1256+ // Traverse condition
1257+ if (forwardRecursive (condTok, info, f) == Progress::Break)
1258+ return Progress::Break;
1259+ // TODO: Should we traverse the body: forwardRange(tok->link(), tok, info, f)?
1260+ }
1261+ }
1262+ }
1263+ if (Token::Match (tok, " if|while|for (" ) && Token::simpleMatch (tok->next ()->link (), " ) {" )) {
1264+ const Token * endCond = tok->next ()->link ();
1265+ const Token * endBlock = endCond->next ()->link ();
1266+ const Token * condTok = getCondTok (tok);
1267+ if (!condTok)
1268+ continue ;
1269+ // Traverse condition
1270+ if (forwardRange (tok->next (), tok->next ()->link (), info, f) == Progress::Break)
1271+ return Progress::Break;
1272+ Info i = info;
1273+ i.known = false ;
1274+ i.errorPath .emplace_back (condTok, " Assuming condition is true." );
1275+
1276+ // Check if condition is true or false
1277+ bool checkThen = false ;
1278+ bool checkElse = false ;
1279+ std::tie (checkThen, checkElse) = checkCond (condTok, i.known );
1280+
1281+ // Traverse then block
1282+ if (checkThen) {
1283+ if (forwardRange (endCond->next (), endBlock, i, f) == Progress::Break)
1284+ return Progress::Break;
1285+ }
1286+ // Traverse else block
1287+ if (Token::simpleMatch (endBlock, " } else {" )) {
1288+ if (checkElse) {
1289+ i.errorPath .back ().second = " Assuming condition is false." ;
1290+ Progress result = forwardRange (endCond->next (), endBlock, i, f);
1291+ if (result == Progress::Break)
1292+ return Progress::Break;
1293+ }
1294+ tok = endBlock->linkAt (2 );
1295+ } else {
1296+ tok = endBlock;
1297+ }
1298+ } else if (Token::simpleMatch (tok, " } else {" )) {
1299+ tok = tok->linkAt (2 );
1300+ } else {
1301+ info.tok = tok;
1302+ if (f (info) == Progress::Break)
1303+ return Progress::Break;
1304+ }
1305+ // Prevent inifinite recursion
1306+ if (tok->next () == start)
1307+ break ;
1308+ }
1309+ return Progress::Continue;
1310+ }
1311+
1312+ void PathAnalysis::forward (const std::function<Progress(const Info&)>& f) const
1313+ {
1314+ const Scope * endScope = findOuterScope (start->scope ());
1315+ if (!endScope)
1316+ return ;
1317+ const Token * endToken = endScope->bodyEnd ;
1318+ Info info{start, ErrorPath{}, true };
1319+ forwardRange (start, endToken, info, f);
1320+ }
1321+
1322+ bool reaches (const Token * start, const Token * dest, const Library& library, ErrorPath* errorPath)
1323+ {
1324+ PathAnalysis::Info info = PathAnalysis{start, library} .forwardFind ([&](const PathAnalysis::Info& i) {
1325+ return (i.tok == dest);
1326+ });
1327+ if (!info.tok )
1328+ return false ;
1329+ if (errorPath)
1330+ errorPath->insert (errorPath->end (), info.errorPath .begin (), info.errorPath .end ());
1331+ return true ;
1332+ }
1333+
11751334struct FwdAnalysis ::Result FwdAnalysis::checkRecursive (const Token *expr, const Token *startToken, const Token *endToken, const std::set<int > &exprVarIds, bool local, bool inInnerClass)
11761335{
11771336 // Parse the given tokens
0 commit comments