Skip to content

Commit 4b949f8

Browse files
committed
add fixture and test
1 parent f882275 commit 4b949f8

7 files changed

Lines changed: 159 additions & 67 deletions

File tree

config/set/type-declaration-docblocks.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Rector\TypeDeclaration\Rector\ClassMethod\AddReturnArrayDocblockBasedOnArrayMapRector;
77
use Rector\TypeDeclaration\Rector\ClassMethod\AddReturnDocblockForScalarArrayFromAssignsRector;
88
use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarFromParamDocblockInConstructorRector;
9+
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector;
910
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockGetterReturnArrayFromPropertyDocblockVarRector;
1011

1112
/**
@@ -18,5 +19,6 @@
1819
DocblockVarFromParamDocblockInConstructorRector::class,
1920
DocblockVarFromParamDocblockInConstructorRector::class,
2021
DocblockGetterReturnArrayFromPropertyDocblockVarRector::class,
22+
AddReturnDocblockForCommonObjectDenominatorRector::class,
2123
]);
2224
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector\Fixture;
4+
5+
use Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector\Source\FirstExtension;
6+
use Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector\Source\SecondExtension;
7+
8+
final class ReturnOfObjects
9+
{
10+
public function getExtensions(): array
11+
{
12+
return [
13+
new FirstExtension(),
14+
new SecondExtension()
15+
];
16+
}
17+
}
18+
19+
?>
20+
-----
21+
<?php
22+
23+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector\Fixture;
24+
25+
use Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector\Source\FirstExtension;
26+
use Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector\Source\SecondExtension;
27+
28+
final class ReturnOfObjects
29+
{
30+
/**
31+
* @return \Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector\Source\ExtensionInterface[]
32+
*/
33+
public function getExtensions(): array
34+
{
35+
return [
36+
new FirstExtension(),
37+
new SecondExtension()
38+
];
39+
}
40+
}
41+
42+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockGetterReturnArrayFromPropertyDocblockVarRector\Fixture;
4+
5+
final class SomePropertyWithArrayDocblock
6+
{
7+
/**
8+
* @var string[]
9+
*/
10+
private array $names = [];
11+
12+
public function getNames(): array
13+
{
14+
return $this->names;
15+
}
16+
}
17+
18+
?>

rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddReturnDocblockForCommonObjectDenominatorRector/Fixture/some_property_with_array_docblock.php.inc

Lines changed: 0 additions & 40 deletions
This file was deleted.

rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddReturnDocblockForCommonObjectDenominatorRector/config/configured_rule.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
declare(strict_types=1);
44

55
use Rector\Config\RectorConfig;
6+
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector;
67

78
return RectorConfig::configure()
8-
->withRules(
9-
[\Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector::class]
10-
);
9+
->withRules([AddReturnDocblockForCommonObjectDenominatorRector::class]);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\TypeDeclarationDocblocks\NodeFinder;
6+
7+
use PhpParser\Node\Stmt\ClassMethod;
8+
use PhpParser\Node\Stmt\Function_;
9+
use PhpParser\Node\Stmt\Return_;
10+
use Rector\PhpParser\Node\BetterNodeFinder;
11+
use Rector\TypeDeclaration\NodeAnalyzer\ReturnAnalyzer;
12+
13+
final readonly class ReturnNodeFinder
14+
{
15+
public function __construct(
16+
private BetterNodeFinder $betterNodeFinder,
17+
private ReturnAnalyzer $returnAnalyzer,
18+
) {
19+
}
20+
21+
public function findOnlyReturnWithExpr(ClassMethod|Function_ $functionLike): ?Return_
22+
{
23+
$returnsScoped = $this->betterNodeFinder->findReturnsScoped($functionLike);
24+
if (! $this->returnAnalyzer->hasOnlyReturnWithExpr($functionLike, $returnsScoped)) {
25+
return null;
26+
}
27+
28+
return $returnsScoped[0];
29+
}
30+
}

rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddReturnDocblockForCommonObjectDenominatorRector.php

Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@
55
namespace Rector\TypeDeclarationDocblocks\Rector\ClassMethod;
66

77
use PhpParser\Node;
8+
use PhpParser\Node\Expr;
89
use PhpParser\Node\Stmt\ClassMethod;
910
use PhpParser\Node\Stmt\Function_;
11+
use PhpParser\Node\Stmt\Return_;
12+
use PHPStan\Reflection\ReflectionProvider;
1013
use PHPStan\Type\ArrayType;
14+
use PHPStan\Type\Constant\ConstantArrayType;
1115
use PHPStan\Type\MixedType;
1216
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
1317
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
14-
use Rector\PhpParser\Node\BetterNodeFinder;
1518
use Rector\Rector\AbstractRector;
16-
use Rector\TypeDeclaration\NodeAnalyzer\ReturnAnalyzer;
19+
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
20+
use Rector\TypeDeclarationDocblocks\NodeFinder\ReturnNodeFinder;
1721
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
1822
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
1923

