Skip to content

Commit dee6271

Browse files
committed
[tdd] Add AddReturnDocblockFromMethodCallDocblockRector
1 parent 8bd31f0 commit dee6271

File tree

9 files changed

+315
-0
lines changed

9 files changed

+315
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class AddReturnDocblockFromMethodCallDocblockRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Fixture;
6+
7+
use Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Source\SomeRepository;
8+
9+
final class SkipMissingArrayDeclaration
10+
{
11+
private SomeRepository $someRepository;
12+
13+
public function __construct(SomeRepository $someRepository)
14+
{
15+
$this->someRepository = $someRepository;
16+
}
17+
18+
public function getAll()
19+
{
20+
return $this->someRepository->findAll();
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Fixture;
6+
7+
use Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Source\SomeRepository;
8+
9+
final class SkipMissingArrayOnCall
10+
{
11+
private SomeRepository $someRepository;
12+
13+
public function __construct(SomeRepository $someRepository)
14+
{
15+
$this->someRepository = $someRepository;
16+
}
17+
18+
public function getAll(): array
19+
{
20+
return $this->someRepository->findAllWithoutArray();
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Fixture;
6+
7+
use Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Source\SomeRepository;
8+
9+
final class SomeClass
10+
{
11+
private SomeRepository $someRepository;
12+
13+
public function __construct(SomeRepository $someRepository)
14+
{
15+
$this->someRepository = $someRepository;
16+
}
17+
18+
public function getAll(): array
19+
{
20+
return $this->someRepository->findAll();
21+
}
22+
}
23+
24+
?>
25+
-----
26+
<?php
27+
28+
declare(strict_types=1);
29+
30+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Fixture;
31+
32+
use Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Source\SomeRepository;
33+
34+
final class SomeClass
35+
{
36+
private SomeRepository $someRepository;
37+
38+
public function __construct(SomeRepository $someRepository)
39+
{
40+
$this->someRepository = $someRepository;
41+
}
42+
43+
/**
44+
* @return SomeEntity[]
45+
*/
46+
public function getAll(): array
47+
{
48+
return $this->someRepository->findAll();
49+
}
50+
}
51+
52+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Source;
4+
5+
final class SomeEntity
6+
{
7+
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\Source;
6+
7+
final class SomeRepository
8+
{
9+
/**
10+
* @return SomeEntity[]
11+
*/
12+
public function findAll(): array
13+
{
14+
return [];
15+
}
16+
17+
/**
18+
* @return SomeEntity[]
19+
*/
20+
public function findAllWithoutArray()
21+
{
22+
return [];
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector;
7+
8+
return RectorConfig::configure()
9+
->withRules([AddReturnDocblockFromMethodCallDocblockRector::class]);
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\TypeDeclarationDocblocks\Rector\ClassMethod;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\MethodCall;
9+
use PhpParser\Node\Identifier;
10+
use PhpParser\Node\Stmt\ClassMethod;
11+
use PhpParser\Node\Stmt\Return_;
12+
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
13+
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
14+
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
15+
use Rector\PhpParser\AstResolver;
16+
use Rector\Rector\AbstractRector;
17+
use Rector\TypeDeclarationDocblocks\NodeFinder\ReturnNodeFinder;
18+
use Rector\TypeDeclarationDocblocks\TagNodeAnalyzer\UsefulArrayTagNodeAnalyzer;
19+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
20+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
21+
22+
/**
23+
* @see \Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector\AddReturnDocblockFromMethodCallDocblockRectorTest
24+
*/
25+
final class AddReturnDocblockFromMethodCallDocblockRector extends AbstractRector
26+
{
27+
public function __construct(
28+
private readonly PhpDocInfoFactory $phpDocInfoFactory,
29+
private readonly ReturnNodeFinder $returnNodeFinder,
30+
private readonly UsefulArrayTagNodeAnalyzer $usefulArrayTagNodeAnalyzer,
31+
private readonly AstResolver $astResolver,
32+
private readonly PhpDocTypeChanger $phpDocTypeChanger,
33+
) {
34+
}
35+
36+
public function getRuleDefinition(): RuleDefinition
37+
{
38+
return new RuleDefinition(
39+
'Add @return docblock based on detailed type of method call docblock',
40+
[
41+
new CodeSample(
42+
<<<'CODE_SAMPLE'
43+
final class SomeController
44+
{
45+
public function getAll(): array
46+
{
47+
return $this->repository->findAll();
48+
}
49+
}
50+
51+
final class Repository
52+
{
53+
/**
54+
* @return SomeEntity[]
55+
*/
56+
public function findAll(): array
57+
{
58+
// ...
59+
}
60+
}
61+
}
62+
CODE_SAMPLE
63+
,
64+
<<<'CODE_SAMPLE'
65+
final class SomeController
66+
{
67+
/**
68+
* @return SomeEntity[]
69+
*/
70+
public function getAll(): array
71+
{
72+
return $this->repository->findAll();
73+
}
74+
}
75+
76+
final class Repository
77+
{
78+
/**
79+
* @return SomeEntity[]
80+
*/
81+
public function findAll(): array
82+
{
83+
// ...
84+
}
85+
}
86+
CODE_SAMPLE
87+
),
88+
89+
]
90+
);
91+
}
92+
93+
/**
94+
* @return array<class-string<Node>>
95+
*/
96+
public function getNodeTypes(): array
97+
{
98+
return [ClassMethod::class];
99+
}
100+
101+
/**
102+
* @param ClassMethod $node
103+
*/
104+
public function refactor(Node $node): ?Node
105+
{
106+
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
107+
if ($this->usefulArrayTagNodeAnalyzer->isUsefulArrayTag($phpDocInfo->getReturnTagValue())) {
108+
return null;
109+
}
110+
111+
// definitely not an array return
112+
if (! $node->returnType instanceof Node || ! $this->isName($node->returnType, 'array')) {
113+
return null;
114+
}
115+
116+
$onlyReturnWithExpr = $this->returnNodeFinder->findOnlyReturnWithExpr($node);
117+
if (! $onlyReturnWithExpr instanceof Return_ || ! $onlyReturnWithExpr->expr instanceof MethodCall) {
118+
return null;
119+
}
120+
121+
$returnedMethodCall = $onlyReturnWithExpr->expr;
122+
123+
$calledClassMethod = $this->astResolver->resolveClassMethodFromCall($returnedMethodCall);
124+
if (! $calledClassMethod instanceof ClassMethod) {
125+
return null;
126+
}
127+
128+
if (! $calledClassMethod->returnType instanceof Identifier) {
129+
return null;
130+
}
131+
132+
if (! $this->isName($calledClassMethod->returnType, 'array')) {
133+
return null;
134+
}
135+
136+
$calledClassMethodPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($calledClassMethod);
137+
138+
$calledReturnTagValue = $calledClassMethodPhpDocInfo->getReturnTagValue();
139+
if (! $calledReturnTagValue instanceof ReturnTagValueNode) {
140+
return null;
141+
}
142+
143+
$this->phpDocTypeChanger->changeReturnTypeNode($node, $phpDocInfo, $calledReturnTagValue->type);
144+
145+
return $node;
146+
}
147+
}

src/Config/Level/TypeDeclarationDocblocksLevel.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector;
2222
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForDimFetchArrayFromAssignsRector;
2323
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForJsonArrayRector;
24+
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockFromMethodCallDocblockRector;
2425
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockGetterReturnArrayFromPropertyDocblockVarRector;
2526
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockReturnArrayFromDirectArrayInstanceRector;
2627

@@ -63,5 +64,7 @@ final class TypeDeclarationDocblocksLevel
6364

6465
// run latter after other rules, as more generic
6566
AddReturnDocblockForDimFetchArrayFromAssignsRector::class,
67+
68+
AddReturnDocblockFromMethodCallDocblockRector::class,
6669
];
6770
}

0 commit comments

Comments
 (0)