|
9 | 9 | use PhpParser\Node\Expr\Variable; |
10 | 10 | use PhpParser\Node\Stmt; |
11 | 11 | use PhpParser\Node\Stmt\ClassMethod; |
| 12 | +use PhpParser\Node\Stmt\Expression; |
12 | 13 | use PhpParser\Node\Stmt\Foreach_; |
13 | 14 | use PhpParser\NodeVisitor; |
14 | 15 | use PHPStan\Type\ObjectType; |
@@ -132,6 +133,20 @@ public function refactor(Node $node): ?Node |
132 | 133 |
|
133 | 134 | $next = 0; |
134 | 135 | foreach ($node->stmts as $key => $stmt) { |
| 136 | + // already asserted in a previous run? drop the variable to keep the rule idempotent |
| 137 | + $assertedVariableName = $this->matchAssertInstanceOfVariableName($stmt); |
| 138 | + if (is_string($assertedVariableName)) { |
| 139 | + $alreadyAssertedVariableNameToType = $variableNameToTypeCollection->matchByVariableName( |
| 140 | + $assertedVariableName |
| 141 | + ); |
| 142 | + |
| 143 | + if ($alreadyAssertedVariableNameToType instanceof VariableNameToType) { |
| 144 | + $variableNameToTypeCollection->remove($alreadyAssertedVariableNameToType); |
| 145 | + } |
| 146 | + |
| 147 | + continue; |
| 148 | + } |
| 149 | + |
135 | 150 | // has callable on nullable variable of already collected name? |
136 | 151 | $matchedNullableVariableNameToType = $this->matchedNullableArgumentNameToType( |
137 | 152 | $stmt, |
@@ -224,4 +239,36 @@ private function matchedNullableArgumentNameToType( |
224 | 239 |
|
225 | 240 | return $matchedNullableVariableNameToType; |
226 | 241 | } |
| 242 | + |
| 243 | + private function matchAssertInstanceOfVariableName(Stmt $stmt): ?string |
| 244 | + { |
| 245 | + if (! $stmt instanceof Expression) { |
| 246 | + return null; |
| 247 | + } |
| 248 | + |
| 249 | + if (! $stmt->expr instanceof MethodCall) { |
| 250 | + return null; |
| 251 | + } |
| 252 | + |
| 253 | + $methodCall = $stmt->expr; |
| 254 | + if (! $this->isName($methodCall->name, 'assertInstanceOf')) { |
| 255 | + return null; |
| 256 | + } |
| 257 | + |
| 258 | + $args = $methodCall->getArgs(); |
| 259 | + if (! isset($args[1])) { |
| 260 | + return null; |
| 261 | + } |
| 262 | + |
| 263 | + if (! $args[1]->value instanceof Variable) { |
| 264 | + return null; |
| 265 | + } |
| 266 | + |
| 267 | + $variableName = $this->getName($args[1]->value); |
| 268 | + if (! is_string($variableName)) { |
| 269 | + return null; |
| 270 | + } |
| 271 | + |
| 272 | + return $variableName; |
| 273 | + } |
227 | 274 | } |
0 commit comments