Skip to content

Commit

Permalink
[DeadCode] Add RemoveJustVariableAssignRector
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Jul 3, 2022
1 parent 0660b21 commit cd15d1f
Show file tree
Hide file tree
Showing 9 changed files with 595 additions and 466 deletions.
791 changes: 340 additions & 451 deletions build/target-repository/docs/rector_rules_overview.md

Large diffs are not rendered by default.

28 changes: 16 additions & 12 deletions config/set/early-return.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\DeadCode\Rector\StmtsAwareInterface\RemoveJustVariableAssignRector;
use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector;
use Rector\EarlyReturn\Rector\Foreach_\ReturnAfterToEarlyOnBreakRector;
use Rector\EarlyReturn\Rector\If_\ChangeAndIfToEarlyReturnRector;
Expand All @@ -17,16 +18,19 @@
use Rector\EarlyReturn\Rector\StmtsAwareInterface\ReturnEarlyIfVariableRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rule(ChangeNestedForeachIfsToEarlyContinueRector::class);
$rectorConfig->rule(ChangeAndIfToEarlyReturnRector::class);
$rectorConfig->rule(ChangeIfElseValueAssignToEarlyReturnRector::class);
$rectorConfig->rule(ChangeNestedIfsToEarlyReturnRector::class);
$rectorConfig->rule(RemoveAlwaysElseRector::class);
$rectorConfig->rule(ReturnBinaryAndToEarlyReturnRector::class);
$rectorConfig->rule(ChangeOrIfReturnToEarlyReturnRector::class);
$rectorConfig->rule(ChangeOrIfContinueToMultiContinueRector::class);
$rectorConfig->rule(ReturnAfterToEarlyOnBreakRector::class);
$rectorConfig->rule(PreparedValueToEarlyReturnRector::class);
$rectorConfig->rule(ReturnBinaryOrToEarlyReturnRector::class);
$rectorConfig->rule(ReturnEarlyIfVariableRector::class);
$rectorConfig->rules([
ChangeNestedForeachIfsToEarlyContinueRector::class,
ChangeAndIfToEarlyReturnRector::class,
ChangeIfElseValueAssignToEarlyReturnRector::class,
ChangeNestedIfsToEarlyReturnRector::class,
RemoveAlwaysElseRector::class,
ReturnBinaryAndToEarlyReturnRector::class,
ChangeOrIfReturnToEarlyReturnRector::class,
ChangeOrIfContinueToMultiContinueRector::class,
ReturnAfterToEarlyOnBreakRector::class,
PreparedValueToEarlyReturnRector::class,
ReturnBinaryOrToEarlyReturnRector::class,
ReturnEarlyIfVariableRector::class,
RemoveJustVariableAssignRector::class,
]);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustVariableAssignRector\Fixture;

final class SkipReferencedVariable
{
private $temporaryValue;

public function run(&$result)
{
$result = 100;

$this->temporaryValue = $result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustVariableAssignRector\Fixture;

final class SomeClass
{
private int $temporaryValue;

public function run()
{
$result = 100;

$this->temporaryValue = $result;
}
}

?>
-----
<?php

namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustVariableAssignRector\Fixture;

final class SomeClass
{
private int $temporaryValue;

public function run()
{
$this->temporaryValue = 100;
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustVariableAssignRector;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;

final class RemoveJustVariableAssignRectorTest 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';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\DeadCode\Rector\StmtsAwareInterface\RemoveJustVariableAssignRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rule(RemoveJustVariableAssignRector::class);
};
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ function (Node $node) use ($variableUsages, $propertyFetch): ?PropertyFetch {
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode instanceof ClosureUse) {
// remove closure use which will be replaced by a property fetch
$this->nodesToRemoveCollector->addNodeToRemove($parentNode);
$this->removeNode($parentNode);

return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
<?php

declare(strict_types=1);

namespace Rector\DeadCode\Rector\StmtsAwareInterface;

use PhpParser\Node;
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\NodeAnalyzer\VariableAnalyzer;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \Rector\Tests\DeadCode\Rector\StmtsAwareInterface\RemoveJustVariableAssignRector\RemoveJustVariableAssignRectorTest
*/
final class RemoveJustVariableAssignRector extends AbstractRector
{
public function __construct(
private VariableAnalyzer $variableAnalyzer
) {
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Remove variable just to assign value or return value', [
new CodeSample(
<<<'CODE_SAMPLE'
final class SomeClass
{
public function run()
{
$result = 100;
$this->temporaryValue = $result;
}
}
CODE_SAMPLE

,
<<<'CODE_SAMPLE'
final class SomeClass
{
public function run()
{
$this->temporaryValue = 100;
}
}
CODE_SAMPLE
),
]);
}

/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [StmtsAwareInterface::class];
}

/**
* @param StmtsAwareInterface $node
*/
public function refactor(Node $node): ?Node
{
$stmts = (array) $node->stmts;
if ($stmts === []) {
return null;
}

$originalStmts = $stmts;

foreach ($stmts as $key => $stmt) {
$nextStmt = $stmts[$key + 1] ?? null;

if (! $stmt instanceof Expression) {
continue;
}

if (! $stmt->expr instanceof Assign) {
continue;
}

$currentAssign = $stmt->expr;

if (! $nextStmt instanceof Expression) {
continue;
}

if (! $nextStmt->expr instanceof Assign) {
continue;
}

$nextAssign = $nextStmt->expr;

if (! $this->areTwoVariablesCrossAssign($currentAssign, $nextAssign)) {
continue;
}

// ...
$currentAssign->var = $nextAssign->var;
unset($stmts[$key + 1]);
}

if ($originalStmts === $stmts) {
return null;
}

$node->stmts = $stmts;

return $node;
}

/**
* This detects if two variables are cross assigned:
*
* $<some> = 1000;
* $this->value = $<some>;
*/
private function areTwoVariablesCrossAssign(Assign $currentAssign, Assign $nextAssign): bool
{
// is just re-assign to variable
if (! $currentAssign->var instanceof Variable) {
return false;
}

if (! $nextAssign->expr instanceof Variable) {
return false;
}

if (! $this->nodeComparator->areNodesEqual($currentAssign->var, $nextAssign->expr)) {
return false;
}

if ($this->variableAnalyzer->isUsedByReference($currentAssign->var)) {
return false;
}

return ! $this->variableAnalyzer->isUsedByReference($nextAssign->expr);
}
}
4 changes: 2 additions & 2 deletions src/Rector/AbstractRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn

protected NodeComparator $nodeComparator;

protected NodesToRemoveCollector $nodesToRemoveCollector;

protected File $file;

protected NodesToAddCollector $nodesToAddCollector;
Expand All @@ -103,6 +101,8 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn

protected ScopeFactory $scopeFactory;

private NodesToRemoveCollector $nodesToRemoveCollector;

private SimpleCallableNodeTraverser $simpleCallableNodeTraverser;

private ExclusionManager $exclusionManager;
Expand Down

0 comments on commit cd15d1f

Please sign in to comment.