Skip to content

Commit d59528f

Browse files
authored
Option for reporting all unused catch statements (#13)
1 parent 15d7db5 commit d59528f

File tree

7 files changed

+136
-7
lines changed

7 files changed

+136
-7
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ includes:
4444
4545
parameters:
4646
exceptionRules:
47+
reportUnusedCatchesOfUncheckedExceptions: false
4748
checkedExceptions:
4849
- RuntimeException
4950
```

extension.neon

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
parameters:
22
exceptionRules:
3-
reportMaybes: true
3+
reportUnusedCatchesOfUncheckedExceptions: false
44
checkedExceptions: []
55
uncheckedExceptions: []
66
methodThrowTypeDeclarations: []
@@ -22,6 +22,8 @@ services:
2222

2323
-
2424
class: Pepakriz\PHPStanExceptionRules\Rules\ThrowsPhpDocRule
25+
arguments:
26+
reportUnusedCatchesOfUncheckedExceptions: %exceptionRules.reportUnusedCatchesOfUncheckedExceptions%
2527
tags: [phpstan.rules.rule]
2628

2729
-

phpstan.neon.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ parameters:
1212
- %rootDir%/../../../tests/*/data/*
1313

1414
exceptionRules:
15+
reportUnusedCatchesOfUncheckedExceptions: true
1516
uncheckedExceptions:
1617
- LogicException
1718
- PHPStan\ShouldNotHappenException

src/Rules/ThrowsPhpDocRule.php

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,23 @@ class ThrowsPhpDocRule implements Rule
6767
*/
6868
private $throwsScope;
6969

70+
/**
71+
* @var bool
72+
*/
73+
private $reportUnusedCatchesOfUncheckedExceptions;
74+
7075
public function __construct(
7176
CheckedExceptionService $checkedExceptionService,
7277
DynamicThrowTypeService $dynamicThrowTypeService,
73-
Broker $broker
78+
Broker $broker,
79+
bool $reportUnusedCatchesOfUncheckedExceptions
7480
)
7581
{
7682
$this->checkedExceptionService = $checkedExceptionService;
7783
$this->dynamicThrowTypeService = $dynamicThrowTypeService;
7884
$this->broker = $broker;
7985
$this->throwsScope = new ThrowsScope();
86+
$this->reportUnusedCatchesOfUncheckedExceptions = $reportUnusedCatchesOfUncheckedExceptions;
8087
}
8188

8289
public function getNodeType(): string
@@ -391,13 +398,19 @@ private function processCatch(Catch_ $node): array
391398
}
392399
}
393400

394-
$caughtExceptions = $this->checkedExceptionService->filterCheckedExceptions($caughtExceptions);
395-
if (count($caughtExceptions) > 0) {
401+
$exceptionClass = $type->toString();
402+
if (
403+
!$this->reportUnusedCatchesOfUncheckedExceptions
404+
&& !$this->checkedExceptionService->isCheckedException($exceptionClass)
405+
) {
396406
continue;
397407
}
398408

399-
$exceptionClass = $type->toString();
400-
if (!$this->checkedExceptionService->isCheckedException($exceptionClass)) {
409+
if (!$this->reportUnusedCatchesOfUncheckedExceptions) {
410+
$caughtExceptions = $this->checkedExceptionService->filterCheckedExceptions($caughtExceptions);
411+
}
412+
413+
if (count($caughtExceptions) > 0) {
401414
continue;
402415
}
403416

tests/src/Rules/ThrowsPhpDocRuleTest.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
class ThrowsPhpDocRuleTest extends RuleTestCase
1616
{
1717

18+
/**
19+
* @var bool
20+
*/
21+
private $reportUnusedCatchesOfUncheckedExceptions = false;
22+
1823
protected function getRule(): Rule
1924
{
2025
$throwsRule = new ThrowsPhpDocRule(
@@ -31,7 +36,8 @@ protected function getRule(): Rule
3136
], [
3237
new DynamicFunctionExtension(),
3338
]),
34-
$this->createBroker()
39+
$this->createBroker(),
40+
$this->reportUnusedCatchesOfUncheckedExceptions
3541
);
3642

3743
return $throwsRule;
@@ -57,6 +63,12 @@ public function testUnusedCatches(): void
5763
$this->analyse(__DIR__ . '/data/unused-catches.php');
5864
}
5965

66+
public function testAllUnusedCatches(): void
67+
{
68+
$this->reportUnusedCatchesOfUncheckedExceptions = true;
69+
$this->analyse(__DIR__ . '/data/unused-catches-all.php');
70+
}
71+
6072
public function testIterators(): void
6173
{
6274
$this->analyse(__DIR__ . '/data/iterators.php');
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Pepakriz\PHPStanExceptionRules\Rules\UnusedCatchesAll;
4+
5+
use LogicException;
6+
use RuntimeException;
7+
8+
class FooException extends RuntimeException
9+
{
10+
11+
}
12+
13+
class UnusedCatches
14+
{
15+
16+
public function nestedUnusedCatch(): void
17+
{
18+
try {
19+
try {
20+
throw new FooException();
21+
} catch (LogicException $e) { // error: LogicException is never thrown in the corresponding try block
22+
23+
} catch (RuntimeException $e) {
24+
25+
}
26+
} catch (FooException $e) { // error: Pepakriz\PHPStanExceptionRules\Rules\UnusedCatchesAll\FooException is never thrown in the corresponding try block
27+
28+
}
29+
}
30+
31+
public function correctCatchMethodCall(): void
32+
{
33+
try {
34+
$this->someVoidMethod();
35+
} catch (LogicException $e) { // error: LogicException is never thrown in the corresponding try block
36+
37+
} catch (RuntimeException $e) { // error: RuntimeException is never thrown in the corresponding try block
38+
39+
}
40+
}
41+
42+
public function correctCatchMethodCallWithThrows(): void
43+
{
44+
try {
45+
$this->throwLogic();
46+
} catch (LogicException $e) {
47+
48+
} catch (RuntimeException $e) { // error: RuntimeException is never thrown in the corresponding try block
49+
50+
}
51+
}
52+
53+
private function someVoidMethod(): void
54+
{
55+
}
56+
57+
/**
58+
* @throws LogicException
59+
*/
60+
private function throwLogic(): void // error: Unused @throws LogicException annotation
61+
{
62+
throw new LogicException();
63+
}
64+
65+
}
66+

tests/src/Rules/data/unused-catches.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,39 @@ public function nestedUnusedCatch(): void
7171
}
7272
}
7373

74+
public function correctCatchMethodCall(): void
75+
{
76+
try {
77+
$this->someVoidMethod();
78+
} catch (LogicException $e) {
79+
80+
} catch (RuntimeException $e) { // error: RuntimeException is never thrown in the corresponding try block
81+
82+
}
83+
}
84+
85+
public function correctCatchMethodCallWithThrows(): void
86+
{
87+
try {
88+
$this->throwLogic();
89+
} catch (LogicException $e) {
90+
91+
} catch (RuntimeException $e) { // error: RuntimeException is never thrown in the corresponding try block
92+
93+
}
94+
}
95+
96+
private function someVoidMethod(): void
97+
{
98+
}
99+
100+
/**
101+
* @throws LogicException
102+
*/
103+
private function throwLogic(): void // error: Unused @throws LogicException annotation
104+
{
105+
throw new LogicException();
106+
}
107+
74108
}
75109

0 commit comments

Comments
 (0)