51
51
use PHPStan \BetterReflection \SourceLocator \Ast \Strategy \NodeToReflection ;
52
52
use PHPStan \BetterReflection \SourceLocator \Located \LocatedSource ;
53
53
use PHPStan \DependencyInjection \Reflection \ClassReflectionExtensionRegistryProvider ;
54
+ use PHPStan \DependencyInjection \Type \DynamicThrowTypeExtensionProvider ;
54
55
use PHPStan \File \FileHelper ;
55
56
use PHPStan \File \FileReader ;
56
57
use PHPStan \Node \BooleanAndNode ;
@@ -145,6 +146,8 @@ class NodeScopeResolver
145
146
146
147
private \PHPStan \Analyser \TypeSpecifier $ typeSpecifier ;
147
148
149
+ private DynamicThrowTypeExtensionProvider $ dynamicThrowTypeExtensionProvider ;
150
+
148
151
private bool $ polluteScopeWithLoopInitialAssignments ;
149
152
150
153
private bool $ polluteCatchScopeWithTryAssignments ;
@@ -190,6 +193,7 @@ public function __construct(
190
193
PhpDocInheritanceResolver $ phpDocInheritanceResolver ,
191
194
FileHelper $ fileHelper ,
192
195
TypeSpecifier $ typeSpecifier ,
196
+ DynamicThrowTypeExtensionProvider $ dynamicThrowTypeExtensionProvider ,
193
197
bool $ polluteScopeWithLoopInitialAssignments ,
194
198
bool $ polluteCatchScopeWithTryAssignments ,
195
199
bool $ polluteScopeWithAlwaysIterableForeach ,
@@ -208,6 +212,7 @@ public function __construct(
208
212
$ this ->phpDocInheritanceResolver = $ phpDocInheritanceResolver ;
209
213
$ this ->fileHelper = $ fileHelper ;
210
214
$ this ->typeSpecifier = $ typeSpecifier ;
215
+ $ this ->dynamicThrowTypeExtensionProvider = $ dynamicThrowTypeExtensionProvider ;
211
216
$ this ->polluteScopeWithLoopInitialAssignments = $ polluteScopeWithLoopInitialAssignments ;
212
217
$ this ->polluteCatchScopeWithTryAssignments = $ polluteCatchScopeWithTryAssignments ;
213
218
$ this ->polluteScopeWithAlwaysIterableForeach = $ polluteScopeWithAlwaysIterableForeach ;
@@ -1780,34 +1785,9 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
1780
1785
$ throwPoints = array_merge ($ throwPoints , $ result ->getThrowPoints ());
1781
1786
1782
1787
if (isset ($ functionReflection )) {
1783
- if ($ functionReflection ->getThrowType () !== null ) {
1784
- $ throwType = $ functionReflection ->getThrowType ();
1785
- if (!$ throwType instanceof VoidType) {
1786
- $ throwPoints [] = ThrowPoint::createExplicit ($ scope , $ throwType , true );
1787
- }
1788
- } elseif ($ this ->implicitThrows ) {
1789
- $ requiredParameters = null ;
1790
- if ($ parametersAcceptor !== null ) {
1791
- $ requiredParameters = 0 ;
1792
- foreach ($ parametersAcceptor ->getParameters () as $ parameter ) {
1793
- if ($ parameter ->isOptional ()) {
1794
- continue ;
1795
- }
1796
-
1797
- $ requiredParameters ++;
1798
- }
1799
- }
1800
- if (
1801
- !$ functionReflection ->isBuiltin ()
1802
- || $ requiredParameters === null
1803
- || $ requiredParameters > 0
1804
- || count ($ expr ->args ) > 0
1805
- ) {
1806
- $ functionReturnedType = $ scope ->getType ($ expr );
1807
- if (!(new ObjectType (\Throwable::class))->isSuperTypeOf ($ functionReturnedType )->yes ()) {
1808
- $ throwPoints [] = ThrowPoint::createImplicit ($ scope );
1809
- }
1810
- }
1788
+ $ functionThrowPoint = $ this ->getFunctionThrowPoint ($ functionReflection , $ parametersAcceptor , $ expr , $ scope );
1789
+ if ($ functionThrowPoint !== null ) {
1790
+ $ throwPoints [] = $ functionThrowPoint ;
1811
1791
}
1812
1792
} else {
1813
1793
$ throwPoints [] = ThrowPoint::createImplicit ($ scope );
@@ -1975,16 +1955,9 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
1975
1955
$ expr ->args ,
1976
1956
$ methodReflection ->getVariants ()
1977
1957
);
1978
- if ($ methodReflection ->getThrowType () !== null ) {
1979
- $ throwType = $ methodReflection ->getThrowType ();
1980
- if (!$ throwType instanceof VoidType) {
1981
- $ throwPoints [] = ThrowPoint::createExplicit ($ scope , $ methodReflection ->getThrowType (), true );
1982
- }
1983
- } elseif ($ this ->implicitThrows ) {
1984
- $ methodReturnedType = $ scope ->getType ($ expr );
1985
- if (!(new ObjectType (\Throwable::class))->isSuperTypeOf ($ methodReturnedType )->yes ()) {
1986
- $ throwPoints [] = ThrowPoint::createImplicit ($ scope );
1987
- }
1958
+ $ methodThrowPoint = $ this ->getMethodThrowPoint ($ methodReflection , $ expr , $ scope );
1959
+ if ($ methodThrowPoint !== null ) {
1960
+ $ throwPoints [] = $ methodThrowPoint ;
1988
1961
}
1989
1962
} else {
1990
1963
$ throwPoints [] = ThrowPoint::createImplicit ($ scope );
@@ -2056,16 +2029,9 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
2056
2029
$ expr ->args ,
2057
2030
$ methodReflection ->getVariants ()
2058
2031
);
2059
- if ($ methodReflection ->getThrowType () !== null ) {
2060
- $ throwType = $ methodReflection ->getThrowType ();
2061
- if (!$ throwType instanceof VoidType) {
2062
- $ throwPoints [] = ThrowPoint::createExplicit ($ scope , $ throwType , true );
2063
- }
2064
- } elseif ($ this ->implicitThrows ) {
2065
- $ methodReturnedType = $ scope ->getType ($ expr );
2066
- if (!(new ObjectType (\Throwable::class))->isSuperTypeOf ($ methodReturnedType )->yes ()) {
2067
- $ throwPoints [] = ThrowPoint::createImplicit ($ scope );
2068
- }
2032
+ $ methodThrowPoint = $ this ->getStaticMethodThrowPoint ($ methodReflection , $ expr , $ scope );
2033
+ if ($ methodThrowPoint !== null ) {
2034
+ $ throwPoints [] = $ methodThrowPoint ;
2069
2035
}
2070
2036
if (
2071
2037
$ classReflection ->getName () === 'Closure '
@@ -2627,6 +2593,119 @@ static function () use ($scope, $expr): MutatingScope {
2627
2593
);
2628
2594
}
2629
2595
2596
+ private function getFunctionThrowPoint (
2597
+ FunctionReflection $ functionReflection ,
2598
+ ?ParametersAcceptor $ parametersAcceptor ,
2599
+ FuncCall $ funcCall ,
2600
+ MutatingScope $ scope
2601
+ ): ?ThrowPoint
2602
+ {
2603
+ foreach ($ this ->dynamicThrowTypeExtensionProvider ->getDynamicFunctionThrowTypeExtensions () as $ extension ) {
2604
+ if (!$ extension ->isFunctionSupported ($ functionReflection )) {
2605
+ continue ;
2606
+ }
2607
+
2608
+ $ throwType = $ extension ->getThrowTypeFromFunctionCall ($ functionReflection , $ funcCall , $ scope );
2609
+ if ($ throwType === null ) {
2610
+ return null ;
2611
+ }
2612
+
2613
+ return ThrowPoint::createExplicit ($ scope , $ throwType , false );
2614
+ }
2615
+
2616
+ if ($ functionReflection ->getThrowType () !== null ) {
2617
+ $ throwType = $ functionReflection ->getThrowType ();
2618
+ if (!$ throwType instanceof VoidType) {
2619
+ return ThrowPoint::createExplicit ($ scope , $ throwType , true );
2620
+ }
2621
+ } elseif ($ this ->implicitThrows ) {
2622
+ $ requiredParameters = null ;
2623
+ if ($ parametersAcceptor !== null ) {
2624
+ $ requiredParameters = 0 ;
2625
+ foreach ($ parametersAcceptor ->getParameters () as $ parameter ) {
2626
+ if ($ parameter ->isOptional ()) {
2627
+ continue ;
2628
+ }
2629
+
2630
+ $ requiredParameters ++;
2631
+ }
2632
+ }
2633
+ if (
2634
+ !$ functionReflection ->isBuiltin ()
2635
+ || $ requiredParameters === null
2636
+ || $ requiredParameters > 0
2637
+ || count ($ funcCall ->args ) > 0
2638
+ ) {
2639
+ $ functionReturnedType = $ scope ->getType ($ funcCall );
2640
+ if (!(new ObjectType (\Throwable::class))->isSuperTypeOf ($ functionReturnedType )->yes ()) {
2641
+ return ThrowPoint::createImplicit ($ scope );
2642
+ }
2643
+ }
2644
+ }
2645
+
2646
+ return null ;
2647
+ }
2648
+
2649
+ private function getMethodThrowPoint (MethodReflection $ methodReflection , MethodCall $ methodCall , MutatingScope $ scope ): ?ThrowPoint
2650
+ {
2651
+ foreach ($ this ->dynamicThrowTypeExtensionProvider ->getDynamicMethodThrowTypeExtensions () as $ extension ) {
2652
+ if (!$ extension ->isMethodSupported ($ methodReflection )) {
2653
+ continue ;
2654
+ }
2655
+
2656
+ $ throwType = $ extension ->getThrowTypeFromMethodCall ($ methodReflection , $ methodCall , $ scope );
2657
+ if ($ throwType === null ) {
2658
+ return null ;
2659
+ }
2660
+
2661
+ return ThrowPoint::createExplicit ($ scope , $ throwType , false );
2662
+ }
2663
+
2664
+ if ($ methodReflection ->getThrowType () !== null ) {
2665
+ $ throwType = $ methodReflection ->getThrowType ();
2666
+ if (!$ throwType instanceof VoidType) {
2667
+ return ThrowPoint::createExplicit ($ scope , $ throwType , true );
2668
+ }
2669
+ } elseif ($ this ->implicitThrows ) {
2670
+ $ methodReturnedType = $ scope ->getType ($ methodCall );
2671
+ if (!(new ObjectType (\Throwable::class))->isSuperTypeOf ($ methodReturnedType )->yes ()) {
2672
+ return ThrowPoint::createImplicit ($ scope );
2673
+ }
2674
+ }
2675
+
2676
+ return null ;
2677
+ }
2678
+
2679
+ private function getStaticMethodThrowPoint (MethodReflection $ methodReflection , StaticCall $ methodCall , MutatingScope $ scope ): ?ThrowPoint
2680
+ {
2681
+ foreach ($ this ->dynamicThrowTypeExtensionProvider ->getDynamicStaticMethodThrowTypeExtensions () as $ extension ) {
2682
+ if (!$ extension ->isStaticMethodSupported ($ methodReflection )) {
2683
+ continue ;
2684
+ }
2685
+
2686
+ $ throwType = $ extension ->getThrowTypeFromStaticMethodCall ($ methodReflection , $ methodCall , $ scope );
2687
+ if ($ throwType === null ) {
2688
+ return null ;
2689
+ }
2690
+
2691
+ return ThrowPoint::createExplicit ($ scope , $ throwType , false );
2692
+ }
2693
+
2694
+ if ($ methodReflection ->getThrowType () !== null ) {
2695
+ $ throwType = $ methodReflection ->getThrowType ();
2696
+ if (!$ throwType instanceof VoidType) {
2697
+ return ThrowPoint::createExplicit ($ scope , $ throwType , true );
2698
+ }
2699
+ } elseif ($ this ->implicitThrows ) {
2700
+ $ methodReturnedType = $ scope ->getType ($ methodCall );
2701
+ if (!(new ObjectType (\Throwable::class))->isSuperTypeOf ($ methodReturnedType )->yes ()) {
2702
+ return ThrowPoint::createImplicit ($ scope );
2703
+ }
2704
+ }
2705
+
2706
+ return null ;
2707
+ }
2708
+
2630
2709
/**
2631
2710
* @param Expr $expr
2632
2711
* @return string[]
0 commit comments