5
5
use Iterator ;
6
6
use IteratorAggregate ;
7
7
use Pepakriz \PHPStanExceptionRules \CheckedExceptionService ;
8
+ use Pepakriz \PHPStanExceptionRules \DefaultThrowTypeService ;
8
9
use Pepakriz \PHPStanExceptionRules \DynamicThrowTypeService ;
9
10
use Pepakriz \PHPStanExceptionRules \Node \FunctionEnd ;
10
11
use Pepakriz \PHPStanExceptionRules \Node \TryCatchTryEnd ;
11
12
use Pepakriz \PHPStanExceptionRules \ThrowsAnnotationReader ;
13
+ use Pepakriz \PHPStanExceptionRules \UnsupportedClassException ;
14
+ use Pepakriz \PHPStanExceptionRules \UnsupportedFunctionException ;
12
15
use PhpParser \Node ;
13
16
use PhpParser \Node \Expr ;
14
17
use PhpParser \Node \Expr \FuncCall ;
@@ -65,6 +68,11 @@ class ThrowsPhpDocRule implements Rule
65
68
*/
66
69
private $ dynamicThrowTypeService ;
67
70
71
+ /**
72
+ * @var DefaultThrowTypeService
73
+ */
74
+ private $ defaultThrowTypeService ;
75
+
68
76
/**
69
77
* @var ThrowsAnnotationReader
70
78
*/
@@ -93,6 +101,7 @@ class ThrowsPhpDocRule implements Rule
93
101
public function __construct (
94
102
CheckedExceptionService $ checkedExceptionService ,
95
103
DynamicThrowTypeService $ dynamicThrowTypeService ,
104
+ DefaultThrowTypeService $ defaultThrowTypeService ,
96
105
ThrowsAnnotationReader $ throwsAnnotationReader ,
97
106
Broker $ broker ,
98
107
bool $ reportUnusedCatchesOfUncheckedExceptions ,
@@ -101,6 +110,7 @@ public function __construct(
101
110
{
102
111
$ this ->checkedExceptionService = $ checkedExceptionService ;
103
112
$ this ->dynamicThrowTypeService = $ dynamicThrowTypeService ;
113
+ $ this ->defaultThrowTypeService = $ defaultThrowTypeService ;
104
114
$ this ->throwsAnnotationReader = $ throwsAnnotationReader ;
105
115
$ this ->broker = $ broker ;
106
116
$ this ->throwsScope = new ThrowsScope ();
@@ -438,26 +448,41 @@ private function filterUnusedExceptions(array $declaredThrows, array $usedThrows
438
448
$ checkedThrowsAnnotations = $ this ->checkedExceptionService ->filterCheckedExceptions ($ usedThrowsAnnotations );
439
449
$ unusedThrows = array_diff ($ declaredThrows , $ checkedThrowsAnnotations );
440
450
441
- if (!$ this ->ignoreDescriptiveUncheckedExceptions ) {
442
- return $ unusedThrows ;
443
- }
444
-
445
451
$ functionReflection = $ scope ->getFunction ();
446
452
if ($ functionReflection === null ) {
447
453
return $ unusedThrows ;
448
454
}
449
455
456
+ try {
457
+ if ($ functionReflection instanceof MethodReflection) {
458
+ $ defaultThrowsType = $ functionReflection ->getName () === '__construct ' ?
459
+ $ this ->defaultThrowTypeService ->getConstructorThrowType ($ functionReflection ) :
460
+ $ this ->defaultThrowTypeService ->getMethodThrowType ($ functionReflection );
461
+ } else {
462
+ $ defaultThrowsType = $ this ->defaultThrowTypeService ->getFunctionThrowType ($ functionReflection );
463
+ }
464
+ } catch (UnsupportedClassException | UnsupportedFunctionException $ exception ) {
465
+ $ defaultThrowsType = new VoidType ();
466
+ }
467
+
468
+ $ unusedThrows = array_diff ($ unusedThrows , TypeUtils::getDirectClassNames ($ defaultThrowsType ));
469
+
450
470
try {
451
471
if ($ functionReflection instanceof MethodReflection) {
452
472
$ nativeClassReflection = $ functionReflection ->getDeclaringClass ()->getNativeReflection ();
453
473
$ nativeFunctionReflection = $ nativeClassReflection ->getMethod ($ functionReflection ->getName ());
474
+
454
475
} else {
455
476
$ nativeFunctionReflection = new ReflectionFunction ($ functionReflection ->getName ());
456
477
}
457
478
} catch (ReflectionException $ exception ) {
458
479
return $ unusedThrows ;
459
480
}
460
481
482
+ if (!$ this ->ignoreDescriptiveUncheckedExceptions ) {
483
+ return $ unusedThrows ;
484
+ }
485
+
461
486
$ throwsAnnotations = $ this ->throwsAnnotationReader ->read ($ nativeFunctionReflection );
462
487
463
488
return array_filter ($ unusedThrows , static function (string $ type ) use ($ throwsAnnotations , $ usedThrowsAnnotations ): bool {
0 commit comments