Skip to content

Commit 26286a8

Browse files
committed
extract NodeTypeCorrector service to wrap similar logic
1 parent c419fe2 commit 26286a8

2 files changed

Lines changed: 84 additions & 42 deletions

File tree

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\NodeTypeResolver;
6+
7+
use PHPStan\Type\Accessory\AccessoryArrayListType;
8+
use PHPStan\Type\IntersectionType;
9+
use PHPStan\Type\Type;
10+
use Rector\NodeTypeResolver\NodeTypeCorrector\AccessoryNonEmptyArrayTypeCorrector;
11+
use Rector\NodeTypeResolver\NodeTypeCorrector\AccessoryNonEmptyStringTypeCorrector;
12+
use Rector\NodeTypeResolver\NodeTypeCorrector\GenericClassStringTypeCorrector;
13+
14+
/**
15+
* This service correct unnecessary intersection/union types that do not bring any value.
16+
* We focus on scalar types like "array", "string", "int" etc.,
17+
* to print them as valid type declarations.
18+
*/
19+
final readonly class NodeTypeCorrector
20+
{
21+
public function __construct(
22+
private AccessoryNonEmptyStringTypeCorrector $accessoryNonEmptyStringTypeCorrector,
23+
private GenericClassStringTypeCorrector $genericClassStringTypeCorrector,
24+
private AccessoryNonEmptyArrayTypeCorrector $accessoryNonEmptyArrayTypeCorrector,
25+
) {
26+
}
27+
28+
public function correctType(Type $type): Type
29+
{
30+
$type = $this->accessoryNonEmptyStringTypeCorrector->correct($type);
31+
$type = $this->genericClassStringTypeCorrector->correct($type);
32+
33+
$type = $this->removeAccessoryArrayListType($type);
34+
35+
return $this->accessoryNonEmptyArrayTypeCorrector->correct($type);
36+
}
37+
38+
private function removeAccessoryArrayListType(Type $type): Type
39+
{
40+
if (! $type instanceof IntersectionType) {
41+
return $type;
42+
}
43+
44+
$cleanTypes = [];
45+
foreach ($type->getTypes() as $intersectionType) {
46+
if ($intersectionType instanceof AccessoryArrayListType) {
47+
continue;
48+
}
49+
50+
$cleanTypes[] = $intersectionType;
51+
}
52+
53+
if (count($cleanTypes) === 1) {
54+
return $cleanTypes[0];
55+
}
56+
57+
return new IntersectionType($cleanTypes);
58+
}
59+
}

src/NodeTypeResolver/NodeTypeResolver.php

