Skip to content

Commit d32942a

Browse files
authored
Fix dead catch when iterating objects
1 parent 6525d68 commit d32942a

File tree

3 files changed

+82
-0
lines changed

3 files changed

+82
-0
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138
use PHPStan\Type\UnionType;
139139
use PHPStan\Type\VoidType;
140140
use Throwable;
141+
use Traversable;
141142
use function array_fill_keys;
142143
use function array_filter;
143144
use function array_key_exists;
@@ -823,6 +824,9 @@ private function processStmtNode(
823824
if (!$isIterableAtLeastOnce->no()) {
824825
$throwPoints = array_merge($throwPoints, $finalScopeResult->getThrowPoints());
825826
}
827+
if (!(new ObjectType(Traversable::class))->isSuperTypeOf($scope->getType($stmt->expr))->no()) {
828+
$throwPoints[] = ThrowPoint::createImplicit($scope, $stmt->expr);
829+
}
826830

827831
return new StatementResult(
828832
$finalScope,

tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,20 @@ public function testFirstClassCallables(): void
196196
]);
197197
}
198198

199+
public function testBug5903(): void
200+
{
201+
$this->analyse([__DIR__ . '/data/bug-5903.php'], [
202+
[
203+
'Dead catch - Throwable is never thrown in the try block.',
204+
47,
205+
],
206+
[
207+
'Dead catch - Throwable is never thrown in the try block.',
208+
54,
209+
],
210+
]);
211+
}
212+
199213
public function testBug6262(): void
200214
{
201215
$this->analyse([__DIR__ . '/data/bug-6262.php'], []);
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
namespace Bug5903;
4+
5+
class Test
6+
{
7+
/** @var \Traversable<string> */
8+
protected $traversable;
9+
/** @var \Iterator<string> */
10+
protected $iterator;
11+
/** @var iterable<string> */
12+
protected $iterable;
13+
/** @var array<string> */
14+
protected $array;
15+
/** @var array<string>|null */
16+
protected $maybeArray;
17+
/** @var \Iterator<string>|null */
18+
protected $maybeIterable;
19+
20+
public function foo()
21+
{
22+
try {
23+
foreach ($this->traversable as $val) {
24+
echo $val;
25+
}
26+
} catch (\Throwable $e) {
27+
}
28+
29+
try {
30+
foreach ($this->iterator as $val) {
31+
echo $val;
32+
}
33+
} catch (\Throwable $e) {
34+
}
35+
36+
try {
37+
foreach ($this->iterable as $val) {
38+
echo $val;
39+
}
40+
} catch (\Throwable $e) {
41+
}
42+
43+
try {
44+
foreach ($this->array as $val) {
45+
echo $val;
46+
}
47+
} catch (\Throwable $e) {
48+
}
49+
50+
try {
51+
foreach ($this->maybeArray as $val) {
52+
echo $val;
53+
}
54+
} catch (\Throwable $e) {
55+
}
56+
57+
try {
58+
foreach ($this->maybeIterable as $val) {
59+
echo $val;
60+
}
61+
} catch (\Throwable $e) {
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)