Skip to content

Commit 306401c

Browse files
authored
Add array with dim fetch assign support to AddMethodCallBasedStrictParamTypeRector (#7506)
* add intersection fixture * remove accessor array list type * remove accessory array type, to allow array type fill * move to correct type method * extract NodeTypeCorrector service to wrap similar logic * update names
1 parent 3f23985 commit 306401c

File tree

10 files changed

+138
-46
lines changed

10 files changed

+138
-46
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddMethodCallBasedStrictParamTypeRector\FixtureIntersection;
6+
7+
final class CoverIntersection
8+
{
9+
public function run(array $values): void
10+
{
11+
$items = [];
12+
13+
foreach ($values as $value) {
14+
$items[] = 10;
15+
}
16+
17+
$this->nextItems($items);
18+
}
19+
20+
private function nextItems($items): void
21+
{
22+
}
23+
}
24+
25+
?>
26+
-----
27+
<?php
28+
29+
declare(strict_types=1);
30+
31+
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddMethodCallBasedStrictParamTypeRector\FixtureIntersection;
32+
33+
final class CoverIntersection
34+
{
35+
public function run(array $values): void
36+
{
37+
$items = [];
38+
39+
foreach ($values as $value) {
40+
$items[] = 10;
41+
}
42+
43+
$this->nextItems($items);
44+
}
45+
46+
private function nextItems(array $items): void
47+
{
48+
}
49+
}
50+
51+
?>

rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,9 @@ private function resolveExceptionArgumentPosition(Name $exceptionName): ?int
210210
$extendedMethodReflection->getVariants()
211211
);
212212

