| 450 | } |
| 451 | |
| 452 | Progress updateLoop(const Token* endToken, |
| 453 | Token* endBlock, |
| 454 | Token* condTok, |
| 455 | Token* initTok = nullptr, |
| 456 | Token* stepTok = nullptr, |
| 457 | bool exit = false) { |
| 458 | if (initTok && updateRecursive(initTok) == Progress::Break) |
| 459 | return Break(); |
| 460 | const bool isDoWhile = precedes(endBlock, condTok); |
| 461 | bool checkThen = true; |
| 462 | bool checkElse = false; |
| 463 | if (condTok && !Token::simpleMatch(condTok, ":")) |
| 464 | std::tie(checkThen, checkElse) = evalCond(condTok, isDoWhile ? endBlock->previous() : nullptr); |
| 465 | // exiting a do while(false) |
| 466 | if (checkElse && exit) { |
| 467 | if (hasJump(endBlock)) { |
| 468 | if (!analyzer->lowerToPossible()) |
| 469 | return Break(Analyzer::Terminate::Bail); |
| 470 | if (analyzer->isConditional() && stopUpdates()) |
| 471 | return Break(Analyzer::Terminate::Conditional); |
| 472 | } |
| 473 | return Progress::Continue; |
| 474 | } |
| 475 | Analyzer::Action bodyAnalysis = analyzeScope(endBlock); |
| 476 | Analyzer::Action allAnalysis = bodyAnalysis; |
| 477 | Analyzer::Action condAnalysis; |
| 478 | if (condTok) { |
| 479 | condAnalysis = analyzeRecursive(condTok); |
| 480 | allAnalysis |= condAnalysis; |
| 481 | } |
| 482 | if (stepTok) |
| 483 | allAnalysis |= analyzeRecursive(stepTok); |
| 484 | actions |= allAnalysis; |
| 485 | // do while(false) is not really a loop |
| 486 | if (checkElse && isDoWhile && |
| 487 | (condTok->hasKnownIntValue() || |
| 488 | (!bodyAnalysis.isModified() && !condAnalysis.isModified() && condAnalysis.isRead()))) { |
| 489 | if (updateScope(endBlock) == Progress::Break) |
| 490 | return Break(); |
| 491 | return updateRecursive(condTok); |
| 492 | } |
| 493 | if (allAnalysis.isInconclusive()) { |
| 494 | if (!analyzer->lowerToInconclusive()) |
| 495 | return Break(Analyzer::Terminate::Bail); |
| 496 | } else if (allAnalysis.isModified() || (exit && allAnalysis.isIdempotent())) { |
| 497 | if (!analyzer->lowerToPossible()) |
| 498 | return Break(Analyzer::Terminate::Bail); |
| 499 | } |
| 500 | |
| 501 | if (condTok && !Token::simpleMatch(condTok, ":")) { |
| 502 | if (!isDoWhile || (!bodyAnalysis.isModified() && !bodyAnalysis.isIdempotent())) |
| 503 | if (updateRecursive(condTok) == Progress::Break) |
| 504 | return Break(); |
| 505 | } |
| 506 | if (!checkThen && !checkElse && !isDoWhile && stopOnCondition(condTok) && stopUpdates()) |
| 507 | return Break(Analyzer::Terminate::Conditional); |
| 508 | // condition is false, we don't enter the loop |
| 509 | if (checkElse && !isDoWhile) |
no test coverage detected