[CodeQuality] Add ArrayMergeOfNonArraysToSimpleArrayRector

This commit is contained in:
Tomas Votruba 2019-10-17 19:03:40 +02:00
parent 5a4134e14f
commit e91e8ea2c1
5 changed files with 210 additions and 0 deletions

View File

@ -44,3 +44,4 @@ services:
Rector\CodeQuality\Rector\If_\ShortenElseIfRector: ~
Rector\SOLID\Rector\ClassMethod\UseInterfaceOverImplementationInConstructorRector: ~
Rector\CodeQuality\Rector\FuncCall\AddPregQuoteDelimiterRector: ~
Rector\CodeQuality\Rector\FuncCall\ArrayMergeOfNonArraysToSimpleArrayRector: ~

View File

@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
namespace Rector\CodeQuality\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\FuncCall;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Constant\ConstantArrayType;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
/**
* @see https://3v4l.org/aLf96
*
* @see \Rector\CodeQuality\Tests\Rector\FuncCall\ArrayMergeOfNonArraysToSimpleArrayRector\ArrayMergeOfNonArraysToSimpleArrayRectorTest
*/
final class ArrayMergeOfNonArraysToSimpleArrayRector extends AbstractRector
{
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change array_merge of non arrays to array directly', [
new CodeSample(
<<<'PHP'
class SomeClass
{
public function go()
{
$value = 5;
$value2 = 10;
return array_merge([$value, $value2]);
}
}
PHP
,
<<<'PHP'
class SomeClass
{
public function go()
{
$value = 5;
$value2 = 10;
return [$value, $value2];
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [FuncCall::class];
}
/**
* @param FuncCall $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isName($node, 'array_merge')) {
return null;
}
if ($this->shouldSkip($node)) {
return null;
}
$array = new Array_();
foreach ($node->args as $arg) {
/** @var Array_ $nestedArrayItem */
$nestedArrayItem = $arg->value;
// skip
if (! $nestedArrayItem instanceof Array_) {
return null;
}
foreach ($nestedArrayItem->items as $nestedArrayItemItem) {
$array->items[] = $nestedArrayItemItem->value;
}
}
return $array;
}
private function shouldSkip(Node $node): bool
{
foreach ($node->args as $arg) {
$argumentValueStaticType = $this->getStaticType($arg->value);
if (! $argumentValueStaticType instanceof ConstantArrayType) {
return true;
}
foreach ($argumentValueStaticType->getValueTypes() as $valueType) {
// nested array → skip
if ($valueType instanceof ArrayType) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Rector\CodeQuality\Tests\Rector\FuncCall\ArrayMergeOfNonArraysToSimpleArrayRector;
use Iterator;
use Rector\CodeQuality\Rector\FuncCall\ArrayMergeOfNonArraysToSimpleArrayRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class ArrayMergeOfNonArraysToSimpleArrayRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideDataForTest()
*/
public function test(string $file): void
{
$this->doTestFile($file);
}
public function provideDataForTest(): Iterator
{
yield [__DIR__ . '/Fixture/fixture.php.inc'];
// skip multiple items https://3v4l.org/anks3
yield [__DIR__ . '/Fixture/skip_non_arrays.php.inc'];
}
protected function getRectorClass(): string
{
return ArrayMergeOfNonArraysToSimpleArrayRector::class;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Rector\CodeQuality\Tests\Rector\FuncCall\ArrayMergeOfNonArraysToSimpleArrayRector\Fixture;
class SomeClass
{
public function go()
{
$value = 5;
$value2 = 10;
return array_merge([$value], [$value2]);
}
}
?>
-----
<?php
namespace Rector\CodeQuality\Tests\Rector\FuncCall\ArrayMergeOfNonArraysToSimpleArrayRector\Fixture;
class SomeClass
{
public function go()
{
$value = 5;
$value2 = 10;
return [$value, $value2];
}
}
?>

View File

@ -0,0 +1,29 @@
<?php
namespace Rector\CodeQuality\Tests\Rector\FuncCall\ArrayMergeOfNonArraysToSimpleArrayRector\Fixture;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Do_;
use PhpParser\Node\Stmt\For_;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\While_;
class SkipNonArrays
{
/**
* @var string[]
*/
private const BREAK_NODES = [FunctionLike::class, ClassMethod::class];
/**
* @var string[]
*/
private const LOOP_NODES = [For_::class, Foreach_::class, While_::class, Do_::class, Switch_::class];
public function go()
{
return array_merge(self::LOOP_NODES, self::BREAK_NODES);
}
}