2
2
3
3
namespace PHPStan \Type \Php ;
4
4
5
- use PhpParser \Node \Arg ;
6
- use PhpParser \Node \Expr ;
7
- use PhpParser \Node \Expr \BinaryOp \BitwiseOr ;
8
5
use PhpParser \Node \Expr \FuncCall ;
9
- use PhpParser \Node \Name ;
10
6
use PHPStan \Analyser \Scope ;
11
7
use PHPStan \Reflection \FunctionReflection ;
12
8
use PHPStan \Reflection \ParametersAcceptorSelector ;
13
- use PHPStan \Reflection \ReflectionProvider ;
14
- use PHPStan \ShouldNotHappenException ;
15
9
use PHPStan \Type \ArrayType ;
10
+ use PHPStan \Type \BitwiseFlagHelper ;
16
11
use PHPStan \Type \Constant \ConstantArrayType ;
17
12
use PHPStan \Type \Constant \ConstantBooleanType ;
18
13
use PHPStan \Type \Constant \ConstantIntegerType ;
22
17
use PHPStan \Type \StringType ;
23
18
use PHPStan \Type \Type ;
24
19
use PHPStan \Type \TypeCombinator ;
25
- use function sprintf ;
26
20
use function strtolower ;
27
21
28
22
class PregSplitDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension
29
23
{
30
24
31
- public function __construct (private ReflectionProvider $ reflectionProvider )
25
+ public function __construct (
26
+ private BitwiseFlagHelper $ bitwiseFlagAnalyser ,
27
+ )
32
28
{
33
29
}
34
30
35
-
36
31
public function isFunctionSupported (FunctionReflection $ functionReflection ): bool
37
32
{
38
33
return strtolower ($ functionReflection ->getName ()) === 'preg_split ' ;
39
34
}
40
35
41
-
42
36
public function getTypeFromFunctionCall (FunctionReflection $ functionReflection , FuncCall $ functionCall , Scope $ scope ): Type
43
37
{
44
38
$ flagsArg = $ functionCall ->getArgs ()[3 ] ?? null ;
45
39
46
- if ($ this ->hasFlag ( $ this -> getConstant ( ' PREG_SPLIT_OFFSET_CAPTURE ' ), $ flagsArg , $ scope )) {
40
+ if ($ flagsArg !== null && $ this ->bitwiseFlagAnalyser -> bitwiseOrContainsConstant ( $ flagsArg-> value , $ scope, ' PREG_SPLIT_OFFSET_CAPTURE ' )-> yes ( )) {
47
41
$ type = new ArrayType (
48
42
new IntegerType (),
49
43
new ConstantArrayType ([new ConstantIntegerType (0 ), new ConstantIntegerType (1 )], [new StringType (), IntegerRangeType::fromInterval (0 , null )]),
@@ -54,39 +48,4 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
54
48
return ParametersAcceptorSelector::selectSingle ($ functionReflection ->getVariants ())->getReturnType ();
55
49
}
56
50
57
-
58
- private function hasFlag (int $ flag , ?Arg $ arg , Scope $ scope ): bool
59
- {
60
- if ($ arg === null ) {
61
- return false ;
62
- }
63
-
64
- return $ this ->isConstantFlag ($ flag , $ arg ->value , $ scope );
65
- }
66
-
67
- private function isConstantFlag (int $ flag , Expr $ expression , Scope $ scope ): bool
68
- {
69
- if ($ expression instanceof BitwiseOr) {
70
- $ left = $ expression ->left ;
71
- $ right = $ expression ->right ;
72
-
73
- return $ this ->isConstantFlag ($ flag , $ left , $ scope ) || $ this ->isConstantFlag ($ flag , $ right , $ scope );
74
- }
75
-
76
- $ type = $ scope ->getType ($ expression );
77
- return $ type instanceof ConstantIntegerType && ($ type ->getValue () & $ flag ) === $ flag ;
78
- }
79
-
80
-
81
- private function getConstant (string $ constantName ): int
82
- {
83
- $ constant = $ this ->reflectionProvider ->getConstant (new Name ($ constantName ), null );
84
- $ valueType = $ constant ->getValueType ();
85
- if (!$ valueType instanceof ConstantIntegerType) {
86
- throw new ShouldNotHappenException (sprintf ('Constant %s does not have integer type. ' , $ constantName ));
87
- }
88
-
89
- return $ valueType ->getValue ();
90
- }
91
-
92
51
}
0 commit comments