Skip to content

Commit 501dd3b

Browse files
committed
[type-declaration-docblocks] Add AddReturnDocblockDataProviderRector
1 parent 69764a7 commit 501dd3b

9 files changed

Lines changed: 388 additions & 20 deletions

File tree

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\Class_\AddReturnDocblockDataProviderRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class AddReturnDocblockDataProviderRectorTest 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,52 @@
1+
<?php
2+
3+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\AddReturnDocblockDataProviderRector\Fixture;
4+
5+
use PHPUnit\Framework\Attributes\DataProvider;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class DataProviderMethod extends TestCase
9+
{
10+
#[DataProvider('provideData')]
11+
public function testSomething()
12+
{
13+
}
14+
15+
public static function provideData()
16+
{
17+
return [
18+
['data1'],
19+
['data2'],
20+
];
21+
}
22+
}
23+
24+
?>
25+
-----
26+
<?php
27+
28+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\AddReturnDocblockDataProviderRector\Fixture;
29+
30+
use PHPUnit\Framework\Attributes\DataProvider;
31+
use PHPUnit\Framework\TestCase;
32+
33+
final class DataProviderMethod extends TestCase
34+
{
35+
#[DataProvider('provideData')]
36+
public function testSomething()
37+
{
38+
}
39+
40+
/**
41+
* @return string[][]
42+
*/
43+
public static function provideData()
44+
{
45+
return [
46+
['data1'],
47+
['data2'],
48+
];
49+
}
50+
}
51+
52+
?>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\AddReturnDocblockDataProviderRector\Fixture;
4+
5+
use PHPUnit\Framework\Attributes\DataProvider;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class WithIntegers extends TestCase
9+
{
10+
#[DataProvider('provideData')]
11+
public function testSomething()
12+
{
13+
}
14+
15+
public static function provideData()
16+
{
17+
return [
18+
[125, 35],
19+
[1252]
20+
];
21+
}
22+
}
23+
24+
?>
25+
-----
26+
<?php
27+
28+
namespace Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\AddReturnDocblockDataProviderRector\Fixture;
29+
30+
use PHPUnit\Framework\Attributes\DataProvider;
31+
use PHPUnit\Framework\TestCase;
32+
33+
final class WithIntegers extends TestCase
34+
{
35+
#[DataProvider('provideData')]
36+
public function testSomething()
37+
{
38+
}
39+
40+
/**
41+
* @return int[][]
42+
*/
43+
public static function provideData()
44+
{
45+
return [
46+
[125, 35],
47+
[1252]
48+
];
49+
}
50+
}
51+
52+
?>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\TypeDeclarationDocblocks\Rector\Class_\AddReturnDocblockDataProviderRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(AddReturnDocblockDataProviderRector::class);
10+
};

rules/CodingStyle/Rector/Enum_/EnumCaseToPascalCaseRector.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,9 @@ private function convertToPascalCase(string $name): string
194194
fn ($part): string =>
195195
// If part is all uppercase, convert to ucfirst(strtolower())
196196
// If part is already mixed or PascalCase, keep as is except ucfirst
197-
ctype_upper((string) $part)
198-
? ucfirst(strtolower((string) $part))
199-
: ucfirst((string) $part),
197+
ctype_upper($part)
198+
? ucfirst(strtolower($part))
199+
: ucfirst($part),
200200
$parts
201201
)
202202
);

rules/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector.php

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,31 @@ private function shouldSkip(
7777
): bool {
7878
$params = $node->getParams();
7979
$args = $callLike->getArgs();
80+
if ($callLike->isFirstClassCallable()) {
81+
return true;
82+
}
8083

81-
if (
82-
$callLike->isFirstClassCallable()
83-
|| $this->isChainedCall($callLike)
84-
|| $this->isUsingNamedArgs($args)
85-
|| $this->isUsingByRef($params)
86-
|| $this->isNotUsingSameParamsForArgs($params, $args)
87-
|| $this->isDependantMethod($callLike, $params)
88-
|| $this->isUsingThisInNonObjectContext($callLike, $scope)
89-
) {
84+
if ($this->isChainedCall($callLike)) {
9085
return true;
9186
}
9287

93-
return false;
88+
if ($this->isUsingNamedArgs($args)) {
89+
return true;
90+
}
91+
92+
if ($this->isUsingByRef($params)) {
93+
return true;
94+
}
95+
96+
if ($this->isNotUsingSameParamsForArgs($params, $args)) {
97+
return true;
98+
}
99+
100+
if ($this->isDependantMethod($callLike, $params)) {
101+
return true;
102+
}
103+
104+
return $this->isUsingThisInNonObjectContext($callLike, $scope);
94105
}
95106

96107
private function extractCallLike(Closure|ArrowFunction $node): FuncCall|MethodCall|StaticCall|null
@@ -99,6 +110,7 @@ private function extractCallLike(Closure|ArrowFunction $node): FuncCall|MethodCa
99110
if (count($node->stmts) !== 1 || ! $node->stmts[0] instanceof Return_) {
100111
return null;
101112
}
113+
102114
$callLike = $node->stmts[0]->expr;
103115
} else {
104116
$callLike = $node->expr;
@@ -198,6 +210,7 @@ private function isUsingByRef(array $params): bool
198210
return true;
199211
}
200212
}
213+
201214
return false;
202215
}
203216

