Skip to content

Commit 1f66bb5

Browse files
committed
Allow process multiple UnreachableStatementNode on NodeScopeResolver::processNodes()
1 parent aa4a123 commit 1f66bb5

File tree

3 files changed

+48
-13
lines changed

3 files changed

+48
-13
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -308,12 +308,10 @@ public function processNodes(
308308
}
309309

310310
$alreadyTerminated = true;
311-
$nextStmt = $this->getFirstUnreachableNode(array_slice($nodes, $i + 1), true);
312-
if (!$nextStmt instanceof Node\Stmt) {
313-
continue;
311+
$nextStmts = $this->getNextUnreachableStatements(array_slice($nodes, $i + 1), true);
312+
foreach ($nextStmts as $nextStmt) {
313+
$nodeCallback(new UnreachableStatementNode($nextStmt), $scope);
314314
}
315-
316-
$nodeCallback(new UnreachableStatementNode($nextStmt), $scope);
317315
}
318316
}
319317

@@ -400,11 +398,10 @@ public function processStmtNodes(
400398
}
401399

402400
$alreadyTerminated = true;
403-
$nextStmt = $this->getFirstUnreachableNode(array_slice($stmts, $i + 1), $parentNode instanceof Node\Stmt\Namespace_);
404-
if ($nextStmt === null) {
405-
continue;
401+
$nextStmts = $this->getNextUnreachableStatements(array_slice($stmts, $i + 1), $parentNode instanceof Node\Stmt\Namespace_);
402+
foreach ($nextStmts as $nextStmt) {
403+
$nodeCallback(new UnreachableStatementNode($nextStmt), $scope);
406404
}
407-
$nodeCallback(new UnreachableStatementNode($nextStmt), $scope);
408405
}
409406

410407
$statementResult = new StatementResult($scope, $hasYield, $alreadyTerminated, $exitPoints, $throwPoints, $impurePoints);
@@ -6199,20 +6196,24 @@ private function getPhpDocReturnType(ResolvedPhpDocBlock $resolvedPhpDoc, Type $
61996196
/**
62006197
* @template T of Node
62016198
* @param array<T> $nodes
6202-
* @return T|null
6199+
* @return Node\Stmt[]
62036200
*/
6204-
private function getFirstUnreachableNode(array $nodes, bool $earlyBinding): ?Node
6201+
private function getNextUnreachableStatements(array $nodes, bool $earlyBinding): array
62056202
{
6203+
$stmts = [];
62066204
foreach ($nodes as $node) {
62076205
if ($node instanceof Node\Stmt\Nop) {
62086206
continue;
62096207
}
62106208
if ($earlyBinding && ($node instanceof Node\Stmt\Function_ || $node instanceof Node\Stmt\ClassLike || $node instanceof Node\Stmt\HaltCompiler)) {
62116209
continue;
62126210
}
6213-
return $node;
6211+
if (! $node instanceof Node\Stmt) {
6212+
continue;
6213+
}
6214+
$stmts[] = $node;
62146215
}
6215-
return null;
6216+
return $stmts;
62166217
}
62176218

62186219
}

tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,23 @@ public function testBug11992(): void
230230
$this->analyse([__DIR__ . '/data/bug-11992.php'], []);
231231
}
232232

233+
public function testMultipleUnreachable(): void
234+
{
235+
$this->treatPhpDocTypesAsCertain = true;
236+
$this->analyse([__DIR__ . '/data/multiple_unreachable.php'], [
237+
[
238+
'Unreachable statement - code above always terminates.',
239+
12,
240+
],
241+
[
242+
'Unreachable statement - code above always terminates.',
243+
13,
244+
],
245+
[
246+
'Unreachable statement - code above always terminates.',
247+
14,
248+
],
249+
]);
250+
}
251+
233252
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
/**
4+
* @param 'foo' $foo
5+
*/
6+
function foo($foo)
7+
{
8+
if ($foo === 'foo') {
9+
return 1;
10+
}
11+
12+
echo 'statement 1';
13+
echo 'statement 2';
14+
echo 'statement 3';
15+
}

0 commit comments

Comments
 (0)