55use PhpParser \Node \Expr \FuncCall ;
66use PHPStan \Analyser \Scope ;
77use PHPStan \Reflection \FunctionReflection ;
8- use PHPStan \Type \Accessory \AccessoryNonEmptyStringType ;
9- use PHPStan \Type \Accessory \AccessoryNonFalsyStringType ;
10- use PHPStan \Type \Accessory \AccessoryNumericStringType ;
11- use PHPStan \Type \Constant \ConstantStringType ;
128use PHPStan \Type \DynamicFunctionReturnTypeExtension ;
13- use PHPStan \Type \IntersectionType ;
14- use PHPStan \Type \StringType ;
159use PHPStan \Type \Type ;
16- use PHPStan \Type \TypeCombinator ;
17- use PHPStan \Type \UnionType ;
1810use function count ;
19- use function date ;
20- use function sprintf ;
2111
2212class DateFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension
2313{
2414
15+ public function __construct (private DateFunctionReturnTypeHelper $ dateFunctionReturnTypeHelper )
16+ {
17+ }
18+
2519 public function isFunctionSupported (FunctionReflection $ functionReflection ): bool
2620 {
2721 return $ functionReflection ->getName () === 'date ' ;
@@ -31,101 +25,16 @@ public function getTypeFromFunctionCall(
3125 FunctionReflection $ functionReflection ,
3226 FuncCall $ functionCall ,
3327 Scope $ scope ,
34- ): Type
28+ ): ? Type
3529 {
3630 if (count ($ functionCall ->getArgs ()) === 0 ) {
37- return new StringType ();
38- }
39- $ argType = $ scope ->getType ($ functionCall ->getArgs ()[0 ]->value );
40- $ constantStrings = $ argType ->getConstantStrings ();
41-
42- if (count ($ constantStrings ) === 0 ) {
43- return new StringType ();
44- }
45-
46- if (count ($ constantStrings ) === 1 ) {
47- $ constantString = $ constantStrings [0 ]->getValue ();
48-
49- // see see https://www.php.net/manual/en/datetime.format.php
50- switch ($ constantString ) {
51- case 'd ' :
52- return $ this ->buildNumericRangeType (1 , 31 , true );
53- case 'j ' :
54- return $ this ->buildNumericRangeType (1 , 31 , false );
55- case 'N ' :
56- return $ this ->buildNumericRangeType (1 , 7 , false );
57- case 'w ' :
58- return $ this ->buildNumericRangeType (0 , 6 , false );
59- case 'm ' :
60- return $ this ->buildNumericRangeType (1 , 12 , true );
61- case 'n ' :
62- return $ this ->buildNumericRangeType (1 , 12 , false );
63- case 't ' :
64- return $ this ->buildNumericRangeType (28 , 31 , false );
65- case 'L ' :
66- return $ this ->buildNumericRangeType (0 , 1 , false );
67- case 'g ' :
68- return $ this ->buildNumericRangeType (1 , 12 , false );
69- case 'G ' :
70- return $ this ->buildNumericRangeType (0 , 23 , false );
71- case 'h ' :
72- return $ this ->buildNumericRangeType (1 , 12 , true );
73- case 'H ' :
74- return $ this ->buildNumericRangeType (0 , 23 , true );
75- case 'I ' :
76- return $ this ->buildNumericRangeType (0 , 1 , false );
77- }
78- }
79-
80- $ types = [];
81- foreach ($ constantStrings as $ constantString ) {
82- $ types [] = new ConstantStringType (date ($ constantString ->getValue ()));
83- }
84-
85- $ type = TypeCombinator::union (...$ types );
86- if ($ type ->isNumericString ()->yes ()) {
87- return new IntersectionType ([
88- new StringType (),
89- new AccessoryNumericStringType (),
90- ]);
91- }
92-
93- if ($ type ->isNonFalsyString ()->yes ()) {
94- return new IntersectionType ([
95- new StringType (),
96- new AccessoryNonFalsyStringType (),
97- ]);
98- }
99-
100- if ($ type ->isNonEmptyString ()->yes ()) {
101- return new IntersectionType ([
102- new StringType (),
103- new AccessoryNonEmptyStringType (),
104- ]);
105- }
106-
107- if ($ type ->isNonEmptyString ()->no ()) {
108- return new ConstantStringType ('' );
109- }
110-
111- return new StringType ();
112- }
113-
114- private function buildNumericRangeType (int $ min , int $ max , bool $ zeroPad ): Type
115- {
116- $ types = [];
117-
118- for ($ i = $ min ; $ i <= $ max ; $ i ++) {
119- $ string = (string ) $ i ;
120-
121- if ($ zeroPad ) {
122- $ string = sprintf ('%02s ' , $ string );
123- }
124-
125- $ types [] = new ConstantStringType ($ string );
31+ return null ;
12632 }
12733
128- return new UnionType ($ types );
34+ return $ this ->dateFunctionReturnTypeHelper ->getTypeFromFormatType (
35+ $ scope ->getType ($ functionCall ->getArgs ()[0 ]->value ),
36+ false ,
37+ );
12938 }
13039
13140}
0 commit comments