|
5 | 5 | namespace Rector\DeadCode\Rector\ClassMethod; |
6 | 6 |
|
7 | 7 | use PhpParser\Node; |
| 8 | +use PhpParser\Node\Arg; |
| 9 | +use PhpParser\Node\Expr\StaticCall; |
| 10 | +use PhpParser\Node\Expr\Variable; |
| 11 | +use PhpParser\Node\Stmt; |
8 | 12 | use PhpParser\Node\Stmt\ClassMethod; |
| 13 | +use PhpParser\Node\Stmt\Expression; |
9 | 14 | use PhpParser\NodeVisitor; |
10 | 15 | use PHPStan\Reflection\ClassReflection; |
11 | 16 | use Rector\Enum\ObjectReference; |
12 | | -use Rector\NodeAnalyzer\ArgsAnalyzer; |
13 | | -use Rector\NodeAnalyzer\ExprAnalyzer; |
14 | | -use Rector\PhpParser\Node\Value\ValueResolver; |
15 | 17 | use Rector\PHPStan\ScopeFetcher; |
16 | 18 | use Rector\Rector\AbstractRector; |
17 | | -use Rector\Reflection\ReflectionResolver; |
18 | 19 | use Rector\ValueObject\MethodName; |
19 | 20 | use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; |
20 | 21 | use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; |
|
24 | 25 | */ |
25 | 26 | final class RemoveParentDelegatingConstructorRector extends AbstractRector |
26 | 27 | { |
27 | | - public function __construct( |
28 | | - private readonly ReflectionResolver $reflectionResolver, |
29 | | - private readonly ArgsAnalyzer $argsAnalyzer, |
30 | | - private readonly ValueResolver $valueResolver, |
31 | | - private readonly ExprAnalyzer $exprAnalyzer |
32 | | - ) { |
33 | | - } |
34 | | - |
35 | 28 | public function getRuleDefinition(): RuleDefinition |
36 | 29 | { |
37 | 30 | return new RuleDefinition( |
@@ -89,48 +82,89 @@ public function refactor(Node $node): ?int |
89 | 82 | return null; |
90 | 83 | } |
91 | 84 |
|
92 | | - if (count($node->stmts) !== 1) { |
| 85 | + if ($node->stmts === null || count($node->stmts) !== 1) { |
93 | 86 | return null; |
94 | 87 | } |
95 | 88 |
|
96 | | - $scope = ScopeFetcher::fetch($node); |
97 | | - $classReflection = $scope->getClassReflection(); |
98 | | - if (! $classReflection->getParentClass() instanceof ClassReflection) { |
| 89 | + if (! $this->hasParentClassWithConstructor($node)) { |
99 | 90 | return null; |
100 | 91 | } |
101 | 92 |
|
102 | | - $parentClassReflection = $classReflection->getParentClass(); |
103 | | - if (! $parentClassReflection->hasConstructor()) { |
| 93 | + $soleStmt = $node->stmts[0]; |
| 94 | + $parentCallArgs = $this->matchParentConstructorCallArgs($soleStmt); |
| 95 | + if ($parentCallArgs === null) { |
104 | 96 | return null; |
105 | 97 | } |
106 | 98 |
|
107 | | - // $parentClassReflectionConstructor = $parentClassReflection->getConstructor(); |
108 | | - |
109 | | - $soleStmt = $node->stmts[0]; |
110 | | - if (! $soleStmt instanceof Node\Stmt\Expression) { |
| 99 | + $constructorParams = $node->getParams(); |
| 100 | + if (count($constructorParams) !== count($parentCallArgs)) { |
111 | 101 | return null; |
112 | 102 | } |
113 | 103 |
|
114 | | - if (! $soleStmt->expr instanceof Node\Expr\StaticCall) { |
| 104 | + // match passed names in the same order |
| 105 | + $paramNames = []; |
| 106 | + foreach ($constructorParams as $constructorParam) { |
| 107 | + $paramNames[] = $this->getName($constructorParam->var); |
| 108 | + } |
| 109 | + |
| 110 | + $argNames = []; |
| 111 | + foreach ($parentCallArgs as $parentCallArg) { |
| 112 | + $argValue = $parentCallArg->value; |
| 113 | + if (! $argValue instanceof Variable) { |
| 114 | + return null; |
| 115 | + } |
| 116 | + |
| 117 | + $argNames[] = $this->getName($argValue); |
| 118 | + } |
| 119 | + |
| 120 | + if ($paramNames !== $argNames) { |
115 | 121 | return null; |
116 | 122 | } |
117 | 123 |
|
118 | | - $staticCall = $soleStmt->expr; |
119 | | - if (! $this->isName($staticCall->class, ObjectReference::PARENT)) { |
| 124 | + return NodeVisitor::REMOVE_NODE; |
| 125 | + } |
| 126 | + |
| 127 | + private function hasParentClassWithConstructor(ClassMethod $classMethod): bool |
| 128 | + { |
| 129 | + $scope = ScopeFetcher::fetch($classMethod); |
| 130 | + |
| 131 | + $classReflection = $scope->getClassReflection(); |
| 132 | + if (! $classReflection instanceof ClassReflection) { |
| 133 | + return false; |
| 134 | + } |
| 135 | + |
| 136 | + $parentClassReflection = $classReflection->getParentClass(); |
| 137 | + if (! $parentClassReflection instanceof ClassReflection) { |
| 138 | + return false; |
| 139 | + } |
| 140 | + |
| 141 | + return $parentClassReflection->hasConstructor(); |
| 142 | + } |
| 143 | + |
| 144 | + /** |
| 145 | + * Looking for parent::__construct() |
| 146 | + * |
| 147 | + * @return Arg[]|null |
| 148 | + */ |
| 149 | + private function matchParentConstructorCallArgs(Stmt $stmt): ?array |
| 150 | + { |
| 151 | + if (! $stmt instanceof Expression) { |
120 | 152 | return null; |
121 | 153 | } |
122 | 154 |
|
123 | | - if (! $this->isName($staticCall->name, MethodName::CONSTRUCT)) { |
| 155 | + if (! $stmt->expr instanceof StaticCall) { |
124 | 156 | return null; |
125 | 157 | } |
126 | 158 |
|
127 | | - $constructorParams = $node->getParams(); |
128 | | - $parentCallArgs = $staticCall->getArgs(); |
| 159 | + $staticCall = $stmt->expr; |
| 160 | + if (! $this->isName($staticCall->class, ObjectReference::PARENT)) { |
| 161 | + return null; |
| 162 | + } |
129 | 163 |
|
130 | | - if (count($constructorParams) !== count($parentCallArgs)) { |
| 164 | + if (! $this->isName($staticCall->name, MethodName::CONSTRUCT)) { |
131 | 165 | return null; |
132 | 166 | } |
133 | 167 |
|
134 | | - return NodeVisitor::REMOVE_NODE; |
| 168 | + return $staticCall->getArgs(); |
135 | 169 | } |
136 | 170 | } |
0 commit comments