Skip to content

Commit e05e393

Browse files
authored
add list<...> support to AddArrayFunctionClosureParamTypeRector (#7116)
1 parent c8c320c commit e05e393

File tree

2 files changed

+84
-17
lines changed

2 files changed

+84
-17
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Rector\Tests\TypeDeclaration\Rector\FuncCall\AddArrayFunctionClosureParamTypeRector\Fixture;
4+
5+
final class ArrayFilterWithDocblockListType
6+
{
7+
/**
8+
* @param list<int> $items
9+
*/
10+
public function run(array $items)
11+
{
12+
$result = array_filter($items, fn ($item) => $item * 2);
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\Tests\TypeDeclaration\Rector\FuncCall\AddArrayFunctionClosureParamTypeRector\Fixture;
21+
22+
final class ArrayFilterWithDocblockListType
23+
{
24+
/**
25+
* @param list<int> $items
26+
*/
27+
public function run(array $items)
28+
{
29+
$result = array_filter($items, fn (int $item) => $item * 2);
30+
}
31+
}
32+
33+
?>

rules/TypeDeclaration/Rector/FuncCall/AddArrayFunctionClosureParamTypeRector.php

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
use PhpParser\Node\Expr\ArrowFunction;
99
use PhpParser\Node\Expr\Closure;
1010
use PhpParser\Node\Expr\FuncCall;
11+
use PHPStan\Type\Accessory\AccessoryArrayListType;
1112
use PHPStan\Type\ArrayType;
1213
use PHPStan\Type\Constant\ConstantArrayType;
14+
use PHPStan\Type\IntersectionType;
1315
use PHPStan\Type\MixedType;
16+
use PHPStan\Type\Type;
1417
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
1518
use Rector\Rector\AbstractRector;
1619
use Rector\StaticTypeMapper\StaticTypeMapper;
@@ -26,7 +29,7 @@
2629
final class AddArrayFunctionClosureParamTypeRector extends AbstractRector implements MinPhpVersionInterface
2730
{
2831
public function __construct(
29-
private readonly StaticTypeMapper $staticTypeMapper
32+
private readonly StaticTypeMapper $staticTypeMapper,
3033
) {
3134
}
3235

@@ -73,6 +76,8 @@ public function refactor(Node $node): ?Node
7376
return null;
7477
}
7578

79+
$hasChanged = false;
80+
7681
foreach (NativeFuncCallPositions::ARRAY_AND_CALLBACK_POSITIONS as $functionName => $positions) {
7782
if (! $this->isName($node, $functionName)) {
7883
continue;
@@ -96,27 +101,29 @@ public function refactor(Node $node): ?Node
96101
}
97102

98103
$passedExprType = $this->getType($node->getArgs()[$arrayPosition]->value);
99-
if ($passedExprType instanceof ConstantArrayType || $passedExprType instanceof ArrayType) {
100-
$singlePassedExprType = $passedExprType->getItemType();
101-
102-
if ($singlePassedExprType instanceof MixedType) {
103-
continue;
104-
}
105104

106-
$paramType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode(
107-
$singlePassedExprType,
108-
TypeKind::PARAM
109-
);
110-
111-
if (! $paramType instanceof Node) {
112-
continue;
113-
}
105+
$singlePassedExprType = $this->resolveArrayItemType($passedExprType);
106+
if (! $singlePassedExprType instanceof Type) {
107+
continue;
108+
}
109+
if ($singlePassedExprType instanceof MixedType) {
110+
continue;
111+
}
114112

115-
$arrowFunctionParam->type = $paramType;
113+
$paramType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode(
114+
$singlePassedExprType,
115+
TypeKind::PARAM
116+
);
116117

117-
return $node;
118+
if (! $paramType instanceof Node) {
119+
continue;
118120
}
119121

122+
$hasChanged = true;
123+
$arrowFunctionParam->type = $paramType;
124+
}
125+
126+
if ($hasChanged === false) {
120127
return null;
121128
}
122129

@@ -127,4 +134,31 @@ public function provideMinPhpVersion(): int
127134
{
128135
return PhpVersionFeature::SCALAR_TYPES;
129136
}
137+
138+
private function resolveArrayItemType(Type $mainType): ?Type
139+
{
140+
if ($mainType instanceof ConstantArrayType || $mainType instanceof ArrayType) {
141+
return $mainType->getItemType();
142+
}
143+
144+
if ($mainType instanceof IntersectionType) {
145+
foreach ($mainType->getTypes() as $subType) {
146+
if ($subType instanceof AccessoryArrayListType) {
147+
continue;
148+
}
149+
150+
if (! $subType->isArray()->yes()) {
151+
continue;
152+
}
153+
154+
if (! $subType instanceof ArrayType) {
155+
continue;
156+
}
157+
158+
return $subType->getItemType();
159+
}
160+
}
161+
162+
return null;
163+
}
130164
}

0 commit comments

Comments
 (0)