Skip to content

Commit d484ea8

Browse files
committed
Fix unreachable code after do-while loop
1 parent 4a392a7 commit d484ea8

File tree

3 files changed

+51
-3
lines changed

3 files changed

+51
-3
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,9 @@ private function processStmtNode(
963963

964964
$bodyScopeResult = $this->processStmtNodes($stmt, $stmt->stmts, $bodyScope, $nodeCallback)->filterOutLoopExitPoints();
965965
$bodyScope = $bodyScopeResult->getScope();
966+
foreach ($bodyScopeResult->getExitPointsByType(Continue_::class) as $continueExitPoint) {
967+
$bodyScope = $bodyScope->mergeWith($continueExitPoint->getScope());
968+
}
966969
$condBooleanType = $bodyScope->getType($stmt->cond)->toBoolean();
967970
$alwaysIterates = $condBooleanType instanceof ConstantBooleanType && $condBooleanType->getValue();
968971

@@ -971,9 +974,6 @@ private function processStmtNode(
971974
} else {
972975
$alwaysTerminating = $bodyScopeResult->isAlwaysTerminating();
973976
}
974-
foreach ($bodyScopeResult->getExitPointsByType(Continue_::class) as $continueExitPoint) {
975-
$bodyScope = $bodyScope->mergeWith($continueExitPoint->getScope());
976-
}
977977
$finalScope = $alwaysTerminating ? $finalScope : $bodyScope->mergeWith($finalScope);
978978
if ($finalScope === null) {
979979
$finalScope = $scope;

tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,10 @@ public function testBug2913(): void
116116
$this->analyse([__DIR__ . '/data/bug-2913.php'], []);
117117
}
118118

119+
public function testBug4370(): void
120+
{
121+
$this->treatPhpDocTypesAsCertain = true;
122+
$this->analyse([__DIR__ . '/data/bug-4370.php'], []);
123+
}
124+
119125
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Bug4370;
4+
5+
interface Lexer
6+
{
7+
public function lex(): int;
8+
}
9+
10+
/**
11+
* This class creates coverage data for the json files in the resources directory
12+
*/
13+
final class P
14+
{
15+
/**
16+
* The codes representing different JSON elements
17+
*
18+
* These come from the Seld\JsonLint\JsonParser class. The values are returned by the lexer when
19+
* the lex() method is called.
20+
*/
21+
private const JSON_OBJECT_START = 17;
22+
private const JSON_OBJECT_END = 18;
23+
24+
/**
25+
* Processes JSON object block that isn't needed for coverage data
26+
*/
27+
public function ignoreObjectBlock(Lexer $lexer): int
28+
{
29+
do {
30+
$code = $lexer->lex();
31+
32+
// recursively ignore nested objects
33+
if ($code !== self::JSON_OBJECT_START) {
34+
continue;
35+
}
36+
37+
$this->ignoreObjectBlock($lexer);
38+
} while ($code !== self::JSON_OBJECT_END);
39+
40+
return $lexer->lex();
41+
}
42+
}

0 commit comments

Comments
 (0)