4
4
5
5
use PhpParser \Node ;
6
6
use PhpParser \Node \Expr ;
7
+ use PHPStan \Analyser \NameScope ;
7
8
use PHPStan \Analyser \Scope ;
8
9
use PHPStan \Node \Expr \GetOffsetValueTypeExpr ;
9
10
use PHPStan \PhpDoc \Tag \VarTag ;
11
+ use PHPStan \PhpDoc \TypeNodeResolver ;
10
12
use PHPStan \Rules \IdentifierRuleError ;
11
13
use PHPStan \Rules \RuleErrorBuilder ;
14
+ use PHPStan \TrinaryLogic ;
12
15
use PHPStan \Type \ArrayType ;
13
16
use PHPStan \Type \Generic \GenericObjectType ;
14
17
use PHPStan \Type \MixedType ;
24
27
final class VarTagTypeRuleHelper
25
28
{
26
29
27
- public function __construct (private bool $ checkTypeAgainstPhpDocType , private bool $ strictWideningCheck )
30
+ public function __construct (
31
+ private TypeNodeResolver $ typeNodeResolver ,
32
+ private bool $ checkTypeAgainstPhpDocType ,
33
+ private bool $ strictWideningCheck ,
34
+ )
28
35
{
29
36
}
30
37
@@ -134,15 +141,15 @@ private function shouldVarTagTypeBeReported(Node\Expr $expr, Type $type, Type $v
134
141
$ type = new ArrayType (new MixedType (), new MixedType ());
135
142
}
136
143
137
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
144
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
138
145
}
139
146
140
147
if ($ expr instanceof Expr \ConstFetch) {
141
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
148
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
142
149
}
143
150
144
151
if ($ expr instanceof Node \Scalar) {
145
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
152
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
146
153
}
147
154
148
155
if ($ expr instanceof Expr \New_) {
@@ -157,36 +164,43 @@ private function shouldVarTagTypeBeReported(Node\Expr $expr, Type $type, Type $v
157
164
private function checkType (Type $ type , Type $ varTagType , int $ depth = 0 ): bool
158
165
{
159
166
if ($ this ->strictWideningCheck ) {
160
- return !$ type -> isSuperTypeOf ( $ varTagType )->yes ();
167
+ return !$ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->yes ();
161
168
}
162
169
163
170
if ($ type ->isConstantArray ()->yes ()) {
164
171
if ($ type ->isIterableAtLeastOnce ()->no ()) {
165
172
$ type = new ArrayType (new MixedType (), new MixedType ());
166
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
173
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
167
174
}
168
175
}
169
176
170
177
if ($ type ->isIterable ()->yes () && $ varTagType ->isIterable ()->yes ()) {
171
- if ($ type -> isSuperTypeOf ( $ varTagType )->no ()) {
178
+ if ($ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ()) {
172
179
return true ;
173
180
}
174
181
175
182
$ innerType = $ type ->getIterableValueType ();
176
183
$ innerVarTagType = $ varTagType ->getIterableValueType ();
177
184
178
185
if ($ type ->equals ($ innerType ) || $ varTagType ->equals ($ innerVarTagType )) {
179
- return !$ innerType -> isSuperTypeOf ( $ innerVarTagType )->yes ();
186
+ return !$ this -> isSuperTypeOfVarType ( $ innerType , $ innerVarTagType )->yes ();
180
187
}
181
188
182
189
return $ this ->checkType ($ innerType , $ innerVarTagType , $ depth + 1 );
183
190
}
184
191
185
- if ($ type ->isConstantValue ()->yes () && $ depth === 0 ) {
186
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
192
+ if ($ depth === 0 && $ type ->isConstantValue ()->yes ()) {
193
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
187
194
}
188
195
189
- return !$ type ->isSuperTypeOf ($ varTagType )->yes ();
196
+ return !$ this ->isSuperTypeOfVarType ($ type , $ varTagType )->yes ();
197
+ }
198
+
199
+ private function isSuperTypeOfVarType (Type $ type , Type $ varTagType ): TrinaryLogic
200
+ {
201
+ $ type = $ this ->typeNodeResolver ->resolve ($ type ->toPhpDocNode (), new NameScope (null , []));
202
+
203
+ return $ type ->isSuperTypeOf ($ varTagType );
190
204
}
191
205
192
206
}
0 commit comments