@@ -211,6 +224,7 @@ private function isUsingNamedArgs(array $args): bool
211224
return true;
212225
}
213226
}
227+
214228
return false;
215229
}
216230

@@ -220,10 +234,6 @@ private function isChainedCall(FuncCall|MethodCall|StaticCall $callLike): bool
220234
return false;
221235
}
222236

223-
if (! $callLike->var instanceof CallLike) {
224-
return false;
225-
}
226-
227-
return true;
237+
return $callLike->var instanceof CallLike;
228238
}
229239
}

rules/Privatization/TypeManipulator/TypeNormalizer.php

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,30 @@
44

55
namespace Rector\Privatization\TypeManipulator;
66

7+
use PHPStan\Type\ArrayType;
78
use PHPStan\Type\BooleanType;
9+
use PHPStan\Type\Constant\ConstantArrayType;
810
use PHPStan\Type\Constant\ConstantBooleanType;
911
use PHPStan\Type\Constant\ConstantFloatType;
1012
use PHPStan\Type\Constant\ConstantIntegerType;
1113
use PHPStan\Type\Constant\ConstantStringType;
1214
use PHPStan\Type\FloatType;
1315
use PHPStan\Type\IntegerType;
16+
use PHPStan\Type\MixedType;
1417
use PHPStan\Type\StringType;
1518
use PHPStan\Type\Type;
1619
use PHPStan\Type\TypeTraverser;
20+
use PHPStan\Type\UnionType;
1721

1822
final class TypeNormalizer
1923
{
2024
/**
21-
* Generalize false/true type to bool,
25+
* Generalize false/true constantArrayType to bool,
2226
* as mostly default value but accepts both
2327
*/
2428
public function generalizeConstantBoolTypes(Type $type): Type
2529
{
26-
return TypeTraverser::map($type, static function (Type $type, callable $traverseCallback): BooleanType|Type {
30+
return TypeTraverser::map($type, function (Type $type, callable $traverseCallback): BooleanType|Type {
2731
if ($type instanceof ConstantBooleanType) {
2832
return new BooleanType();
2933
}
@@ -40,7 +44,45 @@ public function generalizeConstantBoolTypes(Type $type): Type
4044
return new IntegerType();
4145
}
4246

47+
if ($type instanceof ConstantArrayType) {
48+
// is relevant int constantArrayType?
49+
if ($this->isImplicitNumberedListKeyType($type)) {
50+
$keyType = new MixedType();
51+
} else {
52+
$keyType = $traverseCallback($type->getKeyType(), $traverseCallback);
53+
}
54+
55+
// should be string[]
56+
$itemType = $traverseCallback($type->getItemType(), $traverseCallback);
57+
if ($itemType instanceof ConstantStringType) {
58+
$itemType = new StringType();
59+
}
60+
61+
return new ArrayType($keyType, $itemType);
62+
}
63+
4364
return $traverseCallback($type, $traverseCallback);
4465
});
4566
}
67+
68+
private function isImplicitNumberedListKeyType(ConstantArrayType $constantArrayType): bool
69+
{
70+
if (! $constantArrayType->getKeyType() instanceof UnionType) {
71+
return false;
72+
}
73+
74+
foreach ($constantArrayType->getKeyType()->getTypes() as $key => $keyType) {
75+
if ($keyType instanceof ConstantIntegerType) {
76+
if ($keyType->getValue() === $key) {
77+
continue;
78+
}
79+
80+
return false;
81+
}
82+
83+
return false;
84+
}
85+
86+
return true;
87+
}
4688
}

rules/TypeDeclarationDocblocks/NodeFinder/DataProviderMethodsFinder.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ public function __construct(
2121
) {
2222
}
2323

24+
/**
25+
* @return ClassMethod[]
26+
*/
27+
public function findDataProviderNodesInClass(Class_ $class): array
28+
{
29+
$dataProviderClassMethods = [];
30+
31+
foreach ($class->getMethods() as $classMethod) {
32+
$currentDataProviderNodes = $this->findDataProviderNodes($class, $classMethod);
33+
$dataProviderClassMethods = array_merge(
34+
$dataProviderClassMethods,
35+
$currentDataProviderNodes->getClassMethods()
36+
);
37+
}
38+
39+
return $dataProviderClassMethods;
40+
}
41+
2442
public function findDataProviderNodes(Class_ $class, ClassMethod $classMethod): DataProviderNodes
2543
{
2644
$phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod);

0 commit comments

Comments
 (0)