Lines changed: 25 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,11 @@
2929
use PHPStan\Reflection\ClassReflection;
3030
use PHPStan\Reflection\Native\NativeFunctionReflection;
3131
use PHPStan\Reflection\ReflectionProvider;
32-
use PHPStan\Type\Accessory\AccessoryArrayListType;
3332
use PHPStan\Type\ArrayType;
3433
use PHPStan\Type\Constant\ConstantArrayType;
3534
use PHPStan\Type\Constant\ConstantBooleanType;
3635
use PHPStan\Type\Constant\ConstantStringType;
3736
use PHPStan\Type\ErrorType;
38-
use PHPStan\Type\IntersectionType;
3937
use PHPStan\Type\MixedType;
4038
use PHPStan\Type\NeverType;
4139
use PHPStan\Type\NullType;
@@ -54,9 +52,6 @@
5452
use Rector\NodeTypeResolver\Contract\NodeTypeResolverAwareInterface;
5553
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
5654
use Rector\NodeTypeResolver\Node\AttributeKey;
57-
use Rector\NodeTypeResolver\NodeTypeCorrector\AccessoryNonEmptyArrayTypeCorrector;
58-
use Rector\NodeTypeResolver\NodeTypeCorrector\AccessoryNonEmptyStringTypeCorrector;
59-
use Rector\NodeTypeResolver\NodeTypeCorrector\GenericClassStringTypeCorrector;
6055
use Rector\NodeTypeResolver\PHPStan\ObjectWithoutClassTypeWithParentTypes;
6156
use Rector\Php\PhpVersionProvider;
6257
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
@@ -82,10 +77,8 @@ final class NodeTypeResolver
8277
public function __construct(
8378
private readonly ObjectTypeSpecifier $objectTypeSpecifier,
8479
private readonly ClassAnalyzer $classAnalyzer,
85-
private readonly GenericClassStringTypeCorrector $genericClassStringTypeCorrector,
80+
private readonly NodeTypeCorrector $nodeTypeCorrector,
8681
private readonly ReflectionProvider $reflectionProvider,
87-
private readonly AccessoryNonEmptyStringTypeCorrector $accessoryNonEmptyStringTypeCorrector,
88-
private readonly AccessoryNonEmptyArrayTypeCorrector $accessoryNonEmptyArrayTypeCorrector,
8982
private readonly RenamedClassesDataCollector $renamedClassesDataCollector,
9083
private readonly NodeNameResolver $nodeNameResolver,
9184
private readonly PhpVersionProvider $phpVersionProvider,
@@ -203,7 +196,7 @@ public function getType(Node $node): Type
203196
$type = $this->resolveByNodeTypeResolvers($node);
204197

205198
if ($type instanceof Type) {
206-
$type = $this->correctType($type);
199+
$type = $this->nodeTypeCorrector->correctType($type);
207200

208201
if ($type instanceof ObjectType) {
209202
$scope = $node->getAttribute(AttributeKey::SCOPE);
@@ -238,7 +231,7 @@ public function getType(Node $node): Type
238231
return new MixedType();
239232
}
240233

241-
$type = $this->correctType($scope->getType($node));
234+
$type = $this->nodeTypeCorrector->correctType($scope->getType($node));
242235

243236
// hot fix for phpstan not resolving chain method calls
244237
if (! $node instanceof MethodCall) {
@@ -286,7 +279,7 @@ public function getNativeType(Expr $expr): Type
286279
return new ObjectWithoutClassType();
287280
}
288281

289-
return $this->correctType($type);
282+
return $this->nodeTypeCorrector->correctType($type);
290283
}
291284

292285
return $this->resolveNativeUnionType($type);
@@ -374,16 +367,6 @@ public function isMethodStaticCallOrClassMethodObjectType(Node $node, ObjectType
374367
return $classReflection->hasTraitUse($objectType->getClassName());
375368
}
376369

377-
private function correctType(Type $type): Type
378-
{
379-
$type = $this->accessoryNonEmptyStringTypeCorrector->correct($type);
380-
$type = $this->genericClassStringTypeCorrector->correct($type);
381-
382-
$type = $this->cleanArrayIntersectionType($type);
383-
384-
return $this->accessoryNonEmptyArrayTypeCorrector->correct($type);
385-
}
386-
387370
/**
388371
* Allow pull type from
389372
*
@@ -680,25 +663,25 @@ private function isSubstrOnPHP74(FuncCall $funcCall): bool
680663
return ! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_80);
681664
}
682665

683-
private function cleanArrayIntersectionType(Type $type): Type
684-
{
685-
if (! $type instanceof IntersectionType) {
686-
return $type;
687-
}
688-
689-
$cleanTypes = [];
690-
foreach ($type->getTypes() as $intersectionType) {
691-
if ($intersectionType instanceof AccessoryArrayListType) {
692-
continue;
693-
}
694-
695-
$cleanTypes[] = $intersectionType;
696-
}
697-
698-
if (count($cleanTypes) === 1) {
699-
return $cleanTypes[0];
700-
}
701-
702-
return new IntersectionType($cleanTypes);
703-
}
666+
// private function cleanArrayIntersectionType(Type $type): Type
667+
// {
668+
// if (! $type instanceof IntersectionType) {
669+
// return $type;
670+
// }
671+
//
672+
// $cleanTypes = [];
673+
// foreach ($type->getTypes() as $intersectionType) {
674+
// if ($intersectionType instanceof AccessoryArrayListType) {
675+
// continue;
676+
// }
677+
//
678+
// $cleanTypes[] = $intersectionType;
679+
// }
680+
//
681+
// if (count($cleanTypes) === 1) {
682+
// return $cleanTypes[0];
683+
// }
684+
//
685+
// return new IntersectionType($cleanTypes);
686+
// }
704687
}

0 commit comments

Comments
 (0)