Skip to content

Commit 8c7cf85

Browse files
committed
Fix CatchWithUnthrownExceptionRule for $expr::foo()
1 parent 8463afd commit 8c7cf85

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,9 +1995,23 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
19951995
$hasYield = false;
19961996
$throwPoints = [];
19971997
if ($expr->class instanceof Expr) {
1998+
$objectClasses = TypeUtils::getDirectClassNames($scope->getType($expr->class));
1999+
if (count($objectClasses) !== 1) {
2000+
$objectClasses = TypeUtils::getDirectClassNames($scope->getType(new New_($expr->class)));
2001+
}
2002+
if (count($objectClasses) === 1) {
2003+
$objectExprResult = $this->processExprNode(new StaticCall(new Name($objectClasses[0]), $expr->name, []), $scope, static function (): void {
2004+
}, $context->enterDeep());
2005+
$additionalThrowPoints = $objectExprResult->getThrowPoints();
2006+
} else {
2007+
$additionalThrowPoints = [ThrowPoint::createImplicit($scope)];
2008+
}
19982009
$classResult = $this->processExprNode($expr->class, $scope, $nodeCallback, $context->enterDeep());
19992010
$hasYield = $classResult->hasYield();
20002011
$throwPoints = array_merge($throwPoints, $classResult->getThrowPoints());
2012+
foreach ($additionalThrowPoints as $throwPoint) {
2013+
$throwPoints[] = $throwPoint;
2014+
}
20012015
$scope = $classResult->getScope();
20022016
}
20032017

tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,18 @@ public function testBug4806(): void
6868
]);
6969
}
7070

71+
public function testBug4805(): void
72+
{
73+
$this->analyse([__DIR__ . '/data/bug-4805.php'], [
74+
[
75+
'Dead catch - OutOfBoundsException is never thrown in the try block.',
76+
44,
77+
],
78+
[
79+
'Dead catch - OutOfBoundsException is never thrown in the try block.',
80+
66,
81+
],
82+
]);
83+
}
84+
7185
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
namespace Bug4805;
4+
5+
final class Foo
6+
{
7+
/**
8+
* @throws \OutOfBoundsException
9+
*/
10+
public static function canThrow(bool $throw): self
11+
{
12+
if($throw){
13+
throw new \OutOfBoundsException('Ooops');
14+
}
15+
return new self();
16+
}
17+
18+
/**
19+
* @throws void
20+
*/
21+
public static function cannotThrow(bool $throw): void
22+
{
23+
24+
}
25+
}
26+
27+
final class Bar
28+
{
29+
public static function doFoo(Foo $foo, bool $flag): bool
30+
{
31+
try{
32+
$foo::canThrow($flag);
33+
return true;
34+
}catch(\OutOfBoundsException $e){
35+
return false;
36+
}
37+
}
38+
39+
public static function doFoo2(Foo $foo, bool $flag): bool
40+
{
41+
try{
42+
$foo::cannotThrow($flag);
43+
return true;
44+
}catch(\OutOfBoundsException $e){
45+
return false;
46+
}
47+
}
48+
49+
/** @param class-string<Foo> $foo */
50+
public static function doBar(string $foo, bool $flag): bool
51+
{
52+
try{
53+
$foo::canThrow($flag);
54+
return true;
55+
} catch(\OutOfBoundsException $e){
56+
return false;
57+
}
58+
}
59+
60+
/** @param class-string<Foo> $foo */
61+
public static function doBar2(string $foo, bool $flag): bool
62+
{
63+
try{
64+
$foo::cannotThrow($flag);
65+
return true;
66+
} catch(\OutOfBoundsException $e){
67+
return false;
68+
}
69+
}
70+
71+
/** @param class-string $foo */
72+
public static function doBaz(string $foo, bool $flag): bool
73+
{
74+
try{
75+
$foo::canThrow($flag);
76+
return true;
77+
} catch(\OutOfBoundsException $e){
78+
return false;
79+
}
80+
}
81+
82+
/** @param class-string $foo */
83+
public static function doBaz2(string $foo, bool $flag): bool
84+
{
85+
try{
86+
$foo::cannotThrow($flag);
87+
return true;
88+
} catch(\OutOfBoundsException $e){
89+
return false;
90+
}
91+
}
92+
93+
public static function doLorem(string $foo, bool $flag): bool
94+
{
95+
try{
96+
$foo::canThrow($flag);
97+
return true;
98+
} catch(\OutOfBoundsException $e){
99+
return false;
100+
}
101+
}
102+
103+
public static function doLorem2(string $foo, bool $flag): bool
104+
{
105+
try{
106+
$foo::cannotThrow($flag);
107+
return true;
108+
} catch(\OutOfBoundsException $e){
109+
return false;
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)