[CodingStyle] Add UnSpreadOperatorRector (#5015)

Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
Abdul Malik Ikhsan 2020-12-28 18:08:40 +07:00 committed by GitHub
parent a7544e85e1
commit bd1bd30762
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 241 additions and 0 deletions

View File

@ -0,0 +1,143 @@
<?php
declare(strict_types=1);
namespace Rector\CodingStyle\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\CodingStyle\Tests\Rector\ClassMethod\UnSpreadOperatorRector\UnSpreadOperatorRectorTest
*/
final class UnSpreadOperatorRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Remove spread operator', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
public function run(...$array)
{
}
public function execute(array $data)
{
$this->run(...$data);
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeClass
{
public function run(array $array)
{
}
public function execute(array $data)
{
$this->run($data);
}
}
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [ClassMethod::class, MethodCall::class];
}
/**
* @param ClassMethod|MethodCall $node
*/
public function refactor(Node $node): ?Node
{
if ($node instanceof ClassMethod) {
return $this->processUnspreadOperatorClassMethodParams($node);
}
return $this->processUnspreadOperatorMethodCallArgs($node);
}
private function processUnspreadOperatorClassMethodParams(ClassMethod $classMethod): ?ClassMethod
{
$params = $classMethod->params;
if ($params === []) {
return null;
}
$spreadVariables = $this->getSpreadVariables($params);
if ($spreadVariables === []) {
return null;
}
foreach (array_keys($spreadVariables) as $key) {
$classMethod->params[$key]->variadic = false;
$classMethod->params[$key]->type = new Identifier('array');
}
return $classMethod;
}
private function processUnspreadOperatorMethodCallArgs(MethodCall $methodCall): ?MethodCall
{
$args = $methodCall->args;
if ($args === []) {
return null;
}
$spreadVariables = $this->getSpreadVariables($args);
if ($spreadVariables === []) {
return null;
}
foreach (array_keys($spreadVariables) as $key) {
$methodCall->args[$key]->unpack = false;
}
return $methodCall;
}
/**
* @param Param[]|Arg[] $array
* @return Param[]|Arg[]
*/
private function getSpreadVariables(array $array): array
{
$spreadVariables = [];
foreach ($array as $key => $paramOrArg) {
if ($paramOrArg instanceof Param) {
if (! $paramOrArg->variadic) {
continue;
}
if ($paramOrArg->type !== null) {
continue;
}
}
if ($paramOrArg instanceof Arg && ! $paramOrArg->unpack) {
continue;
}
$spreadVariables[$key] = $paramOrArg;
}
return $spreadVariables;
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\UnSpreadOperatorRector\Fixture;
final class Fixture
{
public function run(...$args)
{
}
public function execute(array $data)
{
$this->run(...$data);
}
}
?>
-----
<?php
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\UnSpreadOperatorRector\Fixture;
final class Fixture
{
public function run(array $args)
{
}
public function execute(array $data)
{
$this->run($data);
}
}
?>

View File

@ -0,0 +1,11 @@
<?php
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\UnSpreadOperatorRector\Fixture;
final class SkipNoParamsOrArgs
{
public function run()
{
$this->execute();
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\UnSpreadOperatorRector\Fixture;
final class SkipNoSpreadVariables
{
public function run(array $data)
{
$this->execute($data);
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\UnSpreadOperatorRector\Fixture;
final class SkipTypedParamVariadic
{
public function run(array ...$var)
{
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\UnSpreadOperatorRector;
use Iterator;
use Rector\CodingStyle\Rector\ClassMethod\UnSpreadOperatorRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class UnSpreadOperatorRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return UnSpreadOperatorRector::class;
}
}