213-
foreach ($extendedParametersAcceptor->getParameters() as $position => $parameterReflectionWithPhpDoc) {
214-
$parameterType = $parameterReflectionWithPhpDoc->getType();
215-
$className = ClassNameFromObjectTypeResolver::resolve($parameterReflectionWithPhpDoc->getType());
213+
foreach ($extendedParametersAcceptor->getParameters() as $position => $extendedParameterReflection) {
214+
$parameterType = $extendedParameterReflection->getType();
215+
$className = ClassNameFromObjectTypeResolver::resolve($extendedParameterReflection->getType());
216216

217217
if ($className === null) {
218218
continue;

rules/CodingStyle/Rector/ClassConst/RemoveFinalFromConstRector.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ public function refactor(Node $node): ?Node
6363
}
6464

6565
$hasChanged = false;
66-
foreach ($node->getConstants() as $constant) {
67-
if (! $constant->isFinal()) {
66+
foreach ($node->getConstants() as $classConst) {
67+
if (! $classConst->isFinal()) {
6868
continue;
6969
}
7070

71-
$this->visibilityManipulator->removeFinal($constant);
71+
$this->visibilityManipulator->removeFinal($classConst);
7272
$hasChanged = true;
7373
}
7474

rules/Php71/Rector/FuncCall/RemoveExtraParametersRector.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ private function resolveMaximumAllowedParameterCount(
147147
MethodReflection | FunctionReflection $functionLikeReflection
148148
): int {
149149
$parameterCounts = [0];
150-
foreach ($functionLikeReflection->getVariants() as $variant) {
151-
$parameterCounts[] = count($variant->getParameters());
150+
foreach ($functionLikeReflection->getVariants() as $parametersAcceptor) {
151+
$parameterCounts[] = count($parametersAcceptor->getParameters());
152152
}
153153

154154
return max($parameterCounts);

rules/TypeDeclaration/Rector/ClassMethod/BoolReturnTypeFromBooleanStrictReturnsRector.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ private function isNativeBooleanReturnTypeFuncCall(FuncCall $funcCall): bool
170170
return false;
171171
}
172172

173-
foreach ($functionReflection->getVariants() as $variant) {
174-
if (! $variant->getNativeReturnType()->isBoolean()->yes()) {
173+
foreach ($functionReflection->getVariants() as $extendedParametersAcceptor) {
174+
if (! $extendedParametersAcceptor->getNativeReturnType()->isBoolean()->yes()) {
175175
return false;
176176
}
177177
}

rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddReturnDocblockForArrayDimAssignedObjectRector.php

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@
1414
use PhpParser\Node\Stmt\Function_;
1515
use PhpParser\Node\Stmt\Return_;
1616
use PhpParser\NodeVisitor;
17-
use PHPStan\Type\Accessory\AccessoryArrayListType;
1817
use PHPStan\Type\ArrayType;
19-
use PHPStan\Type\IntersectionType;
2018
use PHPStan\Type\MixedType;
2119
use PHPStan\Type\ObjectType;
2220
use PHPStan\Type\Type;
@@ -151,23 +149,17 @@ public function refactor(Node $node): ?Node
151149
return $node;
152150
}
153151

154-
private function matchArrayObjectType(Type $returnedType): ?Type
152+
private function matchArrayObjectType(Type $type): ?Type
155153
{
156-
if ($returnedType instanceof IntersectionType) {
157-
foreach ($returnedType->getTypes() as $intersectionedType) {
158-
if ($intersectionedType instanceof AccessoryArrayListType) {
159-
continue;
160-
}
161-
162-
if ($intersectionedType instanceof ArrayType && $intersectionedType->getItemType() instanceof ObjectType) {
163-
return $intersectionedType->getItemType();
164-
}
154+
if (! $type instanceof ArrayType) {
155+
return null;
156+
}
165157

166-
return null;
167-
}
158+
if (! $type->getItemType() instanceof ObjectType) {
159+
return null;
168160
}
169161

170-
return null;
162+
return $type->getItemType();
171163
}
172164

173165
private function isVariableExclusivelyArrayDimAssigned(

src/NodeAnalyzer/VariadicAnalyzer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ public function hasVariadicParameters(FuncCall | StaticCall | MethodCall $call):
3030

3131
private function hasVariadicVariant(MethodReflection | FunctionReflection $functionLikeReflection): bool
3232
{
33-
foreach ($functionLikeReflection->getVariants() as $variant) {
33+
foreach ($functionLikeReflection->getVariants() as $parametersAcceptor) {
3434
// can be any number of arguments → nothing to limit here
35-
if ($variant->isVariadic()) {
35+
if ($parametersAcceptor->isVariadic()) {
3636
return true;
3737
}
3838
}

src/NodeCollector/NodeAnalyzer/ArrayCallableMethodMatcher.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,8 @@ private function resolveClassContextType(
178178
$extendedMethodReflection->getVariants()
179179
);
180180

181-
foreach ($extendedParametersAcceptor->getParameters() as $parameterReflectionWithPhpDoc) {
182-
if (! $parameterReflectionWithPhpDoc->getDefaultValue() instanceof Type) {
181+
foreach ($extendedParametersAcceptor->getParameters() as $extendedParameterReflection) {
182+
if (! $extendedParameterReflection->getDefaultValue() instanceof Type) {
183183
return new MixedType();
184184
}
185185
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
// dump($cleanTypes);
54+
// die;
55+
56+
if (count($cleanTypes) === 1) {
57+
return $cleanTypes[0];
58+
}
59+
60+
return new IntersectionType($cleanTypes);
61+
}
62+
}

src/NodeTypeResolver/NodeTypeResolver.php

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,6 @@
5252
use Rector\NodeTypeResolver\Contract\NodeTypeResolverAwareInterface;
5353
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
5454
use Rector\NodeTypeResolver\Node\AttributeKey;
55-
use Rector\NodeTypeResolver\NodeTypeCorrector\AccessoryNonEmptyArrayTypeCorrector;
56-
use Rector\NodeTypeResolver\NodeTypeCorrector\AccessoryNonEmptyStringTypeCorrector;
57-
use Rector\NodeTypeResolver\NodeTypeCorrector\GenericClassStringTypeCorrector;
5855
use Rector\NodeTypeResolver\PHPStan\ObjectWithoutClassTypeWithParentTypes;
5956
use Rector\Php\PhpVersionProvider;
6057
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
@@ -80,10 +77,8 @@ final class NodeTypeResolver
8077
public function __construct(
8178
private readonly ObjectTypeSpecifier $objectTypeSpecifier,
8279
private readonly ClassAnalyzer $classAnalyzer,
83-
private readonly GenericClassStringTypeCorrector $genericClassStringTypeCorrector,
80+
private readonly NodeTypeCorrector $nodeTypeCorrector,
8481
private readonly ReflectionProvider $reflectionProvider,
85-
private readonly AccessoryNonEmptyStringTypeCorrector $accessoryNonEmptyStringTypeCorrector,
86-
private readonly AccessoryNonEmptyArrayTypeCorrector $accessoryNonEmptyArrayTypeCorrector,
8782
private readonly RenamedClassesDataCollector $renamedClassesDataCollector,
8883
private readonly NodeNameResolver $nodeNameResolver,
8984
private readonly PhpVersionProvider $phpVersionProvider,
@@ -201,7 +196,7 @@ public function getType(Node $node): Type
201196
$type = $this->resolveByNodeTypeResolvers($node);
202197

203198
if ($type instanceof Type) {
204-
$type = $this->correctType($type);
199+
$type = $this->nodeTypeCorrector->correctType($type);
205200

206201
if ($type instanceof ObjectType) {
207202
$scope = $node->getAttribute(AttributeKey::SCOPE);
@@ -236,7 +231,7 @@ public function getType(Node $node): Type
236231
return new MixedType();
237232
}
238233

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

241236
// hot fix for phpstan not resolving chain method calls
242237
if (! $node instanceof MethodCall) {
@@ -284,7 +279,7 @@ public function getNativeType(Expr $expr): Type
284279
return new ObjectWithoutClassType();
285280
}
286281

287-
return $this->correctType($type);
282+
return $this->nodeTypeCorrector->correctType($type);
288283
}
289284

290285
return $this->resolveNativeUnionType($type);
@@ -372,14 +367,6 @@ public function isMethodStaticCallOrClassMethodObjectType(Node $node, ObjectType
372367
return $classReflection->hasTraitUse($objectType->getClassName());
373368
}
374369

375-
private function correctType(Type $type): Type
376-
{
377-
$type = $this->accessoryNonEmptyStringTypeCorrector->correct($type);
378-
$type = $this->genericClassStringTypeCorrector->correct($type);
379-
380-
return $this->accessoryNonEmptyArrayTypeCorrector->correct($type);
381-
}
382-
383370
/**
384371
* Allow pull type from
385372
*

0 commit comments

Comments
 (0)