[DeadCode] Add RemoveJustPropertyFetchForAssignRector (#2423)

This commit is contained in:
Tomas Votruba 2022-06-03 12:05:24 +02:00 committed by GitHub
parent 0df2351b89
commit c5f35e4a1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 438 additions and 2 deletions

View File

@ -1,4 +1,4 @@
# 516 Rules Overview
# 517 Rules Overview
<br>
@ -14,7 +14,7 @@
- [Composer](#composer) (6)
- [DeadCode](#deadcode) (48)
- [DeadCode](#deadcode) (49)
- [DependencyInjection](#dependencyinjection) (2)
@ -3230,6 +3230,29 @@ Remove empty method call
<br>
### RemoveJustPropertyFetchForAssignRector
Remove assign of property, just for value assign
- class: [`Rector\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector`](../rules/DeadCode/Rector/StmtsAwareInterface/RemoveJustPropertyFetchForAssignRector.php)
```diff
class SomeClass
{
private $items = [];
public function run()
{
- $items = $this->items;
- $items[] = 1000;
- $this->items = $items ;
+ $this->items[] = 1000;
}
}
```
<br>
### RemoveLastReturnRector
Remove very last `return` that has no meaning

View File

@ -44,6 +44,7 @@ use Rector\DeadCode\Rector\PropertyProperty\RemoveNullPropertyInitializationRect
use Rector\DeadCode\Rector\Return_\RemoveDeadConditionAboveReturnRector;
use Rector\DeadCode\Rector\StaticCall\RemoveParentCallWithoutParentRector;
use Rector\DeadCode\Rector\Stmt\RemoveUnreachableStatementRector;
use Rector\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector;
use Rector\DeadCode\Rector\Switch_\RemoveDuplicatedCaseInSwitchRector;
use Rector\DeadCode\Rector\Ternary\TernaryToBooleanOrFalseToBooleanAndRector;
use Rector\DeadCode\Rector\TryCatch\RemoveDeadTryCatchRector;
@ -97,5 +98,6 @@ return static function (RectorConfig $rectorConfig): void {
RemoveNonExistingVarAnnotationRector::class,
RemoveUnusedPromotedPropertyRector::class,
RemoveLastReturnRector::class,
RemoveJustPropertyFetchForAssignRector::class,
]);
};

View File

@ -712,3 +712,8 @@ parameters:
-
message: '#Method "refactor(Params|Return)\(\)" returns bool type, so the name should start with is/has/was#'
path: rules/Php80/Rector/Class_/ConstantListClassToEnumRector.php
# known values
-
message: '#Offset \d+ does not exist on array<PhpParser\\Node\\Stmt>\|null#'
path: rules/DeadCode/Rector/StmtsAwareInterface/RemoveJustPropertyFetchForAssignRector.php

View File

@ -0,0 +1,17 @@
<?php
namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector\Fixture;
final class SkipDifferentPropertyFetch
{
private $items = [];
private $another = [];
public function run()
{
$items = $this->another;
$items[] = 1000;
$this->items = $items ;
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector\Fixture;
final class SkipDifferentVariable
{
private $items = [];
public function run()
{
$items = $this->items;
$items[] = 1000;
$this->items = $items2;
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector\Fixture;
final class SkipFourStmts
{
private $items = [];
public function run()
{
$items = $this->items;
$items[] = 1000;
$items[] = 1000;
$this->items = $items ;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector\Fixture;
class SomeClass
{
private $items = [];
public function run()
{
$items = $this->items;
$items[] = 1000;
$this->items = $items ;
}
}
?>
-----
<?php
namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector\Fixture;
class SomeClass
{
private $items = [];
public function run()
{
$this->items[] = 1000;
}
}
?>

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class RemoveJustPropertyFetchForAssignRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector;
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rule(RemoveJustPropertyFetchForAssignRector::class);
};

View File

@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\NodeAnalyzer;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\DeadCode\ValueObject\VariableAndPropertyFetchAssign;
final class JustPropertyFetchVariableAssignMatcher
{
public function __construct(
private readonly NodeComparator $nodeComparator
) {
}
public function match(StmtsAwareInterface $stmtsAware): ?VariableAndPropertyFetchAssign
{
$stmts = (array) $stmtsAware->stmts;
$stmtCount = count($stmts);
// must be exactly 3 stmts
if ($stmtCount !== 3) {
return null;
}
$firstVariableAndPropertyFetchAssign = $this->matchVariableAndPropertyFetchAssign($stmts[0]);
if (! $firstVariableAndPropertyFetchAssign instanceof VariableAndPropertyFetchAssign) {
return null;
}
$thirdVariableAndPropertyFetchAssign = $this->matchRevertedVariableAndPropertyFetchAssign($stmts[2]);
if (! $thirdVariableAndPropertyFetchAssign instanceof VariableAndPropertyFetchAssign) {
return null;
}
if (! $this->nodeComparator->areNodesEqual(
$firstVariableAndPropertyFetchAssign->getPropertyFetch(),
$thirdVariableAndPropertyFetchAssign->getPropertyFetch()
)) {
return null;
}
if (! $this->nodeComparator->areNodesEqual(
$firstVariableAndPropertyFetchAssign->getVariable(),
$thirdVariableAndPropertyFetchAssign->getVariable()
)) {
return null;
}
return $firstVariableAndPropertyFetchAssign;
}
private function matchVariableAndPropertyFetchAssign(Stmt $stmt): ?VariableAndPropertyFetchAssign
{
if (! $stmt instanceof Expression) {
return null;
}
if (! $stmt->expr instanceof Assign) {
return null;
}
$assign = $stmt->expr;
if (! $assign->expr instanceof PropertyFetch) {
return null;
}
if (! $assign->var instanceof Variable) {
return null;
}
return new VariableAndPropertyFetchAssign($assign->var, $assign->expr);
}
private function matchRevertedVariableAndPropertyFetchAssign(Stmt $stmt): ?VariableAndPropertyFetchAssign
{
if (! $stmt instanceof Expression) {
return null;
}
if (! $stmt->expr instanceof Assign) {
return null;
}
$assign = $stmt->expr;
if (! $assign->var instanceof PropertyFetch) {
return null;
}
if (! $assign->expr instanceof Variable) {
return null;
}
return new VariableAndPropertyFetchAssign($assign->expr, $assign->var);
}
}

View File

@ -0,0 +1,151 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\Rector\StmtsAwareInterface;
use PhpParser\Node;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\DeadCode\NodeAnalyzer\JustPropertyFetchVariableAssignMatcher;
use Rector\DeadCode\ValueObject\VariableAndPropertyFetchAssign;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustPropertyFetchForAssignRector\RemoveJustPropertyFetchForAssignRectorTest
*/
final class RemoveJustPropertyFetchForAssignRector extends AbstractRector
{
public function __construct(
private readonly JustPropertyFetchVariableAssignMatcher $justPropertyFetchVariableAssignMatcher
) {
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Remove assign of property, just for value assign', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
private $items = [];
public function run()
{
$items = $this->items;
$items[] = 1000;
$this->items = $items ;
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeClass
{
private $items = [];
public function run()
{
$this->items[] = 1000;
}
}
CODE_SAMPLE
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [StmtsAwareInterface::class];
}
/**
* @param StmtsAwareInterface $node
*/
public function refactor(Node $node): ?Node
{
$variableAndPropertyFetchAssign = $this->justPropertyFetchVariableAssignMatcher->match($node);
if (! $variableAndPropertyFetchAssign instanceof VariableAndPropertyFetchAssign) {
return null;
}
$secondStmt = $node->stmts[1];
if (! $secondStmt instanceof Expression) {
return null;
}
if (! $secondStmt->expr instanceof Assign) {
return null;
}
$middleAssign = $secondStmt->expr;
if ($middleAssign->var instanceof Variable) {
return $this->refactorToVariableAssign($middleAssign, $variableAndPropertyFetchAssign, $node);
}
if ($middleAssign->var instanceof ArrayDimFetch) {
return $this->removeToArrayDimFetchAssign($middleAssign, $variableAndPropertyFetchAssign, $node);
}
return null;
}
private function refactorToVariableAssign(
Assign $middleAssign,
VariableAndPropertyFetchAssign $variableAndPropertyFetchAssign,
StmtsAwareInterface $stmtsAware
): StmtsAwareInterface|Node|null {
$middleVariable = $middleAssign->var;
if (! $this->nodeComparator->areNodesEqual($middleVariable, $variableAndPropertyFetchAssign->getVariable())) {
return null;
}
// remove just-assign stmts
unset($stmtsAware->stmts[0]);
unset($stmtsAware->stmts[2]);
$middleAssign->var = $variableAndPropertyFetchAssign->getPropertyFetch();
return $stmtsAware;
}
private function removeToArrayDimFetchAssign(
Assign $middleAssign,
VariableAndPropertyFetchAssign $variableAndPropertyFetchAssign,
StmtsAwareInterface $stmtsAware
): StmtsAwareInterface|null {
$middleArrayDimFetch = $middleAssign->var;
if (! $middleArrayDimFetch instanceof ArrayDimFetch) {
return null;
}
if ($middleArrayDimFetch->var instanceof Variable) {
$middleNestedVariable = $middleArrayDimFetch->var;
if (! $this->nodeComparator->areNodesEqual(
$middleNestedVariable,
$variableAndPropertyFetchAssign->getVariable()
)) {
return null;
}
$middleArrayDimFetch->var = $variableAndPropertyFetchAssign->getPropertyFetch();
}
// remove just-assign stmts
unset($stmtsAware->stmts[0]);
unset($stmtsAware->stmts[2]);
return $stmtsAware;
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\ValueObject;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
final class VariableAndPropertyFetchAssign
{
public function __construct(
private readonly Variable $variable,
private readonly PropertyFetch $propertyFetch
) {
}
public function getVariable(): Variable
{
return $this->variable;
}
public function getPropertyFetch(): PropertyFetch
{
return $this->propertyFetch;
}
}