Skip to content

Commit 00a2eea

Browse files
committed
Functions and methods returning exceptions do not have implicit @throws
1 parent c540b44 commit 00a2eea

2 files changed

Lines changed: 88 additions & 3 deletions

File tree

src/Analyser/NodeScopeResolver.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,7 +1779,10 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
17791779
$throwPoints[] = ThrowPoint::createExplicit($scope, $throwType, true);
17801780
}
17811781
} elseif ($this->implicitThrows) {
1782-
$throwPoints[] = ThrowPoint::createImplicit($scope);
1782+
$functionReturnedType = $scope->getType($expr);
1783+
if (!(new ObjectType(\Throwable::class))->isSuperTypeOf($functionReturnedType)->yes()) {
1784+
$throwPoints[] = ThrowPoint::createImplicit($scope);
1785+
}
17831786
}
17841787
} else {
17851788
$throwPoints[] = ThrowPoint::createImplicit($scope);
@@ -1953,7 +1956,10 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
19531956
$throwPoints[] = ThrowPoint::createExplicit($scope, $methodReflection->getThrowType(), true);
19541957
}
19551958
} elseif ($this->implicitThrows) {
1956-
$throwPoints[] = ThrowPoint::createImplicit($scope);
1959+
$methodReturnedType = $scope->getType($expr);
1960+
if (!(new ObjectType(\Throwable::class))->isSuperTypeOf($methodReturnedType)->yes()) {
1961+
$throwPoints[] = ThrowPoint::createImplicit($scope);
1962+
}
19571963
}
19581964
} else {
19591965
$throwPoints[] = ThrowPoint::createImplicit($scope);
@@ -2017,7 +2023,10 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
20172023
$throwPoints[] = ThrowPoint::createExplicit($scope, $throwType, true);
20182024
}
20192025
} elseif ($this->implicitThrows) {
2020-
$throwPoints[] = ThrowPoint::createImplicit($scope);
2026+
$methodReturnedType = $scope->getType($expr);
2027+
if (!(new ObjectType(\Throwable::class))->isSuperTypeOf($methodReturnedType)->yes()) {
2028+
$throwPoints[] = ThrowPoint::createImplicit($scope);
2029+
}
20212030
}
20222031
if (
20232032
$classReflection->getName() === 'Closure'

tests/PHPStan/Analyser/data/throw-points/try-catch.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ public static function myRand(): int
2727

2828
}
2929

30+
public static function createException(): MyInvalidArgumentException
31+
{
32+
33+
}
34+
35+
/**
36+
* @throws MyRuntimeException
37+
*/
38+
public static function createExceptionOrThrow(): MyInvalidArgumentException
39+
{
40+
41+
}
42+
3043
}
3144

3245
function (): void {
@@ -105,3 +118,66 @@ function (): void {
105118
assertVariableCertainty(TrinaryLogic::createYes(), $foo);
106119
}
107120
};
121+
122+
function (): void {
123+
try {
124+
if (Foo::myRand() === 0) {
125+
$foo = 1;
126+
throw Foo::createException();
127+
}
128+
129+
if (Foo::myRand() === 1) {
130+
$bar = 1;
131+
throw Foo::createExceptionOrThrow();
132+
}
133+
} catch (MyInvalidArgumentException $e) {
134+
assertVariableCertainty(TrinaryLogic::createMaybe(), $foo);
135+
assertVariableCertainty(TrinaryLogic::createMaybe(), $bar);
136+
} catch (\Throwable $e) {
137+
assertVariableCertainty(TrinaryLogic::createNo(), $foo);
138+
assertVariableCertainty(TrinaryLogic::createYes(), $bar);
139+
}
140+
};
141+
142+
function (): void {
143+
try {
144+
if (Foo::myRand() === 0) {
145+
$foo = 1;
146+
throw Foo::createException();
147+
}
148+
149+
if (Foo::myRand() === 1) {
150+
$bar = 1;
151+
throw Foo::createExceptionOrThrow();
152+
}
153+
} catch (MyInvalidArgumentException $e) {
154+
assertVariableCertainty(TrinaryLogic::createMaybe(), $foo);
155+
assertVariableCertainty(TrinaryLogic::createMaybe(), $bar);
156+
} catch (\Exception $e) {
157+
assertVariableCertainty(TrinaryLogic::createNo(), $foo);
158+
assertVariableCertainty(TrinaryLogic::createYes(), $bar);
159+
}
160+
};
161+
162+
function (): void {
163+
try {
164+
if (Foo::myRand() === 0) {
165+
$foo = 1;
166+
throw Foo::createException();
167+
}
168+
169+
if (Foo::myRand() === 1) {
170+
$bar = 1;
171+
throw Foo::createExceptionOrThrow();
172+
}
173+
} catch (MyInvalidArgumentException $e) {
174+
assertVariableCertainty(TrinaryLogic::createMaybe(), $foo);
175+
assertVariableCertainty(TrinaryLogic::createMaybe(), $bar);
176+
} catch (\Exception $e) {
177+
assertVariableCertainty(TrinaryLogic::createNo(), $foo);
178+
assertVariableCertainty(TrinaryLogic::createYes(), $bar);
179+
} catch (\Throwable $e) {
180+
assertVariableCertainty(TrinaryLogic::createNo(), $foo);
181+
assertVariableCertainty(TrinaryLogic::createYes(), $bar);
182+
}
183+
};

0 commit comments

Comments
 (0)