Skip to content

Commit 3a88524

Browse files
committed
Updated Rector to commit d50c1f3b642e747724eec2e134653524ba7ee921
rectorphp/rector-src@d50c1f3 [Transform] Follow parent construct before add new param on StaticCallToMethodCallRector (#6854)
1 parent 3808f70 commit 3a88524

2 files changed

Lines changed: 81 additions & 14 deletions

File tree

src/Application/VersionResolver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ final class VersionResolver
1919
* @api
2020
* @var string
2121
*/
22-
public const PACKAGE_VERSION = 'ea0c50398d51467297a671b31b4508ae696c95bb';
22+
public const PACKAGE_VERSION = 'd50c1f3b642e747724eec2e134653524ba7ee921';
2323
/**
2424
* @api
2525
* @var string
2626
*/
27-
public const RELEASE_DATE = '2025-04-21 17:02:35';
27+
public const RELEASE_DATE = '2025-04-22 15:14:41';
2828
/**
2929
* @var int
3030
*/

src/NodeManipulator/ClassDependencyManipulator.php

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
declare (strict_types=1);
44
namespace Rector\NodeManipulator;
55

6+
use PhpParser\Node\Arg;
67
use PhpParser\Node\Expr\Assign;
78
use PhpParser\Node\Expr\StaticCall;
9+
use PhpParser\Node\Expr\Variable;
810
use PhpParser\Node\Name;
911
use PhpParser\Node\Stmt;
1012
use PhpParser\Node\Stmt\Class_;
13+
use PhpParser\Node\Stmt\ClassLike;
1114
use PhpParser\Node\Stmt\ClassMethod;
1215
use PhpParser\Node\Stmt\Expression;
1316
use PhpParser\Node\Stmt\Property;
@@ -17,6 +20,7 @@
1720
use Rector\NodeAnalyzer\PropertyPresenceChecker;
1821
use Rector\NodeNameResolver\NodeNameResolver;
1922
use Rector\Php\PhpVersionProvider;
23+
use Rector\PhpParser\AstResolver;
2024
use Rector\PhpParser\Node\NodeFactory;
2125
use Rector\PostRector\ValueObject\PropertyMetadata;
2226
use Rector\Reflection\ReflectionResolver;
@@ -64,7 +68,11 @@ final class ClassDependencyManipulator
6468
* @readonly
6569
*/
6670
private ReflectionResolver $reflectionResolver;
67-
public function __construct(\Rector\NodeManipulator\ClassInsertManipulator $classInsertManipulator, \Rector\NodeManipulator\ClassMethodAssignManipulator $classMethodAssignManipulator, NodeFactory $nodeFactory, \Rector\NodeManipulator\StmtsManipulator $stmtsManipulator, PhpVersionProvider $phpVersionProvider, PropertyPresenceChecker $propertyPresenceChecker, NodeNameResolver $nodeNameResolver, AutowiredClassMethodOrPropertyAnalyzer $autowiredClassMethodOrPropertyAnalyzer, ReflectionResolver $reflectionResolver)
71+
/**
72+
* @readonly
73+
*/
74+
private AstResolver $astResolver;
75+
public function __construct(\Rector\NodeManipulator\ClassInsertManipulator $classInsertManipulator, \Rector\NodeManipulator\ClassMethodAssignManipulator $classMethodAssignManipulator, NodeFactory $nodeFactory, \Rector\NodeManipulator\StmtsManipulator $stmtsManipulator, PhpVersionProvider $phpVersionProvider, PropertyPresenceChecker $propertyPresenceChecker, NodeNameResolver $nodeNameResolver, AutowiredClassMethodOrPropertyAnalyzer $autowiredClassMethodOrPropertyAnalyzer, ReflectionResolver $reflectionResolver, AstResolver $astResolver)
6876
{
6977
$this->classInsertManipulator = $classInsertManipulator;
7078
$this->classMethodAssignManipulator = $classMethodAssignManipulator;
@@ -75,6 +83,44 @@ public function __construct(\Rector\NodeManipulator\ClassInsertManipulator $clas
7583
$this->nodeNameResolver = $nodeNameResolver;
7684
$this->autowiredClassMethodOrPropertyAnalyzer = $autowiredClassMethodOrPropertyAnalyzer;
7785
$this->reflectionResolver = $reflectionResolver;
86+
$this->astResolver = $astResolver;
87+
}
88+
private function resolveConstruct(Class_ $class) : ?ClassMethod
89+
{
90+
/** @var ClassMethod|null $constructorMethod */
91+
$constructorMethod = $class->getMethod(MethodName::CONSTRUCT);
92+
// exists in current class
93+
if ($constructorMethod instanceof ClassMethod) {
94+
return $constructorMethod;
95+
}
96+
// lookup parent, found first found (nearest parent constructor to follow)
97+
$classReflection = $this->reflectionResolver->resolveClassReflection($class);
98+
if (!$classReflection instanceof ClassReflection) {
99+
return null;
100+
}
101+
$ancestors = \array_filter($classReflection->getAncestors(), static fn(ClassReflection $ancestor): bool => $ancestor->getName() !== $classReflection->getName());
102+
foreach ($ancestors as $ancestor) {
103+
if (!$ancestor->hasNativeMethod(MethodName::CONSTRUCT)) {
104+
continue;
105+
}
106+
$parentClass = $this->astResolver->resolveClassFromClassReflection($ancestor);
107+
if (!$parentClass instanceof ClassLike) {
108+
continue;
109+
}
110+
$parentConstructorMethod = $parentClass->getMethod(MethodName::CONSTRUCT);
111+
if (!$parentConstructorMethod instanceof ClassMethod) {
112+
continue;
113+
}
114+
// only if it has parameters to check
115+
// early returns as nearest parent construct
116+
if ($parentConstructorMethod->params === []) {
117+
return null;
118+
}
119+
// reprint parent method node to avoid invalid tokens
120+
$this->nodeFactory->createReprintedNode($parentConstructorMethod);
121+
return $parentConstructorMethod;
122+
}
123+
return null;
78124
}
79125
public function addConstructorDependency(Class_ $class, PropertyMetadata $propertyMetadata) : void
80126
{
@@ -93,9 +139,10 @@ public function addConstructorDependency(Class_ $class, PropertyMetadata $proper
93139
$this->classMethodAssignManipulator->addParameterAndAssignToMethod($autowireClassMethod, $propertyMetadata->getName(), $propertyMetadata->getType(), $assign);
94140
return;
95141
}
142+
$constructClassMethod = $this->resolveConstruct($class);
96143
// add PHP 8.0 promoted property
97144
if ($this->shouldAddPromotedProperty($class, $propertyMetadata)) {
98-
$this->addPromotedProperty($class, $propertyMetadata);
145+
$this->addPromotedProperty($class, $propertyMetadata, $constructClassMethod);
99146
return;
100147
}
101148
$assign = $this->nodeFactory->createPropertyAssignment($propertyMetadata->getName());
@@ -106,15 +153,25 @@ public function addConstructorDependency(Class_ $class, PropertyMetadata $proper
106153
*/
107154
public function addConstructorDependencyWithCustomAssign(Class_ $class, string $name, ?Type $type, Assign $assign) : void
108155
{
109-
/** @var ClassMethod|null $constructorMethod */
110-
$constructorMethod = $class->getMethod(MethodName::CONSTRUCT);
111-
if ($constructorMethod instanceof ClassMethod) {
112-
$this->classMethodAssignManipulator->addParameterAndAssignToMethod($constructorMethod, $name, $type, $assign);
156+
/** @var ClassMethod|null $constructClassMethod */
157+
$constructClassMethod = $this->resolveConstruct($class);
158+
if ($constructClassMethod instanceof ClassMethod) {
159+
if (!$class->getMethod(MethodName::CONSTRUCT) instanceof ClassMethod) {
160+
$parentArgs = [];
161+
foreach ($constructClassMethod->params as $originalParam) {
162+
$parentArgs[] = new Arg(new Variable((string) $this->nodeNameResolver->getName($originalParam->var)));
163+
}
164+
$constructClassMethod->stmts = [new Expression(new StaticCall(new Name(ObjectReference::PARENT), MethodName::CONSTRUCT, $parentArgs))];
165+
$this->classInsertManipulator->addAsFirstMethod($class, $constructClassMethod);
166+
$this->classMethodAssignManipulator->addParameterAndAssignToMethod($constructClassMethod, $name, $type, $assign);
167+
} else {
168+
$this->classMethodAssignManipulator->addParameterAndAssignToMethod($constructClassMethod, $name, $type, $assign);
169+
}
113170
return;
114171
}
115-
$constructorMethod = $this->nodeFactory->createPublicMethod(MethodName::CONSTRUCT);
116-
$this->classMethodAssignManipulator->addParameterAndAssignToMethod($constructorMethod, $name, $type, $assign);
117-
$this->classInsertManipulator->addAsFirstMethod($class, $constructorMethod);
172+
$constructClassMethod = $this->nodeFactory->createPublicMethod(MethodName::CONSTRUCT);
173+
$this->classMethodAssignManipulator->addParameterAndAssignToMethod($constructClassMethod, $name, $type, $assign);
174+
$this->classInsertManipulator->addAsFirstMethod($class, $constructClassMethod);
118175
}
119176
/**
120177
* @api doctrine
@@ -140,16 +197,26 @@ public function addStmtsToConstructorIfNotThereYet(Class_ $class, array $stmts)
140197
}
141198
$classMethod->stmts = \array_merge($stmts, (array) $classMethod->stmts);
142199
}
143-
private function addPromotedProperty(Class_ $class, PropertyMetadata $propertyMetadata) : void
200+
private function addPromotedProperty(Class_ $class, PropertyMetadata $propertyMetadata, ?ClassMethod $constructClassMethod) : void
144201
{
145-
$constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
146202
$param = $this->nodeFactory->createPromotedPropertyParam($propertyMetadata);
147203
if ($constructClassMethod instanceof ClassMethod) {
148204
// parameter is already added
149205
if ($this->hasMethodParameter($constructClassMethod, $propertyMetadata->getName())) {
150206
return;
151207
}
152-
$constructClassMethod->params[] = $param;
208+
// found construct, but only on parent, add to current class
209+
if (!$class->getMethod(MethodName::CONSTRUCT) instanceof ClassMethod) {
210+
$parentArgs = [];
211+
foreach ($constructClassMethod->params as $originalParam) {
212+
$parentArgs[] = new Arg(new Variable((string) $this->nodeNameResolver->getName($originalParam->var)));
213+
}
214+
$constructClassMethod->params[] = $param;
215+
$constructClassMethod->stmts = [new Expression(new StaticCall(new Name(ObjectReference::PARENT), MethodName::CONSTRUCT, $parentArgs))];
216+
$this->classInsertManipulator->addAsFirstMethod($class, $constructClassMethod);
217+
} else {
218+
$constructClassMethod->params[] = $param;
219+
}
153220
} else {
154221
$constructClassMethod = $this->nodeFactory->createPublicMethod(MethodName::CONSTRUCT);
155222
$constructClassMethod->params[] = $param;

0 commit comments

Comments
 (0)