Skip to content

Commit 358c483

Browse files
committed
add native property type support to NarrowPropertyUnionToCollectionRector
1 parent 8389f0d commit 358c483

File tree

7 files changed

+116
-36
lines changed

7 files changed

+116
-36
lines changed

rules-tests/TypedCollections/Rector/Property/NarrowPropertyUnionToCollectionRector/Fixture/array_null_collection.php.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NarrowPropertyUnionToCollectionRector\Fixture;
3+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
44

55
use Doctrine\Common\Collections\ArrayCollection;
66

@@ -16,7 +16,7 @@ final class SomePropertyWithManyTypes
1616
-----
1717
<?php
1818

19-
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NarrowPropertyUnionToCollectionRector\Fixture;
19+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
2020

2121
use Doctrine\Common\Collections\ArrayCollection;
2222

rules-tests/TypedCollections/Rector/Property/NarrowPropertyUnionToCollectionRector/Fixture/collection_with_null_type.php.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NarrowPropertyUnionToCollectionRector\Fixture;
3+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
44

55
use Doctrine\Common\Collections\Collection;
66

@@ -16,7 +16,7 @@ final class CollectionWithNullType
1616
-----
1717
<?php
1818

19-
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NarrowPropertyUnionToCollectionRector\Fixture;
19+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
2020

2121
use Doctrine\Common\Collections\Collection;
2222

rules-tests/TypedCollections/Rector/Property/NarrowPropertyUnionToCollectionRector/Fixture/extra_null_on_clear_property_type.php.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NarrowPropertyUnionToCollectionRector\Fixture;
3+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
44

55
use Doctrine\Common\Collections\ArrayCollection;
66
use Doctrine\Common\Collections\Collection;
@@ -17,7 +17,7 @@ final class ExtraNullOnClearPropertyType
1717
-----
1818
<?php
1919

20-
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NarrowPropertyUnionToCollectionRector\Fixture;
20+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
2121

2222
use Doctrine\Common\Collections\ArrayCollection;
2323
use Doctrine\Common\Collections\Collection;

rules-tests/TypedCollections/Rector/Property/NarrowPropertyUnionToCollectionRector/Fixture/some_file_with_settings_array.php.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NarrowPropertyUnionToCollectionRector\Fixture;
3+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
44

55
use Doctrine\Common\Collections\Collection;
66

@@ -16,7 +16,7 @@ final class SomePropertyWithManyTypes
1616
-----
1717
<?php
1818

19-
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NarrowPropertyUnionToCollectionRector\Fixture;
19+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
2020

2121
use Doctrine\Common\Collections\Collection;
2222

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
4+
5+
use Doctrine\Common\Collections\Collection;
6+
7+
final class UnionNativeType
8+
{
9+
private Collection|array|null $keyValues = null;
10+
}
11+
12+
?>
13+
-----
14+
<?php
15+
16+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\Fixture;
17+
18+
use Doctrine\Common\Collections\Collection;
19+
20+
final class UnionNativeType
21+
{
22+
private \Doctrine\Common\Collections\Collection $keyValues;
23+
}
24+
25+
?>

rules-tests/TypedCollections/Rector/Property/NarrowPropertyUnionToCollectionRector/NarrowPropertyUnionToCollectionRectorTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NarrowPropertyUnionToCollectionRector;
5+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector;
66

77
use Iterator;
88
use PHPUnit\Framework\Attributes\DataProvider;

rules/TypedCollections/Rector/Property/NarrowPropertyUnionToCollectionRector.php

Lines changed: 82 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,24 @@
66

77
use Doctrine\Common\Collections\Collection;
88
use PhpParser\Node;
9+
use PhpParser\Node\Expr;
910
use PhpParser\Node\Name;
11+
use PhpParser\Node\Name\FullyQualified;
12+
use PhpParser\Node\Stmt\Class_;
1013
use PhpParser\Node\Stmt\Property;
14+
use PhpParser\Node\UnionType;
1115
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
12-
use PHPStan\Reflection\ClassReflection;
16+
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
1317
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
1418
use Rector\Comments\NodeDocBlock\DocBlockUpdater;
19+
use Rector\Doctrine\Enum\DoctrineClass;
1520
use Rector\Doctrine\TypedCollections\DocBlockProcessor\UnionCollectionTagValueNodeNarrower;
16-
use Rector\PHPStan\ScopeFetcher;
1721
use Rector\Rector\AbstractRector;
1822
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
1923
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
2024

