From 96a8806e30e03873e8d3eeca39ebbe1882a2b39a Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 5 Aug 2026 21:23:44 +0200 Subject: [PATCH 1/3] [CodeQuality] Skip InlineConstructorDefaultToPropertyRector on property also defined in parent, when parent::__construct() is called --- ...own_property_with_parent_construct.php.inc | 37 ++++++++++++++ ...perty_filled_in_parent_constructor.php.inc | 17 +++++++ .../AbstractParentWithFilledProperty.php | 15 ++++++ ...lineConstructorDefaultToPropertyRector.php | 48 ++++++++++++++++++- 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Fixture/own_property_with_parent_construct.php.inc create mode 100644 rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Fixture/skip_property_filled_in_parent_constructor.php.inc create mode 100644 rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Source/AbstractParentWithFilledProperty.php diff --git a/rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Fixture/own_property_with_parent_construct.php.inc b/rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Fixture/own_property_with_parent_construct.php.inc new file mode 100644 index 00000000000..132c83d4d1a --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Fixture/own_property_with_parent_construct.php.inc @@ -0,0 +1,37 @@ +ownTypes = ['refresh_token']; + } +} + +?> +----- + diff --git a/rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Fixture/skip_property_filled_in_parent_constructor.php.inc b/rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Fixture/skip_property_filled_in_parent_constructor.php.inc new file mode 100644 index 00000000000..d9d3ca5b9b3 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Fixture/skip_property_filled_in_parent_constructor.php.inc @@ -0,0 +1,17 @@ +allowedGrantTypes = ['refresh_token']; + } +} diff --git a/rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Source/AbstractParentWithFilledProperty.php b/rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Source/AbstractParentWithFilledProperty.php new file mode 100644 index 00000000000..3fd1f368fc6 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector/Source/AbstractParentWithFilledProperty.php @@ -0,0 +1,15 @@ +allowedGrantTypes[] = 'authorization_code'; + } +} diff --git a/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php b/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php index e952fb1806f..0188e32ce74 100644 --- a/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php +++ b/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php @@ -8,16 +8,19 @@ use PhpParser\Node\Expr; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\If_; use PhpParser\Node\Stmt\Property; +use PHPStan\Reflection\ClassReflection; use Rector\NodeAnalyzer\ExprAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\PhpParser\Node\BetterNodeFinder; use Rector\PhpParser\NodeFinder\PropertyFetchFinder; use Rector\Rector\AbstractRector; +use Rector\Reflection\ReflectionResolver; use Rector\ValueObject\MethodName; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -30,7 +33,8 @@ final class InlineConstructorDefaultToPropertyRector extends AbstractRector public function __construct( private readonly ExprAnalyzer $exprAnalyzer, private readonly BetterNodeFinder $betterNodeFinder, - private readonly PropertyFetchFinder $propertyFetchFinder + private readonly PropertyFetchFinder $propertyFetchFinder, + private readonly ReflectionResolver $reflectionResolver ) { } @@ -89,6 +93,8 @@ public function refactor(Node $node): ?Node return null; } + $hasParentConstructCall = false; + foreach ($constructClassMethod->stmts as $key => $stmt) { // code that is possibly breaking flow if ($stmt instanceof If_) { @@ -99,6 +105,11 @@ public function refactor(Node $node): ?Node continue; } + if ($this->isParentConstructCall($stmt->expr)) { + $hasParentConstructCall = true; + continue; + } + if (! $stmt->expr instanceof Assign) { continue; } @@ -115,6 +126,11 @@ public function refactor(Node $node): ?Node continue; } + // parent constructor may set the very same property, keep assign order as is + if ($hasParentConstructCall && $this->isPropertyDefinedInParentClass($node, $propertyName)) { + continue; + } + $hasPropertyChanged = $this->refactorProperty( $node, $propertyName, @@ -135,6 +151,36 @@ public function refactor(Node $node): ?Node return $node; } + private function isParentConstructCall(Expr $expr): bool + { + if (! $expr instanceof StaticCall) { + return false; + } + + if (! $this->isName($expr->class, 'parent')) { + return false; + } + + return $this->isName($expr->name, MethodName::CONSTRUCT); + } + + private function isPropertyDefinedInParentClass(Class_ $class, string $propertyName): bool + { + $classReflection = $this->reflectionResolver->resolveClassReflection($class); + if (! $classReflection instanceof ClassReflection) { + // unknown parent, keep it safe + return true; + } + + foreach ($classReflection->getParents() as $parentClassReflection) { + if ($parentClassReflection->getNativeReflection()->hasProperty($propertyName)) { + return true; + } + } + + return false; + } + private function matchAssignedLocalPropertyName(Assign $assign): ?string { if (! $assign->var instanceof PropertyFetch) { From cd97a490c60737b365476cc7e7acb965e58d4321 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 5 Aug 2026 21:55:23 +0000 Subject: [PATCH 2/3] [ci-review] Rector Rectify --- .../Class_/InlineConstructorDefaultToPropertyRector.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php b/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php index 0188e32ce74..3388ebb53e6 100644 --- a/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php +++ b/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php @@ -171,14 +171,7 @@ private function isPropertyDefinedInParentClass(Class_ $class, string $propertyN // unknown parent, keep it safe return true; } - - foreach ($classReflection->getParents() as $parentClassReflection) { - if ($parentClassReflection->getNativeReflection()->hasProperty($propertyName)) { - return true; - } - } - - return false; + return array_any($classReflection->getParents(), fn(ClassReflection $parentClassReflection) => $parentClassReflection->getNativeReflection()->hasProperty($propertyName)); } private function matchAssignedLocalPropertyName(Assign $assign): ?string From 45bc95b710ecd4c482de749d43c385433aaa2c9d Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 5 Aug 2026 21:57:12 +0000 Subject: [PATCH 3/3] [ci-review] Rector Rectify --- .../Rector/Class_/InlineConstructorDefaultToPropertyRector.php | 1 + 1 file changed, 1 insertion(+) diff --git a/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php b/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php index 3388ebb53e6..c1e1358fb27 100644 --- a/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php +++ b/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php @@ -171,6 +171,7 @@ private function isPropertyDefinedInParentClass(Class_ $class, string $propertyN // unknown parent, keep it safe return true; } + return array_any($classReflection->getParents(), fn(ClassReflection $parentClassReflection) => $parentClassReflection->getNativeReflection()->hasProperty($propertyName)); }