Skip to content

Commit 6defa40

Browse files
committed
[code-quality] Add ParamTypeFromDependsRector
1 parent 8bfa606 commit 6defa40

File tree

6 files changed

+231
-0
lines changed

6 files changed

+231
-0
lines changed

config/sets/phpunit-code-quality.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Rector\Config\RectorConfig;
66
use Rector\PHPUnit\CodeQuality\Rector\Class_\ConstructClassMethodToSetUpTestCaseRector;
77
use Rector\PHPUnit\CodeQuality\Rector\Class_\NarrowUnusedSetUpDefinedPropertyRector;
8+
use Rector\PHPUnit\CodeQuality\Rector\Class_\ParamTypeFromDependsRector;
89
use Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector;
910
use Rector\PHPUnit\CodeQuality\Rector\Class_\RemoveDataProviderParamKeysRector;
1011
use Rector\PHPUnit\CodeQuality\Rector\Class_\SingleMockPropertyTypeRector;
@@ -70,6 +71,7 @@
7071
// type declarations
7172
TypeWillReturnCallableArrowFunctionRector::class,
7273
StringCastAssertStringContainsStringRector::class,
74+
ParamTypeFromDependsRector::class,
7375

7476
NarrowUnusedSetUpDefinedPropertyRector::class,
7577

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace CodeQuality\Rector\Class_\ParamTypeFromDependsRector\Fixture;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
final class SomeFileTest extends TestCase
8+
{
9+
public function test()
10+
{
11+
return new \stdClass();
12+
}
13+
14+
/**
15+
* @depends test
16+
*/
17+
public function testWithDepends($value)
18+
{
19+
}
20+
}
21+
22+
?>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace CodeQuality\Rector\Class_\ParamTypeFromDependsRector\Fixture;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
final class SomeFileTest extends TestCase
8+
{
9+
public function test()
10+
{
11+
return new \stdClass();
12+
}
13+
14+
/**
15+
* @depends test
16+
*/
17+
public function testWithDepends($value)
18+
{
19+
}
20+
}
21+
22+
?>
23+
-----
24+
<?php
25+
26+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\ClassMethod\ParamTypeFromDependsRector\Fixture;
27+
28+
use PHPUnit\Framework\TestCase;
29+
30+
final class SomeFileTest extends TestCase
31+
{
32+
public function test()
33+
{
34+
return new \stdClass();
35+
}
36+
37+
/**
38+
* @depends test
39+
*/
40+
public function testWithDepends(\stdClass $value)
41+
{
42+
}
43+
}
44+
45+
?>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\ParamTypeFromDependsRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class ParamTypeFromDependsRectorTest 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+
}
Lines changed: 9 additions & 0 deletions
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\PHPUnit\CodeQuality\Rector\Class_\ParamTypeFromDependsRector;
7+
8+
return RectorConfig::configure()
9+
->withRules([ParamTypeFromDependsRector::class]);
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\PHPUnit\CodeQuality\Rector\Class_;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Stmt\Class_;
9+
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
10+
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
11+
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
12+
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
13+
use Rector\Rector\AbstractRector;
14+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
15+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
16+
17+
/**
18+
* @see \Rector\PHPUnit\Tests\CodeQuality\Rector\Class_\ParamTypeFromDependsRector\ParamTypeFromDependsRectorTest
19+
*/
20+
final class ParamTypeFromDependsRector extends AbstractRector
21+
{
22+
public function __construct(
23+
private readonly TestsNodeAnalyzer $testsNodeAnalyzer,
24+
private readonly PhpDocInfoFactory $phpDocInfoFactory,
25+
) {
26+
}
27+
28+
public function getRuleDefinition(): RuleDefinition
29+
{
30+
return new RuleDefinition(
31+
'Add param type declaration based on @depends test method return type',
32+
[
33+
new CodeSample(
34+
<<<'CODE_SAMPLE'
35+
use PHPUnit\Framework\TestCase;
36+
37+
final class SomeTest extends TestCase
38+
{
39+
public function test()
40+
{
41+
return new \stdClass();
42+
}
43+
44+
/**
45+
* @depends test
46+
*/
47+
public function testAnother($someObject)
48+
{
49+
}
50+
}
51+
CODE_SAMPLE
52+
53+
,
54+
<<<'CODE_SAMPLE'
55+
use PHPUnit\Framework\TestCase;
56+
57+
final class SomeTest extends TestCase
58+
{
59+
public function test()
60+
{
61+
return new \stdClass();
62+
}
63+
64+
/**
65+
* @depends test
66+
*/
67+
public function testAnother(\stdClass $someObject)
68+
{
69+
}
70+
}
71+
CODE_SAMPLE
72+
),
73+
]
74+
);
75+
}
76+
77+
/**
78+
* @return array<class-string<Node>>
79+
*/
80+
public function getNodeTypes(): array
81+
{
82+
return [Class_::class];
83+
}
84+
85+
/**
86+
* @param Class_ $node
87+
*/
88+
public function refactor(Node $node): ?Node
89+
{
90+
if (! $this->testsNodeAnalyzer->isInTestClass($node)) {
91+
return null;
92+
}
93+
94+
foreach ($node->getMethods() as $classMethod) {
95+
if (! $classMethod->isPublic()) {
96+
continue;
97+
}
98+
99+
if ($classMethod->params === []) {
100+
continue;
101+
}
102+
103+
$phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod);
104+
if (! $phpDocInfo instanceof PhpDocInfo) {
105+
continue;
106+
}
107+
108+
$dependsTagValueNode = $phpDocInfo->getByName('depends');
109+
if (! $dependsTagValueNode instanceof PhpDocTagNode) {
110+
continue;
111+
}
112+
113+
$dependsMethodName = (string) $dependsTagValueNode->value;
114+
115+
$dependsClassMethod = $node->getMethod($dependsMethodName);
116+
117+
// resolve return type here
118+
dump($dependsClassMethod);
119+
}
120+
121+
die;
122+
123+
return $node;
124+
}
125+
}

0 commit comments

Comments
 (0)