Skip to content

Commit a3480f3

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

7 files changed

Lines changed: 92 additions & 41 deletions

File tree

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

Lines changed: 25 additions & 0 deletions
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: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@
77
use Doctrine\Common\Collections\Collection;
88
use PhpParser\Node;
99
use PhpParser\Node\Name;
10+
use PhpParser\Node\Stmt\Class_;
1011
use PhpParser\Node\Stmt\Property;
1112
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
12-
use PHPStan\Reflection\ClassReflection;
1313
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
1414
use Rector\Comments\NodeDocBlock\DocBlockUpdater;
15+
use Rector\Doctrine\Enum\DoctrineClass;
1516
use Rector\Doctrine\TypedCollections\DocBlockProcessor\UnionCollectionTagValueNodeNarrower;
16-
use Rector\PHPStan\ScopeFetcher;
1717
use Rector\Rector\AbstractRector;
1818
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
1919
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
2020

2121
/**
22-
* @see \Rector\Doctrine\Tests\TypedCollections\Rector\ClassMethod\NarrowParamUnionToCollectionRector\NarrowParamUnionToCollectionRectorTest
22+
* @see \Rector\Doctrine\Tests\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector\NarrowPropertyUnionToCollectionRectorTest
2323
*/
2424
final class NarrowPropertyUnionToCollectionRector extends AbstractRector
2525
{
@@ -33,7 +33,7 @@ public function __construct(
3333
public function getRuleDefinition(): RuleDefinition
3434
{
3535
return new RuleDefinition(
36-
'Narrow union type to Collection type in property docblock',
36+
'Narrow union type to Collection type in property docblock and native type declaration',
3737
[
3838
new CodeSample(
3939
<<<'CODE_SAMPLE'
@@ -66,48 +66,74 @@ class SomeClass
6666

6767
public function getNodeTypes(): array
6868
{
69-
return [Property::class];
69+
return [Class_::class];
7070
}
7171

7272
/**
73-
* @param Property $node
73+
* @param Class_ $node
7474
*/
75-
public function refactor(Node $node): ?Property
75+
public function refactor(Node $node): ?Class_
7676
{
77-
if ($node->isAbstract()) {
78-
return null;
77+
$hasChanged = false;
78+
foreach ($node->getProperties() as $property) {
79+
if ($property->isAbstract()) {
80+
continue;
81+
}
82+
83+
$propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
84+
$varTagValueNode = $propertyPhpDocInfo->getVarTagValueNode();
85+
86+
// 1. handle docblock
87+
if ($varTagValueNode instanceof VarTagValueNode) {
88+
$hasNativeCollectionType = $this->hasNativeTypeCollection($property);
89+
90+
if ($this->unionCollectionTagValueNodeNarrower->narrow($varTagValueNode, $hasNativeCollectionType)) {
91+
$this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($property);
92+
$hasChanged = true;
93+
}
94+
}
95+
96+
// 2. handle native type
97+
if ($property->type instanceof Node\UnionType) {
98+
foreach ($property->type->types as $uniontedType) {
99+
if ($this->isCollectionName($uniontedType)) {
100+
// narrow to pure collection
101+
$property->type = new Name\FullyQualified(DoctrineClass::COLLECTION);
102+
$hasChanged = true;
103+
104+
// remove default, as will be defined in constructor by another rule
105+
if ($property->props[0]->default instanceof Node\Expr) {
106+
$property->props[0]->default = null;
107+
}
108+
109+
break;
110+
}
111+
}
112+
}
79113
}
80114

81-
$scope = ScopeFetcher::fetch($node);
82-
$classReflection = $scope->getClassReflection();
83-
if (! $classReflection instanceof ClassReflection) {
84-
return null;
115+
if ($hasChanged) {
116+
return $node;
85117
}
86118

87-
if ($classReflection->isInterface()) {
88-
return null;
89-
}
90-
91-
$propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
92-
93-
$varTagValueNode = $propertyPhpDocInfo->getVarTagValueNode();
94-
if (! $varTagValueNode instanceof VarTagValueNode) {
95-
return null;
96-
}
119+
return null;
120+
}
97121

98-
$hasNativeCollectionType = false;
99-
if ($node->type instanceof Name && $this->isName($node->type, Collection::class)) {
100-
$hasNativeCollectionType = true;
122+
private function hasNativeTypeCollection(Property $property): bool
123+
{
124+
if (! $property->type instanceof Name) {
125+
return false;
101126
}
102127

103-
$hasChanged = $this->unionCollectionTagValueNodeNarrower->narrow($varTagValueNode, $hasNativeCollectionType);
128+
return $this->isName($property->type, Collection::class);
129+
}
104130

105-
if ($hasChanged === false) {
106-
return null;
131+
private function isCollectionName(Node $node): bool
132+
{
133+
if (! $node instanceof Name) {
134+
return false;
107135
}
108136

109-
$this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node);
110-
111-
return $node;
137+
return $this->isName($node, DoctrineClass::COLLECTION);
112138
}
113139
}

0 commit comments

Comments
 (0)