Skip to content

Commit 361eb2f

Browse files
Niklanmglaman
andauthored
Improve the InspectorTypeExtension and its tests (#871)
* Improve the InspectorTypeExtension and its tests * Improve the InspectorTypeExtension and its tests * Fix PHPCS --------- Co-authored-by: Matt Glaman <[email protected]>
1 parent b8c6664 commit 361eb2f

File tree

2 files changed

+262
-256
lines changed

2 files changed

+262
-256
lines changed

src/Type/InspectorTypeExtension.php

Lines changed: 63 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
use PHPStan\Type\TypeCombinator;
3232
use PHPStan\Type\UnionType;
3333
use Stringable;
34-
use function class_exists;
35-
use function interface_exists;
3634

3735
final class InspectorTypeExtension implements StaticMethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
3836
{
@@ -100,20 +98,20 @@ public function specifyTypes(MethodReflection $staticMethodReflection, StaticCal
10098
*/
10199
private function specifyAssertAll(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
102100
{
103-
$callable = $node->getArgs()[0]->value;
104-
$callableInfo = $scope->getType($callable);
101+
$callableArg = $node->getArgs()[0]->value;
102+
$callableType = $scope->getType($callableArg);
105103

106-
if (!$callableInfo->isCallable()->yes()) {
104+
if (!$callableType->isCallable()->yes()) {
107105
return new SpecifiedTypes();
108106
}
109107

110-
$traversable = $node->getArgs()[1]->value;
111-
$traversableInfo = $scope->getType($traversable);
108+
$traversableArg = $node->getArgs()[1]->value;
109+
$traversableType = $scope->getType($traversableArg);
112110

113111
// If it is already not mixed (narrowed by other code, like
114112
// '::assertAllArray()'), we could not provide any additional
115113
// information. We can only narrow this method to 'array<mixed, mixed>'.
116-
if (!$traversableInfo->equals(new MixedType())) {
114+
if (!$traversableType->equals(new MixedType())) {
117115
return new SpecifiedTypes();
118116
}
119117

@@ -130,85 +128,70 @@ private function specifyAssertAll(MethodReflection $staticMethodReflection, Stat
130128
return new SpecifiedTypes();
131129
}
132130

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);
139134
}
140135

141136
/**
142137
* @see Drupal\Component\Assertion\Inspector::assertAllStrings()
143138
*/
144139
private function specifyAssertAllStrings(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
145140
{
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);
152145
}
153146

154147
/**
155148
* @see Drupal\Component\Assertion\Inspector::assertAllStringable()
156149
*/
157150
private function specifyAssertAllStringable(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
158151
{
152+
$traversableArg = $node->getArgs()[0]->value;
159153
// 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);
169158
}
170159

171160
/**
172161
* @see Drupal\Component\Assertion\Inspector::assertAllArrays()
173162
*/
174163
private function specifyAssertAllArrays(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
175164
{
165+
$traversableArg = $node->getArgs()[0]->value;
176166
$arrayType = new ArrayType(new MixedType(), new MixedType());
177167
$newType = new IterableType(new MixedType(), $arrayType);
178168

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);
185170
}
186171

187172
/**
188173
* @see Drupal\Component\Assertion\Inspector::assertStrictArray()
189174
*/
190175
private function specifyAssertStrictArray(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
191176
{
177+
$traversableArg = $node->getArgs()[0]->value;
192178
$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.
195182
IntegerRangeType::createAllGreaterThanOrEqualTo(0),
196183
new MixedType(),
197184
);
198185

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);
205187
}
206188

207189
/**
208190
* @see Drupal\Component\Assertion\Inspector::assertAllStrictArrays()
209191
*/
210192
private function specifyAssertAllStrictArrays(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
211193
{
194+
$traversableArg = $node->getArgs()[0]->value;
212195
$newType = new IterableType(
213196
new MixedType(),
214197
new ArrayType(
@@ -217,12 +200,7 @@ private function specifyAssertAllStrictArrays(MethodReflection $staticMethodRefl
217200
),
218201
);
219202

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);
226204
}
227205

228206
/**
@@ -272,46 +250,41 @@ private function specifyAssertAllHaveKey(MethodReflection $staticMethodReflectio
272250
*/
273251
private function specifyAssertAllIntegers(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
274252
{
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);
281257
}
282258

283259
/**
284260
* @see Drupal\Component\Assertion\Inspector::assertAllFloat()
285261
*/
286262
private function specifyAssertAllFloat(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
287263
{
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);
294268
}
295269

296270
/**
297271
* @see Drupal\Component\Assertion\Inspector::assertAllCallable()
298272
*/
299273
private function specifyAssertAllCallable(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
300274
{
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);
307279
}
308280

309281
/**
310282
* @see Drupal\Component\Assertion\Inspector::assertAllNotEmpty()
311283
*/
312284
private function specifyAssertAllNotEmpty(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
313285
{
314-
$non_empty_types = [
286+
$traversableArg = $node->getArgs()[0]->value;
287+
$nonEmptyTypes = [
315288
new NonEmptyArrayType(),
316289
new ObjectType('object'),
317290
new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]),
@@ -320,55 +293,44 @@ private function specifyAssertAllNotEmpty(MethodReflection $staticMethodReflecti
320293
new FloatType(),
321294
new ResourceType(),
322295
];
323-
$newType = new IterableType(new MixedType(), new UnionType($non_empty_types));
296+
$newType = new IterableType(new MixedType(), new UnionType($nonEmptyTypes));
324297

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);
331299
}
332300

333301
/**
334302
* @see Drupal\Component\Assertion\Inspector::assertAllNumeric()
335303
*/
336304
private function specifyAssertAllNumeric(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
337305
{
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);
344310
}
345311

346312
/**
347313
* @see Drupal\Component\Assertion\Inspector::assertAllMatch()
348314
*/
349315
private function specifyAssertAllMatch(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
350316
{
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);
357321
}
358322

359323
/**
360324
* @see Drupal\Component\Assertion\Inspector::assertAllRegularExpressionMatch()
361325
*/
362326
private function specifyAssertAllRegularExpressionMatch(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
363327
{
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);
372334
}
373335

374336
/**
@@ -385,22 +347,15 @@ private function specifyAssertAllObjects(MethodReflection $staticMethodReflectio
385347

386348
$argType = $scope->getType($arg->value);
387349
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());
393352
}
394-
395-
$objectTypes[] = new ObjectType($classString);
396353
}
397354
}
398355

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);
405360
}
406361
}

0 commit comments

Comments
 (0)