Skip to content

Commit fd6a0f2

Browse files
herndlmondrejmirtes
authored andcommitted
Fix for endless loop detection
1 parent d6412b8 commit fd6a0f2

File tree

4 files changed

+54
-2
lines changed

4 files changed

+54
-2
lines changed

Diff for: src/Analyser/NodeScopeResolver.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -1369,7 +1369,10 @@ private function processStmtNode(
13691369
}
13701370

13711371
$bodyScope = $bodyScope->mergeWith($initScope);
1372+
1373+
$alwaysIterates = TrinaryLogic::createFromBoolean($context->isTopLevel());
13721374
if ($lastCondExpr !== null) {
1375+
$alwaysIterates = $alwaysIterates->and($bodyScope->getType($lastCondExpr)->toBoolean()->isTrue());
13731376
$bodyScope = $this->processExprNode($stmt, $lastCondExpr, $bodyScope, $nodeCallback, ExpressionContext::createDeep())->getTruthyScope();
13741377
}
13751378

@@ -1385,9 +1388,7 @@ private function processStmtNode(
13851388
}
13861389
$finalScope = $finalScope->generalizeWith($loopScope);
13871390

1388-
$alwaysIterates = TrinaryLogic::createFromBoolean($context->isTopLevel());
13891391
if ($lastCondExpr !== null) {
1390-
$alwaysIterates = $alwaysIterates->and($finalScope->getType($lastCondExpr)->toBoolean()->isTrue());
13911392
$finalScope = $finalScope->filterByFalseyValue($lastCondExpr);
13921393
}
13931394

Diff for: tests/PHPStan/Analyser/StatementResultTest.php

+8
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,14 @@ public function dataIsAlwaysTerminating(): array
297297
'for (; "a", "";) { }',
298298
false,
299299
],
300+
[
301+
'for ($c = (0x80 | 0x40); $c & 0x80; $c = $c << 1) { }',
302+
false,
303+
],
304+
[
305+
'for ($i = 0; $i < 10; $i++) { $i = 5; }',
306+
true,
307+
],
300308
[
301309
'do { } while (doFoo());',
302310
false,

Diff for: tests/PHPStan/Rules/DeadCode/UnreachableStatementRuleTest.php

+6
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,10 @@ public function testBug11179(): void
224224
$this->analyse([__DIR__ . '/data/bug-11179.php'], []);
225225
}
226226

227+
public function testBug11992(): void
228+
{
229+
$this->treatPhpDocTypesAsCertain = false;
230+
$this->analyse([__DIR__ . '/data/bug-11992.php'], []);
231+
}
232+
227233
}

Diff for: tests/PHPStan/Rules/DeadCode/data/bug-11992.php

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug11992;
4+
5+
// valid
6+
function exampleA(): void {
7+
$bc = 0;
8+
for ($i = 0; $i < 3; ++$i) {
9+
$bc++;
10+
}
11+
printf("bc: %d\n", $bc);
12+
}
13+
14+
// not valid? Why? this is deterministic even from a static standpoint
15+
function exampleB(): void {
16+
$bc = 0;
17+
for ($c = (0x80 | 0x40); $c & 0x80; $c = $c << 1) {
18+
$bc++;
19+
}
20+
printf("bc: %d\n", $bc);
21+
}
22+
23+
// invalid because valid() is theoretically infinite?
24+
function exampleC(): void {
25+
for (
26+
$it = new \DirectoryIterator('/tmp');
27+
$it->valid();
28+
$it->next()
29+
) {
30+
printf("name: %s\n", $it->getFilename());
31+
}
32+
printf("done\n");
33+
}
34+
35+
exampleA();
36+
exampleB();
37+
exampleC();

0 commit comments

Comments
 (0)