2125
/**
22-
* @see \Rector\Doctrine\Tests\TypedCollections\Rector\ClassMethod\NarrowParamUnionToCollectionRector\NarrowParamUnionToCollectionRectorTest
26+
* @see \Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\NarrowPropertyUnionToCollectionRectorTest
2327
*/
2428
final class NarrowPropertyUnionToCollectionRector extends AbstractRector
2529
{
@@ -33,7 +37,7 @@ public function __construct(
3337
public function getRuleDefinition(): RuleDefinition
3438
{
3539
return new RuleDefinition(
36-
'Narrow union type to Collection type in property docblock',
40+
'Narrow union type to Collection type in property docblock and native type declaration',
3741
[
3842
new CodeSample(
3943
<<<'CODE_SAMPLE'
@@ -66,48 +70,99 @@ class SomeClass
6670

6771
public function getNodeTypes(): array
6872
{
69-
return [Property::class];
73+
return [Class_::class];
7074
}
7175

7276
/**
73-
* @param Property $node
77+
* @param Class_ $node
7478
*/
75-
public function refactor(Node $node): ?Property
79+
public function refactor(Node $node): ?Class_
7680
{
77-
if ($node->isAbstract()) {
78-
return null;
81+
$hasChanged = false;
82+
foreach ($node->getProperties() as $property) {
83+
if ($property->isAbstract()) {
84+
continue;
85+
}
86+
87+
if ($this->refactorPropertyDocBlock($property)) {
88+
$hasChanged = true;
89+
}
90+
91+
if ($this->refactorNativePropertyType($property)) {
92+
$hasChanged = true;
93+
}
7994
}
8095

81-
$scope = ScopeFetcher::fetch($node);
82-
$classReflection = $scope->getClassReflection();
83-
if (! $classReflection instanceof ClassReflection) {
84-
return null;
96+
if ($hasChanged) {
97+
return $node;
8598
}
8699

87-
if ($classReflection->isInterface()) {
88-
return null;
100+
return null;
101+
}
102+
103+
private function hasNativeTypeCollection(Property $property): bool
104+
{
105+
if (! $property->type instanceof Name) {
106+
return false;
89107
}
90108

91-
$propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
109+
return $this->isName($property->type, Collection::class);
110+
}
92111

93-
$varTagValueNode = $propertyPhpDocInfo->getVarTagValueNode();
94-
if (! $varTagValueNode instanceof VarTagValueNode) {
95-
return null;
112+
private function isCollectionName(Node $node): bool
113+
{
114+
if (! $node instanceof Name) {
115+
return false;
116+
}
117+
118+
return $this->isName($node, DoctrineClass::COLLECTION);
119+
}
120+
121+
private function refactorNativePropertyType(Property $property): bool
122+
{
123+
if (! $property->type instanceof UnionType) {
124+
return false;
96125
}
97126

98-
$hasNativeCollectionType = false;
99-
if ($node->type instanceof Name && $this->isName($node->type, Collection::class)) {
100-
$hasNativeCollectionType = true;
127+
foreach ($property->type->types as $uniontedType) {
128+
if (! $this->isCollectionName($uniontedType)) {
129+
continue;
130+
}
131+
132+
// narrow to pure collection
133+
$property->type = new FullyQualified(DoctrineClass::COLLECTION);
134+
135+
// remove default, as will be defined in constructor by another rule
136+
if ($property->props[0]->default instanceof Expr) {
137+
$property->props[0]->default = null;
138+
}
139+
140+
return true;
141+
}
142+
143+
return false;
144+
}
145+
146+
private function refactorPropertyDocBlock(Property $property): bool
147+
{
148+
$propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNode($property);
149+
if (! $propertyPhpDocInfo instanceof PhpDocInfo) {
150+
return false;
101151
}
102152

103-
$hasChanged = $this->unionCollectionTagValueNodeNarrower->narrow($varTagValueNode, $hasNativeCollectionType);
153+
$varTagValueNode = $propertyPhpDocInfo->getVarTagValueNode();
104154

105-
if ($hasChanged === false) {
106-
return null;
155+
if (! $varTagValueNode instanceof VarTagValueNode) {
156+
return false;
107157
}
108158

109-
$this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node);
159+
$hasNativeCollectionType = $this->hasNativeTypeCollection($property);
160+
161+
if ($this->unionCollectionTagValueNodeNarrower->narrow($varTagValueNode, $hasNativeCollectionType)) {
162+
$this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($property);
163+
return true;
164+
}
110165

111-
return $node;
166+
return false;
112167
}
113168
}

0 commit comments

Comments
 (0)