mirror of
https://github.com/rectorphp/rector.git
synced 2025-02-24 11:44:14 +01:00
Merge pull request #1584 from rectorphp/dead-zero
[DeadCode] Add RemoveDeadZeroAndOneOperationRector
This commit is contained in:
commit
7ad34fc4ee
@ -20,3 +20,4 @@ services:
|
||||
Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector: ~
|
||||
|
||||
Rector\CodeQuality\Rector\Return_\SimplifyUselessVariableRector: ~
|
||||
Rector\DeadCode\Rector\Plus\RemoveZeroAndOneBinaryRector: ~
|
||||
|
@ -0,0 +1,181 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Rector\Plus;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\AssignOp;
|
||||
use PhpParser\Node\Expr\BinaryOp;
|
||||
use PhpParser\Node\Expr\BinaryOp\Div;
|
||||
use PhpParser\Node\Expr\BinaryOp\Minus;
|
||||
use PhpParser\Node\Expr\BinaryOp\Mul;
|
||||
use PhpParser\Node\Expr\BinaryOp\Plus;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* @see https://3v4l.org/I0BGs
|
||||
*/
|
||||
final class RemoveDeadZeroAndOneOperationRector extends AbstractRector
|
||||
{
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$value = 5 * 1;
|
||||
$value = 5 + 0;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$value = 5;
|
||||
$value = 5;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [
|
||||
Plus::class,
|
||||
Minus::class,
|
||||
Mul::class,
|
||||
Div::class,
|
||||
Node\Expr\AssignOp\Plus::class,
|
||||
Node\Expr\AssignOp\Minus::class,
|
||||
Node\Expr\AssignOp\Mul::class,
|
||||
Node\Expr\AssignOp\Div::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AssignOp|BinaryOp $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$changedNode = null;
|
||||
$previousNode = $node;
|
||||
|
||||
if ($node instanceof AssignOp) {
|
||||
$changedNode = $this->processAssignOp($node);
|
||||
}
|
||||
|
||||
// -, +
|
||||
if ($node instanceof BinaryOp) {
|
||||
$changedNode = $this->processBinaryOp($node);
|
||||
}
|
||||
|
||||
// recurse nested combinations
|
||||
while ($changedNode !== null && ! $this->areNodesEqual($previousNode, $changedNode)) {
|
||||
$previousNode = $changedNode;
|
||||
|
||||
if ($changedNode instanceof BinaryOp || $changedNode instanceof AssignOp) {
|
||||
$changedNode = $this->refactor($changedNode);
|
||||
}
|
||||
|
||||
// nothing more to change, return last node
|
||||
if ($changedNode === null) {
|
||||
return $previousNode;
|
||||
}
|
||||
}
|
||||
|
||||
return $changedNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Plus|Minus $binaryOp
|
||||
*/
|
||||
private function processBinaryPlusAndMinus(BinaryOp $binaryOp): ?Expr
|
||||
{
|
||||
if ($this->isValue($binaryOp->left, 0)) {
|
||||
if ($this->isNumberType($binaryOp->right)) {
|
||||
return $binaryOp->right;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isValue($binaryOp->right, 0)) {
|
||||
if ($this->isNumberType($binaryOp->left)) {
|
||||
return $binaryOp->left;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Mul|Div $binaryOp
|
||||
*/
|
||||
private function processBinaryMulAndDiv(BinaryOp $binaryOp): ?Expr
|
||||
{
|
||||
if ($this->isValue($binaryOp->left, 1)) {
|
||||
if ($this->isNumberType($binaryOp->right)) {
|
||||
return $binaryOp->right;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isValue($binaryOp->right, 1)) {
|
||||
if ($this->isNumberType($binaryOp->left)) {
|
||||
return $binaryOp->left;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function processAssignOp(Node $node): ?Expr
|
||||
{
|
||||
// +=, -=
|
||||
if ($node instanceof Node\Expr\AssignOp\Plus || $node instanceof Node\Expr\AssignOp\Minus) {
|
||||
if (! $this->isValue($node->expr, 0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->isNumberType($node->var)) {
|
||||
return $node->var;
|
||||
}
|
||||
}
|
||||
|
||||
// *, /
|
||||
if ($node instanceof Node\Expr\AssignOp\Mul || $node instanceof Node\Expr\AssignOp\Div) {
|
||||
if (! $this->isValue($node->expr, 1)) {
|
||||
return null;
|
||||
}
|
||||
if ($this->isNumberType($node->var)) {
|
||||
return $node->var;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function processBinaryOp(Node $node): ?Expr
|
||||
{
|
||||
if ($node instanceof Plus || $node instanceof Minus) {
|
||||
return $this->processBinaryPlusAndMinus($node);
|
||||
}
|
||||
|
||||
// *, /
|
||||
if ($node instanceof Mul || $node instanceof Div) {
|
||||
return $this->processBinaryMulAndDiv($node);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Plus\RemoveDeadZeroAndOneOperationRector\Fixture;
|
||||
|
||||
class Assigns
|
||||
{
|
||||
public function run(int $value)
|
||||
{
|
||||
$value += 0;
|
||||
$value *= 1;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Plus\RemoveDeadZeroAndOneOperationRector\Fixture;
|
||||
|
||||
class Assigns
|
||||
{
|
||||
public function run(int $value)
|
||||
{
|
||||
$value;
|
||||
$value;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Plus\RemoveDeadZeroAndOneOperationRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$value = 5 * 1;
|
||||
$value = 1 * 5;
|
||||
|
||||
$value = 5 + 0;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Plus\RemoveDeadZeroAndOneOperationRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$value = 5;
|
||||
$value = 5;
|
||||
|
||||
$value = 5;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Plus\RemoveDeadZeroAndOneOperationRector\Fixture;
|
||||
|
||||
class Multiple
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$value = 0 + 5 + 0;
|
||||
$value = 5 + 0 + 5 + 0;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Plus\RemoveDeadZeroAndOneOperationRector\Fixture;
|
||||
|
||||
class Multiple
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$value = 5;
|
||||
$value = 5 + 5;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Plus\RemoveDeadZeroAndOneOperationRector\Fixture;
|
||||
|
||||
class SkipFloats
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$value = 5;
|
||||
var_dump($value); // 5
|
||||
|
||||
$value = $value * 1.0;
|
||||
var_dump($value); // 5.0
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Plus\RemoveDeadZeroAndOneOperationRector\Fixture;
|
||||
|
||||
class SkipTypeChnge
|
||||
{
|
||||
public function runBinary()
|
||||
{
|
||||
$value = '5';
|
||||
|
||||
return $value + 0;
|
||||
}
|
||||
|
||||
public function runAssign()
|
||||
{
|
||||
$value = '5';
|
||||
$value += 0;
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Plus\RemoveDeadZeroAndOneOperationRector;
|
||||
|
||||
use Rector\DeadCode\Rector\Plus\RemoveDeadZeroAndOneOperationRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class RemoveDeadZeroAndOneOperationRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$this->doTestFiles([
|
||||
__DIR__ . '/Fixture/fixture.php.inc',
|
||||
__DIR__ . '/Fixture/multiple.php.inc',
|
||||
__DIR__ . '/Fixture/assigns.php.inc',
|
||||
__DIR__ . '/Fixture/skip_type_change.php.inc',
|
||||
__DIR__ . '/Fixture/skip_floats.php.inc',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return RemoveDeadZeroAndOneOperationRector::class;
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ use PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
@ -414,7 +415,7 @@ final class NodeTypeResolver
|
||||
}
|
||||
|
||||
// skip anonymous classes, ref https://github.com/rectorphp/rector/issues/1574
|
||||
if ($node instanceof Expr\New_) {
|
||||
if ($node instanceof New_) {
|
||||
$className = $this->nameResolver->resolve($node->class);
|
||||
if ($className === null || Strings::contains($className, 'AnonymousClass')) {
|
||||
return [];
|
||||
|
@ -4,6 +4,8 @@ namespace Rector\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
@ -103,7 +105,7 @@ CODE_SAMPLE
|
||||
/**
|
||||
* Looks for "parent::<methodName>
|
||||
*/
|
||||
private function hasParentCallOfMethod(Node\Stmt\ClassMethod $classMethod, string $method): bool
|
||||
private function hasParentCallOfMethod(ClassMethod $classMethod, string $method): bool
|
||||
{
|
||||
return (bool) $this->betterNodeFinder->findFirst((array) $classMethod->stmts, function (Node $node) use (
|
||||
$method
|
||||
@ -122,7 +124,7 @@ CODE_SAMPLE
|
||||
|
||||
private function createParentStaticCall(string $method): Expression
|
||||
{
|
||||
$parentStaticCall = new StaticCall(new Node\Name('parent'), new Node\Identifier($method));
|
||||
$parentStaticCall = new StaticCall(new Name('parent'), new Identifier($method));
|
||||
|
||||
return new Expression($parentStaticCall);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user