@@ -23,10 +27,10 @@
2327
final class AddReturnDocblockForCommonObjectDenominatorRector extends AbstractRector
2428
{
2529
public function __construct(
26-
private readonly BetterNodeFinder $betterNodeFinder,
27-
private readonly ReturnAnalyzer $returnAnalyzer,
28-
private readonly PhpDocTypeChanger $phpDocTypeChanger,
2930
private readonly PhpDocInfoFactory $phpDocInfoFactory,
31+
private readonly ReturnNodeFinder $returnNodeFinder,
32+
private readonly ReflectionProvider $reflectionProvider,
33+
private readonly PhpDocTypeChanger $phpDocTypeChanger,
3034
) {
3135
}
3236

@@ -35,8 +39,8 @@ public function getRuleDefinition(): RuleDefinition
3539
return new RuleDefinition(
3640
'Add @return docblock array of objects, that have common denominator interface/parent class',
3741
[
38-
new CodeSample(
39-
<<<'CODE_SAMPLE'
42+
new CodeSample(
43+
<<<'CODE_SAMPLE'
4044
final class ExtensionProvider
4145
{
4246
public function getExtensions(): array
@@ -56,8 +60,8 @@ class SecondExtension implements ExtensionInterface
5660
{
5761
}
5862
CODE_SAMPLE
59-
,
60-
<<<'CODE_SAMPLE'
63+
,
64+
<<<'CODE_SAMPLE'
6165
final class ExtensionProvider
6266
{
6367
/**
@@ -80,9 +84,10 @@ class SecondExtension implements ExtensionInterface
8084
{
8185
}
8286
CODE_SAMPLE
83-
),
84-
85-
]);
87+
),
88+
89+
]
90+
);
8691
}
8792

8893
/**
@@ -105,26 +110,62 @@ public function refactor(Node $node): ?Node
105110
return null;
106111
}
107112

108-
dump(123);
109-
die;
110-
113+
// definitely not an array return
111114
if ($node->returnType instanceof Node && ! $this->isName($node->returnType, 'array')) {
112115
return null;
113116
}
114117

115-
$returnsScoped = $this->betterNodeFinder->findReturnsScoped($node);
118+
$onlyReturnWithExpr = $this->returnNodeFinder->findOnlyReturnWithExpr($node);
119+
if (! $onlyReturnWithExpr instanceof Return_ || ! $onlyReturnWithExpr->expr instanceof Expr) {
120+
return null;
121+
}
122+
123+
$returnedType = $this->getType($onlyReturnWithExpr->expr);
124+
if (! $returnedType instanceof ArrayType && ! $returnedType instanceof ConstantArrayType) {
125+
return null;
126+
}
116127

117-
if (! $this->returnAnalyzer->hasOnlyReturnWithExpr($node, $returnsScoped)) {
128+
$referencedClasses = $returnedType->getReferencedClasses();
129+
// nothing to find here
130+
if ($referencedClasses === []) {
118131
return null;
119132
}
120133

121-
// $arrayType = new ArrayType(new MixedType(), $firstScalarType);
122-
//
123-
// $hasChanged = $this->phpDocTypeChanger->changeReturnType($node, $phpDocInfo, $arrayType);
124-
// if ($hasChanged) {
125-
// return $node;
126-
// }
134+
$parentClassesAndInterfaces = [];
135+
136+
foreach ($referencedClasses as $referencedClass) {
137+
$parentClassesAndInterfaces[] = $this->resolveParentClassesAndInterfaces($referencedClass);
138+
}
139+
140+
$firstSharedTypes = array_intersect(...$parentClassesAndInterfaces);
141+
$firstSharedType = $firstSharedTypes[0] ?? null;
142+
143+
if ($firstSharedType === null) {
144+
return null;
145+
}
146+
147+
$objectTypeArrayType = new ArrayType(new MixedType(), new FullyQualifiedObjectType($firstSharedType));
148+
$hasChanged = $this->phpDocTypeChanger->changeReturnType($node, $phpDocInfo, $objectTypeArrayType);
149+
if (! $hasChanged) {
150+
return null;
151+
}
152+
153+
return $node;
154+
}
155+
156+
/**
157+
* @return string[]
158+
*/
159+
private function resolveParentClassesAndInterfaces(string $className): array
160+
{
161+
$referenceClassReflection = $this->reflectionProvider->getClass($className);
162+
163+
$currentParentClassesAndInterfaces = $referenceClassReflection->getParentClassesNames();
164+
165+
foreach ($referenceClassReflection->getInterfaces() as $classReflection) {
166+
$currentParentClassesAndInterfaces[] = $classReflection->getName();
167+
}
127168

128-
return null;
169+
return $currentParentClassesAndInterfaces;
129170
}
130171
}

0 commit comments

Comments
 (0)