From 66aabb068fce64530ea5968acbc1f4dd85cc0ae4 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 26 Feb 2026 18:48:18 +0700 Subject: [PATCH 1/3] [CodeQuality] Skip with custom param in previous position on ThrowWithPreviousExceptionRector --- ..._custom_param_in_previous_position.php.inc | 24 +++++++++++++++++ .../ThrowWithPreviousExceptionRector.php | 26 ++++++++++++++----- 2 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 rules-tests/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector/Fixture/skip_with_custom_param_in_previous_position.php.inc diff --git a/rules-tests/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector/Fixture/skip_with_custom_param_in_previous_position.php.inc b/rules-tests/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector/Fixture/skip_with_custom_param_in_previous_position.php.inc new file mode 100644 index 00000000000..bcac00b5afe --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector/Fixture/skip_with_custom_param_in_previous_position.php.inc @@ -0,0 +1,24 @@ +getMessage(), previous: $e); + } + } +} diff --git a/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php b/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php index c53fce5269a..489b47e976d 100644 --- a/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php +++ b/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php @@ -158,7 +158,7 @@ private function refactorThrow(Throw_ $throw, Variable $caughtThrowableVariable) } if (! isset($new->getArgs()[1])) { - if ($this->hasCodeParameter($new->class)) { + if ($this->hasParameter($new, 'code') && ! $this->hasArgument($new, 'code')) { // get previous code $new->args[1] = new Arg( new MethodCall($caughtThrowableVariable, 'getCode'), @@ -173,7 +173,7 @@ private function refactorThrow(Throw_ $throw, Variable $caughtThrowableVariable) /** @var Arg $arg1 */ $arg1 = $new->args[1]; if ($arg1->name instanceof Identifier && $arg1->name->toString() === 'previous') { - if ($this->hasCodeParameter($new->class)) { + if ($this->hasParameter($new, 'code') && ! $this->hasArgument($new, 'code')) { $new->args[1] = new Arg( new MethodCall($caughtThrowableVariable, 'getCode'), name: $shouldUseNamedArguments ? new Identifier('code') : null @@ -183,11 +183,14 @@ private function refactorThrow(Throw_ $throw, Variable $caughtThrowableVariable) } elseif (! $hasChanged) { return null; } - } else { + } elseif ($this->hasParameter($new, 'previous') && ! $this->hasArgument($new, 'previous')) { $new->args[$exceptionArgumentPosition] = new Arg( $caughtThrowableVariable, name: $shouldUseNamedArguments ? new Identifier('previous') : null ); + $hasChanged = true; + } elseif (! $hasChanged) { + return null; } // null the node, to fix broken format preserving printers, see https://github.com/rectorphp/rector/issues/5576 @@ -197,9 +200,9 @@ private function refactorThrow(Throw_ $throw, Variable $caughtThrowableVariable) return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN; } - private function hasCodeParameter(Name $exceptionName): bool + private function hasParameter(New_ $new, string $parameterName): bool { - $className = $this->getName($exceptionName); + $className = $this->getName($new->class); if (! $this->reflectionProvider->hasClass($className)) { return false; } @@ -217,7 +220,18 @@ private function hasCodeParameter(Name $exceptionName): bool ); foreach ($extendedParametersAcceptor->getParameters() as $extendedParameterReflection) { - if ($extendedParameterReflection->getName() === 'code') { + if ($extendedParameterReflection->getName() === $parameterName) { + return true; + } + } + + return false; + } + + private function hasArgument(New_ $new, string $argumentName): bool + { + foreach ($new->getArgs() as $arg) { + if ($arg->name instanceof Identifier && $arg->name->toString() === $argumentName) { return true; } } From d44dd34dd7f3f9bcee399d92c342818c31ee130e Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 26 Feb 2026 18:50:39 +0700 Subject: [PATCH 2/3] [CodeQuality] Skip with custom param in previous position on ThrowWithPreviousExceptionRector --- .../Rector/Catch_/ThrowWithPreviousExceptionRector.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php b/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php index 489b47e976d..ba36f610026 100644 --- a/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php +++ b/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php @@ -203,6 +203,10 @@ private function refactorThrow(Throw_ $throw, Variable $caughtThrowableVariable) private function hasParameter(New_ $new, string $parameterName): bool { $className = $this->getName($new->class); + if ($className === null) { + return false; + } + if (! $this->reflectionProvider->hasClass($className)) { return false; } From 47e5dedb02510a4c5638bc576986c6e4c2a9ce79 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 26 Feb 2026 21:10:05 +0700 Subject: [PATCH 3/3] final touch: add on purpose comment for future reference --- .../skip_with_custom_param_in_previous_position.php.inc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rules-tests/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector/Fixture/skip_with_custom_param_in_previous_position.php.inc b/rules-tests/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector/Fixture/skip_with_custom_param_in_previous_position.php.inc index bcac00b5afe..9e0768e5ff0 100644 --- a/rules-tests/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector/Fixture/skip_with_custom_param_in_previous_position.php.inc +++ b/rules-tests/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector/Fixture/skip_with_custom_param_in_previous_position.php.inc @@ -2,6 +2,9 @@ namespace Rector\Tests\CodeQuality\Rector\Catch_\ThrowWithPreviousExceptionRector\Fixture; +/** + * This direct use new ExceptionWithCustomParam() inside the class is on purpose to reproduce the issue + */ final class ExceptionWithCustomParam extends \RuntimeException { public function __construct(