31
31
use PHPStan \Type \TypeCombinator ;
32
32
use PHPStan \Type \UnionType ;
33
33
use Stringable ;
34
- use function class_exists ;
35
- use function interface_exists ;
36
34
37
35
final class InspectorTypeExtension implements StaticMethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
38
36
{
@@ -100,20 +98,20 @@ public function specifyTypes(MethodReflection $staticMethodReflection, StaticCal
100
98
*/
101
99
private function specifyAssertAll (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
102
100
{
103
- $ callable = $ node ->getArgs ()[0 ]->value ;
104
- $ callableInfo = $ scope ->getType ($ callable );
101
+ $ callableArg = $ node ->getArgs ()[0 ]->value ;
102
+ $ callableType = $ scope ->getType ($ callableArg );
105
103
106
- if (!$ callableInfo ->isCallable ()->yes ()) {
104
+ if (!$ callableType ->isCallable ()->yes ()) {
107
105
return new SpecifiedTypes ();
108
106
}
109
107
110
- $ traversable = $ node ->getArgs ()[1 ]->value ;
111
- $ traversableInfo = $ scope ->getType ($ traversable );
108
+ $ traversableArg = $ node ->getArgs ()[1 ]->value ;
109
+ $ traversableType = $ scope ->getType ($ traversableArg );
112
110
113
111
// If it is already not mixed (narrowed by other code, like
114
112
// '::assertAllArray()'), we could not provide any additional
115
113
// information. We can only narrow this method to 'array<mixed, mixed>'.
116
- if (!$ traversableInfo ->equals (new MixedType ())) {
114
+ if (!$ traversableType ->equals (new MixedType ())) {
117
115
return new SpecifiedTypes ();
118
116
}
119
117
@@ -130,85 +128,70 @@ private function specifyAssertAll(MethodReflection $staticMethodReflection, Stat
130
128
return new SpecifiedTypes ();
131
129
}
132
130
133
- return $ this ->typeSpecifier ->create (
134
- $ node ->getArgs ()[1 ]->value ,
135
- new IterableType (new MixedType (), new MixedType ()),
136
- $ context ,
137
- $ scope ,
138
- );
131
+ $ newType = new IterableType (new MixedType (), new MixedType ());
132
+
133
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
139
134
}
140
135
141
136
/**
142
137
* @see Drupal\Component\Assertion\Inspector::assertAllStrings()
143
138
*/
144
139
private function specifyAssertAllStrings (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
145
140
{
146
- return $ this ->typeSpecifier ->create (
147
- $ node ->getArgs ()[0 ]->value ,
148
- new IterableType (new MixedType (), new StringType ()),
149
- $ context ,
150
- $ scope ,
151
- );
141
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
142
+ $ newType = new IterableType (new MixedType (), new StringType ());
143
+
144
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
152
145
}
153
146
154
147
/**
155
148
* @see Drupal\Component\Assertion\Inspector::assertAllStringable()
156
149
*/
157
150
private function specifyAssertAllStringable (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
158
151
{
152
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
159
153
// Drupal considers string as part of "stringable" as well.
160
- $ stringable = TypeCombinator::union (new ObjectType (Stringable::class), new StringType ());
161
- $ newType = new IterableType (new MixedType (), $ stringable );
162
-
163
- return $ this ->typeSpecifier ->create (
164
- $ node ->getArgs ()[0 ]->value ,
165
- $ newType ,
166
- $ context ,
167
- $ scope ,
168
- );
154
+ $ stringableType = TypeCombinator::union (new ObjectType (Stringable::class), new StringType ());
155
+ $ newType = new IterableType (new MixedType (), $ stringableType );
156
+
157
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
169
158
}
170
159
171
160
/**
172
161
* @see Drupal\Component\Assertion\Inspector::assertAllArrays()
173
162
*/
174
163
private function specifyAssertAllArrays (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
175
164
{
165
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
176
166
$ arrayType = new ArrayType (new MixedType (), new MixedType ());
177
167
$ newType = new IterableType (new MixedType (), $ arrayType );
178
168
179
- return $ this ->typeSpecifier ->create (
180
- $ node ->getArgs ()[0 ]->value ,
181
- $ newType ,
182
- $ context ,
183
- $ scope ,
184
- );
169
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
185
170
}
186
171
187
172
/**
188
173
* @see Drupal\Component\Assertion\Inspector::assertStrictArray()
189
174
*/
190
175
private function specifyAssertStrictArray (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
191
176
{
177
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
192
178
$ newType = new ArrayType (
193
- // In Drupal, 'strict arrays' are defined as arrays whose indexes
194
- // consist of integers that are equal to or greater than 0.
179
+ // In Drupal, 'strict arrays' are defined as arrays whose
180
+ // indexes consist of integers that are equal to or greater
181
+ // than 0.
195
182
IntegerRangeType::createAllGreaterThanOrEqualTo (0 ),
196
183
new MixedType (),
197
184
);
198
185
199
- return $ this ->typeSpecifier ->create (
200
- $ node ->getArgs ()[0 ]->value ,
201
- $ newType ,
202
- $ context ,
203
- $ scope ,
204
- );
186
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
205
187
}
206
188
207
189
/**
208
190
* @see Drupal\Component\Assertion\Inspector::assertAllStrictArrays()
209
191
*/
210
192
private function specifyAssertAllStrictArrays (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
211
193
{
194
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
212
195
$ newType = new IterableType (
213
196
new MixedType (),
214
197
new ArrayType (
@@ -217,12 +200,7 @@ private function specifyAssertAllStrictArrays(MethodReflection $staticMethodRefl
217
200
),
218
201
);
219
202
220
- return $ this ->typeSpecifier ->create (
221
- $ node ->getArgs ()[0 ]->value ,
222
- $ newType ,
223
- $ context ,
224
- $ scope ,
225
- );
203
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
226
204
}
227
205
228
206
/**
@@ -272,46 +250,41 @@ private function specifyAssertAllHaveKey(MethodReflection $staticMethodReflectio
272
250
*/
273
251
private function specifyAssertAllIntegers (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
274
252
{
275
- return $ this ->typeSpecifier ->create (
276
- $ node ->getArgs ()[0 ]->value ,
277
- new IterableType (new MixedType (), new IntegerType ()),
278
- $ context ,
279
- $ scope ,
280
- );
253
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
254
+ $ newType = new IterableType (new MixedType (), new IntegerType ());
255
+
256
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
281
257
}
282
258
283
259
/**
284
260
* @see Drupal\Component\Assertion\Inspector::assertAllFloat()
285
261
*/
286
262
private function specifyAssertAllFloat (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
287
263
{
288
- return $ this ->typeSpecifier ->create (
289
- $ node ->getArgs ()[0 ]->value ,
290
- new IterableType (new MixedType (), new FloatType ()),
291
- $ context ,
292
- $ scope ,
293
- );
264
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
265
+ $ newType = new IterableType (new MixedType (), new FloatType ());
266
+
267
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
294
268
}
295
269
296
270
/**
297
271
* @see Drupal\Component\Assertion\Inspector::assertAllCallable()
298
272
*/
299
273
private function specifyAssertAllCallable (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
300
274
{
301
- return $ this ->typeSpecifier ->create (
302
- $ node ->getArgs ()[0 ]->value ,
303
- new IterableType (new MixedType (), new CallableType ()),
304
- $ context ,
305
- $ scope ,
306
- );
275
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
276
+ $ newType = new IterableType (new MixedType (), new CallableType ());
277
+
278
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
307
279
}
308
280
309
281
/**
310
282
* @see Drupal\Component\Assertion\Inspector::assertAllNotEmpty()
311
283
*/
312
284
private function specifyAssertAllNotEmpty (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
313
285
{
314
- $ non_empty_types = [
286
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
287
+ $ nonEmptyTypes = [
315
288
new NonEmptyArrayType (),
316
289
new ObjectType ('object ' ),
317
290
new IntersectionType ([new StringType (), new AccessoryNonEmptyStringType ()]),
@@ -320,55 +293,44 @@ private function specifyAssertAllNotEmpty(MethodReflection $staticMethodReflecti
320
293
new FloatType (),
321
294
new ResourceType (),
322
295
];
323
- $ newType = new IterableType (new MixedType (), new UnionType ($ non_empty_types ));
296
+ $ newType = new IterableType (new MixedType (), new UnionType ($ nonEmptyTypes ));
324
297
325
- return $ this ->typeSpecifier ->create (
326
- $ node ->getArgs ()[0 ]->value ,
327
- $ newType ,
328
- $ context ,
329
- $ scope ,
330
- );
298
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
331
299
}
332
300
333
301
/**
334
302
* @see Drupal\Component\Assertion\Inspector::assertAllNumeric()
335
303
*/
336
304
private function specifyAssertAllNumeric (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
337
305
{
338
- return $ this ->typeSpecifier ->create (
339
- $ node ->getArgs ()[0 ]->value ,
340
- new IterableType (new MixedType (), new UnionType ([new IntegerType (), new FloatType ()])),
341
- $ context ,
342
- $ scope ,
343
- );
306
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
307
+ $ newType = new IterableType (new MixedType (), new UnionType ([new IntegerType (), new FloatType ()]));
308
+
309
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
344
310
}
345
311
346
312
/**
347
313
* @see Drupal\Component\Assertion\Inspector::assertAllMatch()
348
314
*/
349
315
private function specifyAssertAllMatch (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
350
316
{
351
- return $ this ->typeSpecifier ->create (
352
- $ node ->getArgs ()[1 ]->value ,
353
- new IterableType (new MixedType (), new StringType ()),
354
- $ context ,
355
- $ scope ,
356
- );
317
+ $ traversableArg = $ node ->getArgs ()[1 ]->value ;
318
+ $ newType = new IterableType (new MixedType (), new StringType ());
319
+
320
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
357
321
}
358
322
359
323
/**
360
324
* @see Drupal\Component\Assertion\Inspector::assertAllRegularExpressionMatch()
361
325
*/
362
326
private function specifyAssertAllRegularExpressionMatch (MethodReflection $ staticMethodReflection , StaticCall $ node , Scope $ scope , TypeSpecifierContext $ context ): SpecifiedTypes
363
327
{
364
- return $ this ->typeSpecifier ->create (
365
- $ node ->getArgs ()[1 ]->value ,
366
- // Drupal treats any non-string input in traversable as invalid
367
- // value, so it is possible to narrow type here.
368
- new IterableType (new MixedType (), new StringType ()),
369
- $ context ,
370
- $ scope ,
371
- );
328
+ $ traversableArg = $ node ->getArgs ()[1 ]->value ;
329
+ // Drupal treats any non-string input in traversable as invalid
330
+ // value, so it is possible to narrow type here.
331
+ $ newType = new IterableType (new MixedType (), new StringType ());
332
+
333
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
372
334
}
373
335
374
336
/**
@@ -385,22 +347,15 @@ private function specifyAssertAllObjects(MethodReflection $staticMethodReflectio
385
347
386
348
$ argType = $ scope ->getType ($ arg ->value );
387
349
foreach ($ argType ->getConstantStrings () as $ stringType ) {
388
- $ classString = $ stringType ->getValue ();
389
- // PHPStan does not recognize a string argument like '\\Stringable'
390
- // as a class string, so we need to explicitly check it.
391
- if (!class_exists ($ classString ) && !interface_exists ($ classString )) {
392
- continue ;
350
+ if ($ stringType ->isClassString ()->yes ()) {
351
+ $ objectTypes [] = new ObjectType ($ stringType ->getValue ());
393
352
}
394
-
395
- $ objectTypes [] = new ObjectType ($ classString );
396
353
}
397
354
}
398
355
399
- return $ this ->typeSpecifier ->create (
400
- $ node ->getArgs ()[0 ]->value ,
401
- new IterableType (new MixedType (), TypeCombinator::union (...$ objectTypes )),
402
- $ context ,
403
- $ scope ,
404
- );
356
+ $ traversableArg = $ node ->getArgs ()[0 ]->value ;
357
+ $ newType = new IterableType (new MixedType (), TypeCombinator::union (...$ objectTypes ));
358
+
359
+ return $ this ->typeSpecifier ->create ($ traversableArg , $ newType , $ context , $ scope );
405
360
}
406
361
}
0 commit comments