mirror of
https://github.com/rectorphp/rector.git
synced 2025-03-14 20:39:43 +01:00
Merge pull request #676 from rectorphp/cq-assign-short
[CodeQuality] Add CombinedAssignRector
This commit is contained in:
commit
45d1810602
@ -19,19 +19,19 @@
|
|||||||
"symfony/dependency-injection": "^3.4|^4.1",
|
"symfony/dependency-injection": "^3.4|^4.1",
|
||||||
"symfony/finder": "^3.4|^4.1",
|
"symfony/finder": "^3.4|^4.1",
|
||||||
"symfony/process": "^3.4|^4.1",
|
"symfony/process": "^3.4|^4.1",
|
||||||
"symplify/better-phpdoc-parser": "^5.2",
|
"symplify/better-phpdoc-parser": "^5.1",
|
||||||
"symplify/easy-coding-standard": "^5.2",
|
"symplify/easy-coding-standard": "^5.1",
|
||||||
"symplify/package-builder": "^5.2",
|
"symplify/package-builder": "^5.1",
|
||||||
"thecodingmachine/safe": "^0.1.4"
|
"thecodingmachine/safe": "^0.1.4"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"humbug/php-scoper": "^0.9.2",
|
"humbug/php-scoper": "^0.9.2",
|
||||||
"phpunit/phpunit": "^7.3",
|
"phpunit/phpunit": "^7.3",
|
||||||
"symplify/changelog-linker": "^5.2",
|
"symplify/changelog-linker": "^5.1",
|
||||||
"symplify/monorepo-builder": "^5.2",
|
"symplify/monorepo-builder": "^5.1",
|
||||||
"symplify/phpstan-extensions": "^5.2",
|
"symplify/phpstan-extensions": "^5.1",
|
||||||
"thecodingmachine/phpstan-safe-rule": "^0.1.0",
|
"thecodingmachine/phpstan-safe-rule": "^0.1.0",
|
||||||
"thecodingmachine/phpstan-strict-rules": "^0.10.3",
|
"thecodingmachine/phpstan-strict-rules": "^0.10.4",
|
||||||
"tracy/tracy": "^2.5"
|
"tracy/tracy": "^2.5"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -121,6 +121,7 @@
|
|||||||
"tests/Rector/Architecture/DoctrineRepositoryAsService/Wrong",
|
"tests/Rector/Architecture/DoctrineRepositoryAsService/Wrong",
|
||||||
"tests/Rector/Interface_/MergeInterfacesRector/Wrong",
|
"tests/Rector/Interface_/MergeInterfacesRector/Wrong",
|
||||||
"tests/Rector/Visibility/ChangeMethodVisibilityRector/Wrong",
|
"tests/Rector/Visibility/ChangeMethodVisibilityRector/Wrong",
|
||||||
|
"tests/Rector/CodeQuality/CombinedAssignRector/Wrong",
|
||||||
"tests/Rector/Visibility/ChangePropertyVisibilityRector/Wrong",
|
"tests/Rector/Visibility/ChangePropertyVisibilityRector/Wrong",
|
||||||
"tests/Rector/Visibility/ChangeConstantVisibilityRector/Wrong",
|
"tests/Rector/Visibility/ChangeConstantVisibilityRector/Wrong",
|
||||||
"tests/Rector/Annotation/AnnotationReplacerRector/Wrong",
|
"tests/Rector/Annotation/AnnotationReplacerRector/Wrong",
|
||||||
@ -218,7 +219,5 @@
|
|||||||
"bin": ["bin/rector"],
|
"bin": ["bin/rector"],
|
||||||
"config": {
|
"config": {
|
||||||
"sort-packages": true
|
"sort-packages": true
|
||||||
},
|
}
|
||||||
"minimum-stability": "dev",
|
|
||||||
"prefer-stable": true
|
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,9 @@ parameters:
|
|||||||
# not really needed, empty
|
# not really needed, empty
|
||||||
- '#Rector\\NodeTraverser\\RectorNodeTraverser::__construct\(\) does not call parent constructor from PhpParser\\NodeTraverser#'
|
- '#Rector\\NodeTraverser\\RectorNodeTraverser::__construct\(\) does not call parent constructor from PhpParser\\NodeTraverser#'
|
||||||
|
|
||||||
|
# intentionally
|
||||||
|
- '#In method "(.*?)", caught "Throwable" must be rethrown. Either catch a more specific exception or add a "throw" clause in the "catch" block to propagate the exception#'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
-
|
-
|
||||||
class: Symplify\PHPStanExtensions\Type\SplFileInfoTolerantDynamicMethodReturnTypeExtension
|
class: Symplify\PHPStanExtensions\Type\SplFileInfoTolerantDynamicMethodReturnTypeExtension
|
||||||
|
117
src/Rector/CodeQuality/CombinedAssignRector.php
Normal file
117
src/Rector/CodeQuality/CombinedAssignRector.php
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Rector\CodeQuality;
|
||||||
|
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Expr\Assign;
|
||||||
|
use PhpParser\Node\Expr\AssignOp;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\BitwiseAnd as AssignBitwiseAnd;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\BitwiseOr as AssignBitwiseOr;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\BitwiseXor as AssignBitwiseXor;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\Concat as AssignConcat;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\Div as AssignDiv;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\Minus as AssignMinus;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\Mod as AssignMod;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\Mul as AssignMul;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\Plus as AssignPlus;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\Pow as AssignPow;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\ShiftLeft as AssignShiftLeft;
|
||||||
|
use PhpParser\Node\Expr\AssignOp\ShiftRight as AssignShiftRight;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\BitwiseAnd;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\BitwiseOr;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\BitwiseXor;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\Concat;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\Div;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\Minus;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\Mod;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\Mul;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\Plus;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\Pow;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\ShiftLeft;
|
||||||
|
use PhpParser\Node\Expr\BinaryOp\ShiftRight;
|
||||||
|
use Rector\Printer\BetterStandardPrinter;
|
||||||
|
use Rector\Rector\AbstractRector;
|
||||||
|
use Rector\RectorDefinition\CodeSample;
|
||||||
|
use Rector\RectorDefinition\RectorDefinition;
|
||||||
|
|
||||||
|
final class CombinedAssignRector extends AbstractRector
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $binaryOpClassToAssignOpClass = [
|
||||||
|
BitwiseOr::class => AssignBitwiseOr::class,
|
||||||
|
BitwiseAnd::class => AssignBitwiseAnd::class,
|
||||||
|
BitwiseXor::class => AssignBitwiseXor::class,
|
||||||
|
Plus::class => AssignPlus::class,
|
||||||
|
Div::class => AssignDiv::class,
|
||||||
|
Mul::class => AssignMul::class,
|
||||||
|
Minus::class => AssignMinus::class,
|
||||||
|
Concat::class => AssignConcat::class,
|
||||||
|
Pow::class => AssignPow::class,
|
||||||
|
Mod::class => AssignMod::class,
|
||||||
|
ShiftLeft::class => AssignShiftLeft::class,
|
||||||
|
ShiftRight::class => AssignShiftRight::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var BetterStandardPrinter
|
||||||
|
*/
|
||||||
|
private $betterStandardPrinter;
|
||||||
|
|
||||||
|
public function __construct(BetterStandardPrinter $betterStandardPrinter)
|
||||||
|
{
|
||||||
|
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefinition(): RectorDefinition
|
||||||
|
{
|
||||||
|
return new RectorDefinition(
|
||||||
|
'Simplify $value = $value + 5; assignments to shorter ones',
|
||||||
|
[new CodeSample('$value = $value + 5;', '$value += 5;')]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getNodeTypes(): array
|
||||||
|
{
|
||||||
|
return [Assign::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Assign $assignNode
|
||||||
|
*/
|
||||||
|
public function refactor(Node $assignNode): ?Node
|
||||||
|
{
|
||||||
|
if (! $assignNode->expr instanceof BinaryOp) {
|
||||||
|
return $assignNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var BinaryOp $binaryNode */
|
||||||
|
$binaryNode = $assignNode->expr;
|
||||||
|
|
||||||
|
if (! $this->areNodesEqual($assignNode->var, $binaryNode->left)) {
|
||||||
|
return $assignNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
$binaryNodeClass = get_class($binaryNode);
|
||||||
|
if (! isset($this->binaryOpClassToAssignOpClass[$binaryNodeClass])) {
|
||||||
|
return $assignNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newAssignNodeClass = $this->binaryOpClassToAssignOpClass[$binaryNodeClass];
|
||||||
|
|
||||||
|
/** @var AssignOp $newAssignNodeClass */
|
||||||
|
return new $newAssignNodeClass($assignNode->var, $binaryNode->right);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function areNodesEqual(Node $firstNode, Node $secondNode): bool
|
||||||
|
{
|
||||||
|
return $this->betterStandardPrinter->prettyPrint([$firstNode]) === $this->betterStandardPrinter->prettyPrint(
|
||||||
|
[$secondNode]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Tests\Rector\CodeQuality\CombinedAssignRector;
|
||||||
|
|
||||||
|
use Iterator;
|
||||||
|
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Rector\Rector\CodeQuality\CombinedAssignRector
|
||||||
|
*
|
||||||
|
* Some tests used from:
|
||||||
|
* - https://github.com/doctrine/coding-standard/pull/83/files
|
||||||
|
* - https://github.com/slevomat/coding-standard/blob/master/tests/Sniffs/Operators/data/requireCombinedAssignmentOperatorErrors.php
|
||||||
|
*/
|
||||||
|
final class CombinedAssignRectorTest extends AbstractRectorTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider provideWrongToFixedFiles()
|
||||||
|
*/
|
||||||
|
public function test(string $wrong, string $fixed): void
|
||||||
|
{
|
||||||
|
$this->doTestFileMatchesExpectedContent($wrong, $fixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideWrongToFixedFiles(): Iterator
|
||||||
|
{
|
||||||
|
yield [__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc'];
|
||||||
|
yield [__DIR__ . '/Wrong/wrong2.php.inc', __DIR__ . '/Correct/correct2.php.inc'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function provideConfig(): string
|
||||||
|
{
|
||||||
|
return __DIR__ . '/config.yml';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
$value = 10;
|
||||||
|
$value += 2;
|
||||||
|
|
||||||
|
$foo .= '';
|
||||||
|
$bar += Something::count();
|
||||||
|
$baz **= 2;
|
||||||
|
$quux |= Something::FOO;
|
@ -0,0 +1,25 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Tests\Rector\CodeQuality\CombinedAssignRector\Wrong;
|
||||||
|
|
||||||
|
class Whatever
|
||||||
|
{
|
||||||
|
public function __construct($parameter)
|
||||||
|
{
|
||||||
|
self::$a &= 2;
|
||||||
|
static::$a |= 4;
|
||||||
|
self::$$parameter .= '';
|
||||||
|
parent::${'a'} /= 10;
|
||||||
|
self::${'a'}[0] -= 100;
|
||||||
|
Anything::$a **= 2;
|
||||||
|
Something\Anything::$a %= 2;
|
||||||
|
\Something\Anything::$a *= 1000;
|
||||||
|
self::$a::$b += 4;
|
||||||
|
$this::$a <<= 2;
|
||||||
|
$this->a >>= 2;
|
||||||
|
$this->$$parameter ^= 10;
|
||||||
|
$this->{'a'} += 10;
|
||||||
|
$this->${'a'}[0]->$$b[1][2]::$c[3][4][5]->{" $d"} *= 100;
|
||||||
|
$this->something += 10;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
$value = 10;
|
||||||
|
$value = $value + 2;
|
||||||
|
|
||||||
|
$foo = $foo . '';
|
||||||
|
$bar = $bar + Something::count();
|
||||||
|
$baz = $baz ** 2;
|
||||||
|
$quux = $quux | Something::FOO;
|
@ -0,0 +1,25 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\Tests\Rector\CodeQuality\CombinedAssignRector\Wrong;
|
||||||
|
|
||||||
|
class Whatever
|
||||||
|
{
|
||||||
|
public function __construct($parameter)
|
||||||
|
{
|
||||||
|
self::$a = self::$a & 2;
|
||||||
|
static::$a = static::$a | 4;
|
||||||
|
self::$$parameter = self::$$parameter . '';
|
||||||
|
parent::${'a'} = parent::${'a'} / 10;
|
||||||
|
self::${'a'}[0] = self::${'a'}[0] - 100;
|
||||||
|
Anything::$a = Anything::$a ** 2;
|
||||||
|
Something\Anything::$a = Something\Anything::$a % 2;
|
||||||
|
\Something\Anything::$a = \Something\Anything::$a * 1000;
|
||||||
|
self::$a::$b = self::$a::$b + 4;
|
||||||
|
$this::$a = $this::$a << 2;
|
||||||
|
$this->a = $this->a >> 2;
|
||||||
|
$this->$$parameter = $this->$$parameter ^ 10;
|
||||||
|
$this->{'a'} = $this->{'a'} + 10;
|
||||||
|
$this->${'a'}[0]->$$b[1][2]::$c[3][4][5]->{" $d"} = $this->${'a'}[0]->$$b[1][2]::$c[3][4][5]->{" $d"} * 100;
|
||||||
|
$this->something = $this->something + 10;
|
||||||
|
}
|
||||||
|
}
|
2
tests/Rector/CodeQuality/CombinedAssignRector/config.yml
Normal file
2
tests/Rector/CodeQuality/CombinedAssignRector/config.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
services:
|
||||||
|
Rector\Rector\CodeQuality\CombinedAssignRector: ~
|
Loading…
x
Reference in New Issue
Block a user