|
8 | 8 | use PhpParser\Node\Expr; |
9 | 9 | use PhpParser\Node\Expr\ArrayDimFetch; |
10 | 10 | use PhpParser\Node\Expr\Assign; |
| 11 | +use PhpParser\Node\Expr\MethodCall; |
11 | 12 | use PhpParser\Node\Stmt\Class_; |
12 | 13 | use PhpParser\Node\Stmt\ClassMethod; |
| 14 | +use PhpParser\Node\Stmt\Expression; |
13 | 15 | use PhpParser\Node\Stmt\Return_; |
14 | 16 | use Rector\Configuration\Parameter\FeatureFlags; |
15 | 17 | use Rector\NodeAnalyzer\PropertyFetchAnalyzer; |
@@ -85,7 +87,7 @@ public function refactor(Node $node): ?Node |
85 | 87 | } |
86 | 88 |
|
87 | 89 | // early return can skip the assign, so the default value is still needed |
88 | | - if ($this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($constructClassMethod, Return_::class)) { |
| 90 | + if ($this->hasEarlyReturn($node, $constructClassMethod)) { |
89 | 91 | return null; |
90 | 92 | } |
91 | 93 |
|
@@ -138,6 +140,47 @@ public function refactor(Node $node): ?Node |
138 | 140 | return null; |
139 | 141 | } |
140 | 142 |
|
| 143 | + /** |
| 144 | + * The constructor itself, or any local method it calls, can skip the assign with an early return |
| 145 | + */ |
| 146 | + private function hasEarlyReturn(Class_ $class, ClassMethod $constructClassMethod): bool |
| 147 | + { |
| 148 | + if ($this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($constructClassMethod, Return_::class)) { |
| 149 | + return true; |
| 150 | + } |
| 151 | + |
| 152 | + foreach ((array) $constructClassMethod->stmts as $stmt) { |
| 153 | + if (! $stmt instanceof Expression) { |
| 154 | + continue; |
| 155 | + } |
| 156 | + |
| 157 | + if (! $stmt->expr instanceof MethodCall) { |
| 158 | + continue; |
| 159 | + } |
| 160 | + |
| 161 | + $methodCall = $stmt->expr; |
| 162 | + if (! $this->isName($methodCall->var, 'this')) { |
| 163 | + continue; |
| 164 | + } |
| 165 | + |
| 166 | + $methodName = $this->getName($methodCall->name); |
| 167 | + if ($methodName === null) { |
| 168 | + continue; |
| 169 | + } |
| 170 | + |
| 171 | + $calledClassMethod = $class->getMethod($methodName); |
| 172 | + if (! $calledClassMethod instanceof ClassMethod) { |
| 173 | + continue; |
| 174 | + } |
| 175 | + |
| 176 | + if ($this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($calledClassMethod, Return_::class)) { |
| 177 | + return true; |
| 178 | + } |
| 179 | + } |
| 180 | + |
| 181 | + return false; |
| 182 | + } |
| 183 | + |
141 | 184 | private function isAssignedViaArrayDimFetch(Class_ $class, string $propertyName): bool |
142 | 185 | { |
143 | 186 | return $this->betterNodeFinder->findFirst($class, function (Node $subNode) use ($propertyName): bool { |
|
0 commit comments