Sitelet https://github.com/phpstan/phpstan-src/pull/2279/files
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ public function processNodes(
callable $nodeCallback,
): void
{
$nodesCount = count($nodes);
foreach ($nodes as $i => $node) {
if (!$node instanceof Node\Stmt) {
continue;
Expand All @@ -252,14 +251,12 @@ public function processNodes(
continue;
}

if ($i < $nodesCount - 1) {
$nextStmt = $nodes[$i + 1];
if (!$nextStmt instanceof Node\Stmt) {
continue;
}

$nodeCallback(new UnreachableStatementNode($nextStmt), $scope);
$nextStmt = $this->getFirstNonNopNode(array_slice($nodes, $i + 1));
if (!$nextStmt instanceof Node\Stmt) {
continue;
}

$nodeCallback(new UnreachableStatementNode($nextStmt), $scope);
break;
}
}
Expand Down Expand Up @@ -323,8 +320,8 @@ public function processStmtNodes(
}

$alreadyTerminated = true;
if ($i < $stmtCount - 1) {
$nextStmt = $stmts[$i + 1];
$nextStmt = $this->getFirstNonNopNode(array_slice($stmts, $i + 1));
if ($nextStmt !== null) {
$nodeCallback(new UnreachableStatementNode($nextStmt), $scope);
}
break;
Expand Down Expand Up @@ -4365,4 +4362,20 @@ private function getPhpDocReturnType(ResolvedPhpDocBlock $resolvedPhpDoc, Type $
return null;
}

/**
* @template T of Node
* @param array<T> $nodes
* @return T
*/
private function getFirstNonNopNode(array $nodes): ?Node
{
foreach ($nodes as $node) {
if (!$node instanceof Node\Stmt\Nop) {
return $node;
}
}

return null;
}

}
4 changes: 0 additions & 4 deletions src/Rules/DeadCode/UnreachableStatementRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ public function getNodeType(): string

public function processNode(Node $node, Scope $scope): array
{
if ($node->getOriginalStatement() instanceof Node\Stmt\Nop) {
return [];
}

return [
RuleErrorBuilder::message('Unreachable statement - code above always terminates.')
->identifier('deadCode.unreachableStatement')
Expand Down
23 changes: 21 additions & 2 deletions tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,19 @@ public function testRule(): void
],
[
'Unreachable statement - code above always terminates.',
71,
44,
],
[
'Unreachable statement - code above always terminates.',
135,
58,
],
[
'Unreachable statement - code above always terminates.',
93,
],
[
'Unreachable statement - code above always terminates.',
157,
],
]);
}
Expand Down Expand Up @@ -141,4 +149,15 @@ public function testBug8620(): void
$this->analyse([__DIR__ . '/data/bug-8620.php'], []);
}

public function testBug8966(): void
{
$this->treatPhpDocTypesAsCertain = true;
$this->analyse([__DIR__ . '/data/bug-8966.php'], [
[
'Unreachable statement - code above always terminates.',
8,
],
]);
}

}
8 changes: 8 additions & 0 deletions tests/PHPStan/Rules/DeadCode/data/bug-8966.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

exit;

// empty statement
;

echo 'unreachable';
22 changes: 22 additions & 0 deletions tests/PHPStan/Rules/DeadCode/data/unreachable.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,28 @@ public function doLorem()
// this is why...
}

public function doLorem2(string $foo)
{
return;
// this is why...

echo $foo;
}

public function doLorem3()
{
return;
;
}

public function doLorem4(string $foo)
{
return;
;

echo $foo;
}

/**
* @param \stdClass[] $all
*/
Expand Down