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 )
28
- {
30
+ public function __construct (
31
+ private TypeNodeResolver $ typeNodeResolver ,
32
+ private bool $ checkTypeAgainstPhpDocType ,
33
+ private bool $ strictWideningCheck
34
+ ) {
29
35
}
30
36
31
37
/**
@@ -134,15 +140,15 @@ private function shouldVarTagTypeBeReported(Node\Expr $expr, Type $type, Type $v
134
140
$ type = new ArrayType (new MixedType (), new MixedType ());
135
141
}
136
142
137
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
143
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
138
144
}
139
145
140
146
if ($ expr instanceof Expr \ConstFetch) {
141
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
147
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
142
148
}
143
149
144
150
if ($ expr instanceof Node \Scalar) {
145
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
151
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
146
152
}
147
153
148
154
if ($ expr instanceof Expr \New_) {
@@ -157,36 +163,43 @@ private function shouldVarTagTypeBeReported(Node\Expr $expr, Type $type, Type $v
157
163
private function checkType (Type $ type , Type $ varTagType , int $ depth = 0 ): bool
158
164
{
159
165
if ($ this ->strictWideningCheck ) {
160
- return !$ type -> isSuperTypeOf ( $ varTagType )->yes ();
166
+ return !$ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->yes ();
161
167
}
162
168
163
169
if ($ type ->isConstantArray ()->yes ()) {
164
170
if ($ type ->isIterableAtLeastOnce ()->no ()) {
165
171
$ type = new ArrayType (new MixedType (), new MixedType ());
166
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
172
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
167
173
}
168
174
}
169
175
170
176
if ($ type ->isIterable ()->yes () && $ varTagType ->isIterable ()->yes ()) {
171
- if ($ type -> isSuperTypeOf ( $ varTagType )->no ()) {
177
+ if ($ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ()) {
172
178
return true ;
173
179
}
174
180
175
181
$ innerType = $ type ->getIterableValueType ();
176
182
$ innerVarTagType = $ varTagType ->getIterableValueType ();
177
183
178
184
if ($ type ->equals ($ innerType ) || $ varTagType ->equals ($ innerVarTagType )) {
179
- return !$ innerType -> isSuperTypeOf ( $ innerVarTagType )->yes ();
185
+ return !$ this -> isSuperTypeOfVarType ( $ innerType , $ innerVarTagType )->yes ();
180
186
}
181
187
182
188
return $ this ->checkType ($ innerType , $ innerVarTagType , $ depth + 1 );
183
189
}
184
190
185
- if ($ type ->isConstantValue ()->yes () && $ depth === 0 ) {
186
- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
191
+ if ($ depth === 0 && $ type ->isConstantValue ()->yes ()) {
192
+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
187
193
}
188
194
189
- return !$ type ->isSuperTypeOf ($ varTagType )->yes ();
195
+ return !$ this ->isSuperTypeOfVarType ($ type , $ varTagType )->yes ();
196
+ }
197
+
198
+ private function isSuperTypeOfVarType (Type $ type , Type $ varTagType ): TrinaryLogic
199
+ {
200
+ $ type = $ this ->typeNodeResolver ->resolve ($ type ->toPhpDocNode (), new NameScope (null , []));
201
+
202
+ return $ type ->isSuperTypeOf ($ varTagType );
190
203
}
191
204
192
205
}
0 commit comments