From ae7ccd45143573aff14d5a42b355b7b0def137d5 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 24 Dec 2025 22:02:57 +0700 Subject: [PATCH 1/5] [DeadCode] Skip with different default param value child vs parent on RemoveParentDelegatingConstructorRector --- ...skip_different_default_param_value.php.inc | 11 +++++++++ .../with_equal_default_param_value.php.inc | 23 +++++++++++++++++++ ...emoveParentDelegatingConstructorRector.php | 17 ++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_default_param_value.php.inc create mode 100644 rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/with_equal_default_param_value.php.inc diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_default_param_value.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_default_param_value.php.inc new file mode 100644 index 00000000000..3d64c96b6ab --- /dev/null +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_default_param_value.php.inc @@ -0,0 +1,11 @@ + +----- + \ No newline at end of file diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php index 8f9e6bee211..6418fbb56e5 100644 --- a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php +++ b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php @@ -6,6 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Arg; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt; @@ -15,9 +16,11 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; use Rector\Enum\ObjectReference; +use Rector\PhpParser\Node\Value\ValueResolver; use Rector\PHPStan\ScopeFetcher; use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Rector\Rector\AbstractRector; +use Rector\Reflection\ReflectionResolver; use Rector\StaticTypeMapper\StaticTypeMapper; use Rector\ValueObject\MethodName; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -30,6 +33,7 @@ final class RemoveParentDelegatingConstructorRector extends AbstractRector { public function __construct( private readonly StaticTypeMapper $staticTypeMapper, + private readonly ValueResolver $valueResolver ) { } @@ -207,6 +211,7 @@ private function areConstructorAndParentParameterTypesMatching( ClassMethod $classMethod, ExtendedMethodReflection $extendedMethodReflection ): bool { + $methodName = $this->getName($classMethod); foreach ($classMethod->getParams() as $position => $param) { $parameterType = $param->type; @@ -230,6 +235,18 @@ private function areConstructorAndParentParameterTypesMatching( if (! $this->nodeComparator->areNodesEqual($parameterType, $parentParameterType)) { return false; } + + if ($extendedMethodReflection->getDeclaringClass()->getNativeReflection()->hasMethod($methodName)) { + $parentMethod = $extendedMethodReflection->getDeclaringClass()->getNativeReflection()->getMethod($methodName); + $nativeParentParameterReflection = $parentMethod->getParameters()[$index] ?? null; + + $parentDefault = $nativeParentParameterReflection->getDefaultValue(); + $currentDefault = $this->valueResolver->getValue($param->default); + + if ($parentDefault !== $currentDefault) { + return false; + } + } } } From 5c398e3a3132d5ce00f716bc3ba5bc3d474c61c4 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 24 Dec 2025 22:06:02 +0700 Subject: [PATCH 2/5] fix --- .../RemoveParentDelegatingConstructorRector.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php index 6418fbb56e5..14b0eaf5ca3 100644 --- a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php +++ b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php @@ -13,6 +13,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use PhpParser\NodeVisitor; +use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; use Rector\Enum\ObjectReference; @@ -20,7 +21,6 @@ use Rector\PHPStan\ScopeFetcher; use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Rector\Rector\AbstractRector; -use Rector\Reflection\ReflectionResolver; use Rector\StaticTypeMapper\StaticTypeMapper; use Rector\ValueObject\MethodName; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -236,10 +236,20 @@ private function areConstructorAndParentParameterTypesMatching( return false; } + if (! $param->default instanceof Expr) { + continue; + } + if ($extendedMethodReflection->getDeclaringClass()->getNativeReflection()->hasMethod($methodName)) { - $parentMethod = $extendedMethodReflection->getDeclaringClass()->getNativeReflection()->getMethod($methodName); + $parentMethod = $extendedMethodReflection->getDeclaringClass() + ->getNativeReflection() + ->getMethod($methodName); $nativeParentParameterReflection = $parentMethod->getParameters()[$index] ?? null; + if (! $nativeParentParameterReflection instanceof ReflectionParameter) { + continue; + } + $parentDefault = $nativeParentParameterReflection->getDefaultValue(); $currentDefault = $this->valueResolver->getValue($param->default); From 62917d4f820c5e94eb19887b853bfbc225dfb053 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 24 Dec 2025 22:06:32 +0700 Subject: [PATCH 3/5] eol --- .../Fixture/skip_different_default_param_value.php.inc | 2 +- .../Fixture/with_equal_default_param_value.php.inc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_default_param_value.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_default_param_value.php.inc index 3d64c96b6ab..be4d4591186 100644 --- a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_default_param_value.php.inc +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_default_param_value.php.inc @@ -8,4 +8,4 @@ class SkipWithDefaultParams extends \DateTime { parent::__construct($datetime, $timezone); } -} \ No newline at end of file +} diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/with_equal_default_param_value.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/with_equal_default_param_value.php.inc index 93e807c6032..f904501bfab 100644 --- a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/with_equal_default_param_value.php.inc +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/with_equal_default_param_value.php.inc @@ -20,4 +20,4 @@ class WithEqualDefaultParamValue extends \DateTime { } -?> \ No newline at end of file +?> From f1f975e0fd9c7d0fffbb0f58c56ada5407315f60 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 24 Dec 2025 22:07:13 +0700 Subject: [PATCH 4/5] comment --- .../ClassMethod/RemoveParentDelegatingConstructorRector.php | 1 + 1 file changed, 1 insertion(+) diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php index 14b0eaf5ca3..7a5c3946506 100644 --- a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php +++ b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php @@ -240,6 +240,7 @@ private function areConstructorAndParentParameterTypesMatching( continue; } + // native reflection is needed to get exact default value if ($extendedMethodReflection->getDeclaringClass()->getNativeReflection()->hasMethod($methodName)) { $parentMethod = $extendedMethodReflection->getDeclaringClass() ->getNativeReflection() From fded30994c63566267acef4b8e18ff8f0302d217 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 25 Dec 2025 15:11:37 +0700 Subject: [PATCH 5/5] extract logic to different method --- ...emoveParentDelegatingConstructorRector.php | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php index 7a5c3946506..c5d610c23ad 100644 --- a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php +++ b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php @@ -211,7 +211,6 @@ private function areConstructorAndParentParameterTypesMatching( ClassMethod $classMethod, ExtendedMethodReflection $extendedMethodReflection ): bool { - $methodName = $this->getName($classMethod); foreach ($classMethod->getParams() as $position => $param) { $parameterType = $param->type; @@ -240,27 +239,38 @@ private function areConstructorAndParentParameterTypesMatching( continue; } - // native reflection is needed to get exact default value - if ($extendedMethodReflection->getDeclaringClass()->getNativeReflection()->hasMethod($methodName)) { - $parentMethod = $extendedMethodReflection->getDeclaringClass() - ->getNativeReflection() - ->getMethod($methodName); - $nativeParentParameterReflection = $parentMethod->getParameters()[$index] ?? null; + if ($this->isDifferentDefaultValue($param->default, $extendedMethodReflection, $index)) { + return false; + } + } + } - if (! $nativeParentParameterReflection instanceof ReflectionParameter) { - continue; - } + return true; + } - $parentDefault = $nativeParentParameterReflection->getDefaultValue(); - $currentDefault = $this->valueResolver->getValue($param->default); + private function isDifferentDefaultValue( + Expr $defaultExpr, + ExtendedMethodReflection $extendedMethodReflection, + int $index + ): bool { + $methodName = $extendedMethodReflection->getName(); + // native reflection is needed to get exact default value + if ($extendedMethodReflection->getDeclaringClass()->getNativeReflection()->hasMethod($methodName)) { + $parentMethod = $extendedMethodReflection->getDeclaringClass() + ->getNativeReflection() + ->getMethod($methodName); + $nativeParentParameterReflection = $parentMethod->getParameters()[$index] ?? null; + + if (! $nativeParentParameterReflection instanceof ReflectionParameter) { + return false; + } - if ($parentDefault !== $currentDefault) { - return false; - } - } + $parentDefault = $nativeParentParameterReflection->getDefaultValue(); + if (! $this->valueResolver->isValue($defaultExpr, $parentDefault)) { + return true; } } - return true; + return false; } }