Skip to content

Commit a753040

Browse files
committed
[rector] add NoIntegerRefactorReturnRule
1 parent b98bb10 commit a753040

File tree

7 files changed

+158
-0
lines changed

7 files changed

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