diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/ExplicitReturnNullRector/Fixture/skip_do_whlile_true_always_returned.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/ExplicitReturnNullRector/Fixture/skip_do_whlile_true_always_returned.php.inc new file mode 100644 index 00000000000..e61df85ca7d --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/ExplicitReturnNullRector/Fixture/skip_do_whlile_true_always_returned.php.inc @@ -0,0 +1,15 @@ +isDoWithAlwaysReturnOrExit($stmt)) { - return true; + if (!$this->isDoOrWhileWithAlwaysReturnOrExit($stmt)) { + continue; } + + return true; } return false; } - private function isDoWithAlwaysReturnOrExit(Do_ $do): bool + private function isFoundLoopControl(Do_|While_ $node): bool + { + $isFoundLoopControl = false; + $this->simpleCallableNodeTraverser->traverseNodesWithCallable( + $node->stmts, + static function (Node $subNode) use (&$isFoundLoopControl) { + if ($subNode instanceof Class_ || $subNode instanceof Function_ || $subNode instanceof Closure) { + return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; + } + + if ($subNode instanceof Break_ || $subNode instanceof Continue_ || $subNode instanceof Goto_) { + $isFoundLoopControl = true; + return NodeTraverser::STOP_TRAVERSAL; + } + } + ); + + return $isFoundLoopControl; + } + + private function isDoOrWhileWithAlwaysReturnOrExit(Stmt $stmt): bool { - if (! $this->hasStmtsAlwaysReturnOrExit($do->stmts)) { + if (! $stmt instanceof Do_ && ! $stmt instanceof While_) { return false; } - return ! (bool) $this->betterNodeFinder->findFirst( - $do->stmts, - static fn (Node $node): bool => $node instanceof Break_ || $node instanceof Continue_ || $node instanceof Goto_ - ); + if ($this->valueResolver->isTrue($stmt->cond)) { + return ! $this->isFoundLoopControl($stmt); + } + + if (! $this->hasStmtsAlwaysReturnOrExit($stmt->stmts)) { + return false; + } + + return ! $this->isFoundLoopControl($stmt);; } private function isIfReturn(Stmt|Expr $stmt): bool