Skip to content

Commit 32fc26e

Browse files
authored
[rector] add NoIntegerRefactorReturnRule (#248)
1 parent b98bb10 commit 32fc26e

File tree

7 files changed

+159
-0
lines changed

7 files changed

+159
-0
lines changed

config/rector-rules.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ rules:
77
- Symplify\PHPStanRules\Rules\Rector\NoPropertyNodeAssignRule
88
- Symplify\PHPStanRules\Rules\Rector\PreferDirectIsNameRule
99
- Symplify\PHPStanRules\Rules\Rector\NoOnlyNullReturnInRefactorRule
10+
- Symplify\PHPStanRules\Rules\Rector\NoIntegerRefactorReturnRule
1011

1112
services:
1213
# $node->getAttribute($1) => Type|null by $1

src/Enum/RuleIdentifier/RectorRuleIdentifier.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ final class RectorRuleIdentifier
1919
public const PREFER_DIRECT_IS_NAME = 'rector.preferDirectIsName';
2020

2121
public const NO_ONLY_NULL_RETURN_IN_REFACTOR = 'rector.noOnlyNullReturnInRefactor';
22+
23+
public const NO_INTEGER_REFACTOR_RETURN = 'rector.noIntegerRefactorReturn';
2224
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symplify\PHPStanRules\Rules\Rector;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Identifier;
9+
use PhpParser\Node\Stmt\ClassMethod;
10+
use PhpParser\Node\UnionType;
11+
use PHPStan\Analyser\Scope;
12+
use PHPStan\Rules\Rule;
13+
use PHPStan\Rules\RuleErrorBuilder;
14+
use Symplify\PHPStanRules\Enum\RuleIdentifier\RectorRuleIdentifier;
15+
16+
/**
17+
* @see \Symplify\PHPStanRules\Tests\Rules\Rector\NoIntegerRefactorReturnRule\NoIntegerRefactorReturnRuleTest
18+
*
19+
* @implements Rule<ClassMethod>
20+
*/
21+
final class NoIntegerRefactorReturnRule implements Rule
22+
{
23+
/**
24+
* @var string
25+
*/
26+
public const ERROR_MESSAGE = 'Instead of using int in refactor(), make use of attributes and return always node or a null. Using traverser enums might lead to unexpected results';
27+
28+
public function getNodeType(): string
29+
{
30+
return ClassMethod::class;
31+
}
32+
33+
/**
34+
* @param ClassMethod $node
35+
*/
36+
public function processNode(Node $node, Scope $scope): array
37+
{
38+
if (! $node->isPublic()) {
39+
return [];
40+
}
41+
42+
if ($node->name->toString() !== 'refactor') {
43+
return [];
44+
}
45+
46+
if (! $node->returnType instanceof UnionType) {
47+
return [];
48+
}
49+
50+
foreach ($node->returnType->types as $type) {
51+
if (! $type instanceof Identifier) {
52+
continue;
53+
}
54+
55+
if ($type->name === 'int') {
56+
$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
57+
->identifier(RectorRuleIdentifier::NO_INTEGER_REFACTOR_RETURN)
58+
->build();
59+
60+
return [$ruleError];
61+
}
62+
}
63+
64+
return [];
65+
}
66+
}
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 Symplify\PHPStanRules\Tests\Rules\Rector\NoIntegerRefactorReturnRule\Fixture;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Stmt\Class_;
9+
use PhpParser\Node\Stmt\Interface_;
10+
use PhpParser\NodeVisitor;
11+
use Rector\Rector\AbstractRector;
12+
13+
final class SimpleReturnInt extends AbstractRector
14+
{
15+
public function getNodeTypes(): array
16+
{
17+
return [Class_::class, Interface_::class];
18+
}
19+
20+
public function refactor(Node $node): \PhpParser\Node|int
21+
{
22+
if ($node instanceof Class_) {
23+
return $node;
24+
}
25+
26+
return NodeVisitor::DONT_TRAVERSE_CHILDREN;
27+
}
28+
}
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 Symplify\PHPStanRules\Tests\Rules\Rector\NoIntegerRefactorReturnRule\Fixture;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Stmt\Class_;
9+
use PhpParser\Node\Stmt\Interface_;
10+
use PhpParser\NodeVisitor;
11+
use Rector\Rector\AbstractRector;
12+
13+
final class SkipBareNodeReturn extends AbstractRector
14+
{
15+
public function getNodeTypes(): array
16+
{
17+
return [Class_::class, Interface_::class];
18+
}
19+
20+
public function refactor(Node $node): \PhpParser\Node|null
21+
{
22+
if ($node instanceof Class_) {
23+
return $node;
24+
}
25+
26+
return null;
27+
}
28+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symplify\PHPStanRules\Tests\Rules\Rector\NoIntegerRefactorReturnRule;
6+
7+
use Iterator;
8+
use PHPStan\Testing\RuleTestCase;
9+
use PHPUnit\Framework\Attributes\DataProvider;
10+
use Symplify\PHPStanRules\Rules\Rector\NoIntegerRefactorReturnRule;
11+
12+
final class NoIntegerRefactorReturnRuleTest extends RuleTestCase
13+
{
14+
#[DataProvider('provideData')]
15+
public function testRule(string $filePath, array $expectedErrorsWithLines): void
16+
{
17+
$this->analyse([$filePath], $expectedErrorsWithLines);
18+
}
19+
20+
public static function provideData(): Iterator
21+
{
22+
$errorMessage = NoIntegerRefactorReturnRule::ERROR_MESSAGE;
23+
yield [__DIR__ . '/Fixture/SimpleReturnInt.php', [[$errorMessage, 20]]];
24+
25+
yield [__DIR__ . '/Fixture/SkipBareNodeReturn.php', []];
26+
}
27+
28+
protected function getRule(): NoIntegerRefactorReturnRule
29+
{
30+
return new NoIntegerRefactorReturnRule();
31+
}
32+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
rules:
2+
- Symplify\PHPStanRules\Rules\Rector\NoInstanceOfStaticReflectionRule

0 commit comments

Comments
 (0)