Skip to content

Commit

Permalink
Replace static with self for private constants (#3178)
Browse files Browse the repository at this point in the history
  • Loading branch information
alfredbez committed Dec 12, 2022
1 parent bea2e12 commit de00876
Show file tree
Hide file tree
Showing 11 changed files with 282 additions and 11 deletions.
23 changes: 21 additions & 2 deletions build/target-repository/docs/rector_rules_overview.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# 411 Rules Overview
# 412 Rules Overview

<br>

## Categories

- [Arguments](#arguments) (5)

- [CodeQuality](#codequality) (78)
- [CodeQuality](#codequality) (79)

- [CodingStyle](#codingstyle) (38)

Expand Down Expand Up @@ -594,6 +594,25 @@ Change multiple null compares to ?? queue

<br>

### ConvertStaticPrivateConstantToSelfRector

Replaces static::* access to private constants with self::* on final classes

- class: [`Rector\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector`](../rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php)

```diff
final class Foo {
private const BAR = 'bar';
public function run()
{
- $bar = static::BAR;
+ $bar = self::BAR;
}
}
```

<br>

### DoWhileBreakFalseToIfElseRector

Replace do (...} while (false); with more readable if/else conditions
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class ConvertStaticPrivateConstantToSelfRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

/**
* @return Iterator<array<string>>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/config.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Utils\Rector\Tests\Rector\UseDateTimeImmutableRector\Fixture;

/**
* @final
*/
class Foo
{
private const BAR = 1;
public function baz(): void
{
echo static::BAR;
}
}
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Utils\Rector\Tests\Rector\UseDateTimeImmutableRector\Fixture;

class Foo
{
private const BAR = 1;
public function baz(): void
{
echo static::BAR;
}
}
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Utils\Rector\Tests\Rector\UseDateTimeImmutableRector\Fixture;

final class Foo
{
public function run(): void
{
echo \DateTimeInterface::ATOM;
}
}
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Utils\Rector\Tests\Rector\UseDateTimeImmutableRector\Fixture;

final class Foo
{
protected const BAR = 1;
public const BAZ = 1;
public function run(): void
{
echo static::BAR;
echo static::BAZ;
}
}
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Utils\Rector\Tests\Rector\UseDateTimeImmutableRector\Fixture;

final class Foo
{
private const BAR = 1;
public function baz(): void
{
echo self::BAR;
}
}
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Utils\Rector\Tests\Rector\UseDateTimeImmutableRector\Fixture;

final class Foo
{
private const BAR = 1;
public function baz(): void
{
echo static::BAR;
}
}
?>
-----
<?php

namespace Utils\Rector\Tests\Rector\UseDateTimeImmutableRector\Fixture;

final class Foo
{
private const BAR = 1;
public function baz(): void
{
echo self::BAR;
}
}
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(Rector\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector::class);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

namespace Rector\CodeQuality\Rector\ClassConstFetch;

use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Name;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \Rector\Tests\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector\ConvertStaticPrivateConstantToSelfRectorTest
* @see https://3v4l.org/8Y0ba
* @see https://phpstan.org/r/11d4c850-1a40-4fae-b665-291f96104d11
*/
final class ConvertStaticPrivateConstantToSelfRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Replaces static::* access to private constants with self::* on final classes',
[
new CodeSample(
<<<'CODE_SAMPLE'
final class Foo {
private const BAR = 'bar';
public function run()
{
$bar = static::BAR;
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
final class Foo {
private const BAR = 'bar';
public function run()
{
$bar = self::BAR;
}
}
CODE_SAMPLE
,
),
],
);
}

public function getNodeTypes(): array
{
return [ClassConstFetch::class];
}

/**
* @param \PhpParser\Node\Expr\ClassConstFetch $node
*/
public function refactor(Node $node): ?ClassConstFetch
{
if (! $this->isUsingStatic($node)) {
return null;
}

if (! $this->isPrivateConstant($node)) {
return null;
}

$node->class = new Name('self');

return $node;
}

private function isUsingStatic(ClassConstFetch $node): bool
{
if (! $node->class instanceof Name) {
return false;
}

return $node->class->toString() === 'static';
}

private function isPrivateConstant(ClassConstFetch $node): bool
{
$class = $this->betterNodeFinder->findParentType($node, Node\Stmt\Class_::class);
if (! $class instanceof Node\Stmt\Class_) {
return false;
}
if (! $class->isFinal()) {
return false;
}
$constantName = $node->name;
if (! $constantName instanceof Node\Identifier) {
return false;
}
foreach ($class->getConstants() as $classConst) {
if (! $this->nodeNameResolver->isName($classConst, $constantName->toString())) {
continue;
}

return $classConst->isPrivate();
}

return false;
}
}
25 changes: 16 additions & 9 deletions utils/Command/MissingInSetCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Nette\Loaders\RobotLoader;
use Nette\Utils\FileSystem;
use Nette\Utils\Strings;
use Rector\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Contract\Rector\DeprecatedRectorInterface;
use Rector\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchRector;
Expand All @@ -29,6 +30,16 @@ final class MissingInSetCommand extends Command
__DIR__ . '/../../rules/TypeDeclaration/Rector' => __DIR__ . '/../../config/set/type-declaration.php',
];

/**
* @var list<string>
*/
private const SKIPPED_RULES = [
ConfigurableRectorInterface::class,
DeprecatedRectorInterface::class,
ConvertStaticPrivateConstantToSelfRector::class,
RemoveJustPropertyFetchRector::class,
];

/**
* @see https://regex101.com/r/HtsmKC/1
* @var string
Expand Down Expand Up @@ -61,16 +72,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$rectorClassesNotInSetConfig = array_filter(
$rectorClassesNotInSetConfig,
static function (string $rectorClass): bool {
if (is_a($rectorClass, ConfigurableRectorInterface::class, true)) {
return false;
foreach (self::SKIPPED_RULES as $rule) {
if (is_a($rectorClass, $rule, true)) {
return false;
}
}

if (is_a($rectorClass, DeprecatedRectorInterface::class, true)) {
return false;
}

// needs more work before adding to the set, @todo
return ! is_a($rectorClass, RemoveJustPropertyFetchRector::class, true);
return true;
}
);

Expand Down

0 comments on commit de00876

Please sign in to comment.