44
55use PhpParser \Node ;
66use PhpParser \Node \Expr ;
7+ use PHPStan \Analyser \NameScope ;
78use PHPStan \Analyser \Scope ;
89use PHPStan \Node \Expr \GetOffsetValueTypeExpr ;
910use PHPStan \PhpDoc \Tag \VarTag ;
11+ use PHPStan \PhpDoc \TypeNodeResolver ;
1012use PHPStan \Rules \IdentifierRuleError ;
1113use PHPStan \Rules \RuleErrorBuilder ;
14+ use PHPStan \TrinaryLogic ;
1215use PHPStan \Type \ArrayType ;
1316use PHPStan \Type \Generic \GenericObjectType ;
1417use PHPStan \Type \MixedType ;
2427final class VarTagTypeRuleHelper
2528{
2629
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+ ) {
2935 }
3036
3137 /**
@@ -134,15 +140,15 @@ private function shouldVarTagTypeBeReported(Node\Expr $expr, Type $type, Type $v
134140 $ type = new ArrayType (new MixedType (), new MixedType ());
135141 }
136142
137- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
143+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
138144 }
139145
140146 if ($ expr instanceof Expr \ConstFetch) {
141- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
147+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
142148 }
143149
144150 if ($ expr instanceof Node \Scalar) {
145- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
151+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
146152 }
147153
148154 if ($ expr instanceof Expr \New_) {
@@ -157,36 +163,43 @@ private function shouldVarTagTypeBeReported(Node\Expr $expr, Type $type, Type $v
157163 private function checkType (Type $ type , Type $ varTagType , int $ depth = 0 ): bool
158164 {
159165 if ($ this ->strictWideningCheck ) {
160- return !$ type -> isSuperTypeOf ( $ varTagType )->yes ();
166+ return !$ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->yes ();
161167 }
162168
163169 if ($ type ->isConstantArray ()->yes ()) {
164170 if ($ type ->isIterableAtLeastOnce ()->no ()) {
165171 $ type = new ArrayType (new MixedType (), new MixedType ());
166- return $ type -> isSuperTypeOf ( $ varTagType )->no ();
172+ return $ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ();
167173 }
168174 }
169175
170176 if ($ type ->isIterable ()->yes () && $ varTagType ->isIterable ()->yes ()) {
171- if ($ type -> isSuperTypeOf ( $ varTagType )->no ()) {
177+ if ($ this -> isSuperTypeOfVarType ( $ type , $ varTagType )->no ()) {
172178 return true ;
173179 }
174180
175181 $ innerType = $ type ->getIterableValueType ();
176182 $ innerVarTagType = $ varTagType ->getIterableValueType ();
177183
178184 if ($ type ->equals ($ innerType ) || $ varTagType ->equals ($ innerVarTagType )) {
179- return !$ innerType -> isSuperTypeOf ( $ innerVarTagType )->yes ();
185+ return !$ this -> isSuperTypeOfVarType ( $ innerType , $ innerVarTagType )->yes ();
180186 }
181187
182188 return $ this ->checkType ($ innerType , $ innerVarTagType , $ depth + 1 );
183189 }
184190
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 ();
187193 }
188194
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 );
190203 }
191204
192205}
0 commit comments