From 1b72a6b500afdd0d3036fb4365c582e22d549926 Mon Sep 17 00:00:00 2001 From: dchaudhari7177 <111210939+dchaudhari7177@users.noreply.github.com> Date: Wed, 9 Sep 2026 12:40:24 +0530 Subject: [PATCH 1/2] Report ConsoleExecuteReturnIntRector when it rewrites a return The rule tracks $this->hasChanged, and refactor() returns the node only when that flag is set -- but only refactorReturnTypeDeclaration() ever set it. Every other mutation was made in place and not declared: setReturnTo0InsteadOfNull() rewrites `return null` to `return 0`, `return false` to `return 1`, the null side of a `??` or of a ternary, and wraps a non-int expression in `(int)`; processReturn0ToMethod() appends `return 0;` to the method. So a command whose execute() already carries `: int` gets its body rewritten while refactor() returns null. That is the empty `Applied rules:` in rectorphp/rector#9897: the diff is printed with no rule attributed to it, and which of the two happens is left to how the caller treats an undeclared in-place mutation -- on 2.4.5 it was dropped, on 2.6.6 it is printed. setReturnTo0InsteadOfNull() now reports whether it rewrote anything, the caller raises hasChanged from it, and the append raises it too. No mutation is added or removed; only the declaration of the ones already being made. Fixture: a command already returning int whose `return null` still needs rewriting -- the shape that had no coverage, since every existing fixture with a null return also lacks the return type and so was carried by refactorReturnTypeDeclaration(). --- .../return_null_with_int_return_type.php.inc | 35 +++++++++++++++++++ .../ConsoleExecuteReturnIntRector.php | 29 +++++++++------ 2 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 rules-tests/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector/Fixture/return_null_with_int_return_type.php.inc diff --git a/rules-tests/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector/Fixture/return_null_with_int_return_type.php.inc b/rules-tests/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector/Fixture/return_null_with_int_return_type.php.inc new file mode 100644 index 00000000..5d9e9319 --- /dev/null +++ b/rules-tests/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector/Fixture/return_null_with_int_return_type.php.inc @@ -0,0 +1,35 @@ + +----- + diff --git a/rules/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector.php b/rules/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector.php index e684d1b3..8373cc5e 100644 --- a/rules/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector.php +++ b/rules/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector.php @@ -145,7 +145,9 @@ private function addReturn0ToExecuteClassMethod(ClassMethod $classMethod): void return null; } - $this->setReturnTo0InsteadOfNull($node); + if ($this->setReturnTo0InsteadOfNull($node)) { + $this->hasChanged = true; + } return null; }); @@ -204,42 +206,47 @@ private function processReturn0ToMethod(ClassMethod $classMethod): void } $classMethod->stmts[] = $return; + $this->hasChanged = true; } - private function setReturnTo0InsteadOfNull(Return_ $return): void + /** + * @return bool True when the return was rewritten, so the caller can report + * the rule as applied for it. + */ + private function setReturnTo0InsteadOfNull(Return_ $return): bool { if (! $return->expr instanceof Expr) { $return->expr = new \PhpParser\Node\Scalar\Int_(0); - return; + return true; } if ($this->valueResolver->isNull($return->expr)) { $return->expr = new \PhpParser\Node\Scalar\Int_(0); - return; + return true; } // false means the command failed, that is the 1 exit code if ($this->valueResolver->isFalse($return->expr)) { $return->expr = new \PhpParser\Node\Scalar\Int_(1); - return; + return true; } if ($return->expr instanceof Coalesce && $this->valueResolver->isNull($return->expr->right)) { $return->expr->right = new \PhpParser\Node\Scalar\Int_(0); - return; + return true; } - if ($return->expr instanceof Ternary) { - $hasChanged = $this->isSuccessfulRefactorTernaryReturn($return->expr); - if ($hasChanged) { - return; - } + if ($return->expr instanceof Ternary && $this->isSuccessfulRefactorTernaryReturn($return->expr)) { + return true; } $staticType = $this->getType($return->expr); if (! $staticType->isInteger()->yes()) { $return->expr = new Int_($return->expr); + return true; } + + return false; } private function isSuccessfulRefactorTernaryReturn(Ternary $ternary): bool From ac38f584287f5884a25e37b9b4499f07a42bf9c3 Mon Sep 17 00:00:00 2001 From: dchaudhari7177 <111210939+dchaudhari7177@users.noreply.github.com> Date: Sun, 13 Sep 2026 11:25:43 +0530 Subject: [PATCH 2/2] Rename setReturnTo0InsteadOfNull now that it reports whether it changed The method returns bool so the caller can mark the rule as applied, which trips symplify.noReturnSetterMethod for a set* name. Name it after its sibling isSuccessfulRefactorTernaryReturn. --- .../Rector/ClassMethod/ConsoleExecuteReturnIntRector.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/rules/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector.php b/rules/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector.php index 8373cc5e..2003d4ee 100644 --- a/rules/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector.php +++ b/rules/Symfony44/Rector/ClassMethod/ConsoleExecuteReturnIntRector.php @@ -145,7 +145,7 @@ private function addReturn0ToExecuteClassMethod(ClassMethod $classMethod): void return null; } - if ($this->setReturnTo0InsteadOfNull($node)) { + if ($this->isSuccessfulRefactorReturn($node)) { $this->hasChanged = true; } @@ -209,11 +209,7 @@ private function processReturn0ToMethod(ClassMethod $classMethod): void $this->hasChanged = true; } - /** - * @return bool True when the return was rewritten, so the caller can report - * the rule as applied for it. - */ - private function setReturnTo0InsteadOfNull(Return_ $return): bool + private function isSuccessfulRefactorReturn(Return_ $return): bool { if (! $return->expr instanceof Expr) { $return->expr = new \PhpParser\Node\Scalar\Int_(0);