Add ReturnArrayClassMethodToYieldRector

This commit is contained in:
Tomas Votruba 2019-01-03 11:54:13 +01:00
parent ca1588309b
commit 7f50b8b5a6
10 changed files with 399 additions and 6 deletions

View File

@ -10,3 +10,4 @@ services:
# requires configuration
# Rector\CodingStyle\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector: ~
# Rector\CodingStyle\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector: ~

View File

@ -1,2 +1,5 @@
services:
Rector\PHPUnit\Rector\ArrayToYieldDataProviderRector: ~
Rector\CodingStyle\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector:

View File

@ -17,10 +17,12 @@
- [CodeQuality\Return_](#codequalityreturn_)
- [CodeQuality\Ternary](#codequalityternary)
- [CodingStyle\ClassConst](#codingstyleclassconst)
- [CodingStyle\ClassMethod](#codingstyleclassmethod)
- [CodingStyle\FuncCall](#codingstylefunccall)
- [CodingStyle\Identical](#codingstyleidentical)
- [CodingStyle\If_](#codingstyleif_)
- [CodingStyle\Switch_](#codingstyleswitch_)
- [CodingStyle\Use_](#codingstyleuse_)
- [DeadCode\Array_](#deadcodearray_)
- [DeadCode\Assign](#deadcodeassign)
- [DeadCode\ClassMethod](#deadcodeclassmethod)
@ -488,8 +490,116 @@ Complete constant `@var` annotations for missing one, yet known.
<br>
## CodingStyle\ClassMethod
### `ReturnArrayClassMethodToYieldRector`
- class: `Rector\CodingStyle\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector`
Turns yield return to array return in specific type and method
```yaml
services:
Rector\CodingStyle\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector:
EventSubscriberInterface:
- getSubscribedEvents
```
```diff
class SomeEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
- yeild 'event' => 'callback';
+ return ['event' => 'callback'];
}
}
```
<br>
### `YieldClassMethodToArrayClassMethodRector`
- class: `Rector\CodingStyle\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector`
Turns yield return to array return in specific type and method
```yaml
services:
Rector\CodingStyle\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector:
EventSubscriberInterface:
- getSubscribedEvents
```
```diff
class SomeEventSubscriber implements EventSubscriberInterface
-{
- public static function getSubscribedEvents()
{
- yeild 'event' => 'callback';
- }
-}
+ public static function getSubscribedEvents()
+ {
+ return ['event' => 'callback'];
+ }
+ }
```
<br>
## CodingStyle\FuncCall
### `SetTypeToCastRector`
- class: `Rector\CodingStyle\Rector\FuncCall\SetTypeToCastRector`
Changes settype() to (type) where possible
```diff
class SomeClass
{
- public function run($foo)
+ public function run(array $items)
{
- settype($foo, 'string');
+ $foo = (string) $foo;
- return settype($foo, 'integer');
+ return (int) $foo;
}
}
```
<br>
### `ConsistentImplodeRector`
- class: `Rector\CodingStyle\Rector\FuncCall\ConsistentImplodeRector`
Changes various implode forms to consistent one
```diff
class SomeClass
{
public function run(array $items)
{
- $itemsAsStrings = implode($items);
- $itemsAsStrings = implode($items, '|');
+ $itemsAsStrings = implode('', $items);
+ $itemsAsStrings = implode('|', $items);
$itemsAsStrings = implode('|', $items);
}
}
```
<br>
### `SimpleArrayCallableToStringRector`
- class: `Rector\CodingStyle\Rector\FuncCall\SimpleArrayCallableToStringRector`
@ -566,6 +676,26 @@ Changes switch with 2 options to if-else
<br>
## CodingStyle\Use_
### `RemoveUnusedAliasRector`
- class: `Rector\CodingStyle\Rector\Use_\RemoveUnusedAliasRector`
Removes unused use aliases
```diff
-use Symfony\Kernel as BaseKernel;
+use Symfony\Kernel;
-class SomeClass extends BaseKernel
+class SomeClass extends Kernel
{
}
```
<br>
## DeadCode\Array_
### `RemoveDuplicatedArrayKeyRector`
@ -1631,7 +1761,7 @@ Null is no more allowed in get_class()
- class: `Rector\Php\Rector\FuncCall\TrailingCommaArgumentsRector`
Adds trailing commas to function and methods calls
Adds trailing commas to function and methods calls
```diff
calling(

View File

@ -0,0 +1,126 @@
<?php declare(strict_types=1);
namespace Rector\CodingStyle\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Return_;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\PhpParser\NodeTransformer;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\ConfiguredCodeSample;
use Rector\RectorDefinition\RectorDefinition;
/**
* @see https://medium.com/tech-tajawal/use-memory-gently-with-yield-in-php-7e62e2480b8d
* @see https://3v4l.org/5PJid
*/
final class ReturnArrayClassMethodToYieldRector extends AbstractRector
{
/**
* @var string[][]
*/
private $methodsByType = [];
/**
* @var NodeTransformer
*/
private $nodeTransformer;
/**
* @param string[][] $methodsByType
*/
public function __construct(array $methodsByType, NodeTransformer $nodeTransformer)
{
$this->methodsByType = $methodsByType;
$this->nodeTransformer = $nodeTransformer;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Turns yield return to array return in specific type and method', [
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
class SomeEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
yeild 'event' => 'callback';
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return ['event' => 'callback'];
}
}
CODE_SAMPLE
,
[
'EventSubscriberInterface' => ['getSubscribedEvents'],
]
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [ClassMethod::class];
}
/**
* @param ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
foreach ($this->methodsByType as $type => $methods) {
if (! $this->isType($node, $type)) {
continue;
}
foreach ($methods as $method) {
if (! $this->isName($node, $method)) {
continue;
}
$arrayNode = $this->collectReturnArrayNodesFromClassMethod($node);
if ($arrayNode === null) {
continue;
}
$yieldNodes = $this->nodeTransformer->transformArrayToYields($arrayNode);
// remove whole return node
$this->removeNode($arrayNode->getAttribute(Attribute::PARENT_NODE));
$node->stmts = array_merge($node->stmts, $yieldNodes);
}
}
return $node;
}
private function collectReturnArrayNodesFromClassMethod(ClassMethod $classMethodNode): ?Array_
{
if ($classMethodNode->stmts === null) {
return null;
}
foreach ($classMethodNode->stmts as $statement) {
if ($statement instanceof Return_) {
if ($statement->expr instanceof Array_) {
return $statement->expr;
}
}
}
return null;
}
}

View File

@ -14,11 +14,12 @@ use Rector\RectorDefinition\RectorDefinition;
/**
* @see https://medium.com/tech-tajawal/use-memory-gently-with-yield-in-php-7e62e2480b8d
* @see https://3v4l.org/5PJid
*/
final class YieldClassMethodToArrayClassMethodRector extends AbstractRector
{
/**
* @var string[]
* @var string[][]
*/
private $methodsByType = [];
@ -28,7 +29,7 @@ final class YieldClassMethodToArrayClassMethodRector extends AbstractRector
private $nodeTransformer;
/**
* @param string[] $methodsByType
* @param string[][] $methodsByType
*/
public function __construct(array $methodsByType, NodeTransformer $nodeTransformer)
{
@ -55,9 +56,7 @@ class SomeEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
['event' => 'callback']
];
return ['event' => 'callback'];
}
}
CODE_SAMPLE
@ -115,6 +114,10 @@ CODE_SAMPLE
{
$yieldNodes = [];
if ($classMethodNode->stmts === null) {
return [];
}
foreach ($classMethodNode->stmts as $statement) {
if (! $statement instanceof Expression) {
continue;

View File

@ -0,0 +1,47 @@
<?php
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Fixture;
use Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Source\ParentTestCase;
class DataProvider extends ParentTestCase
{
public static function provideData()
{
return [
['<?php implode("", $foo, );', '<?php implode($foo, "", );']
];
}
public static function dataProvider()
{
return [
['<?php implode(\'\', $foo, );', '<?php implode($foo, );'],
['<?php implode(\'\', $foo, );', '<?php implode($foo, );']
];
}
}
?>
-----
<?php
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Fixture;
use Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Source\ParentTestCase;
class DataProvider extends ParentTestCase
{
public static function provideData()
{
yield ['<?php implode("", $foo, );', '<?php implode($foo, "", );'];
}
public static function dataProvider()
{
yield ['<?php implode(\'\', $foo, );', '<?php implode($foo, );'];
yield ['<?php implode(\'\', $foo, );', '<?php implode($foo, );'];
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Fixture;
use Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Source\EventSubscriberInterface;
class SomeEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return ['event' => 'callback'];
}
}
?>
-----
<?php
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Fixture;
use Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Source\EventSubscriberInterface;
class SomeEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
yield 'event' => 'callback';
}
}
?>

View File

@ -0,0 +1,36 @@
<?php declare(strict_types=1);
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector;
use Rector\CodingStyle\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector;
use Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Source\EventSubscriberInterface;
use Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Source\ParentTestCase;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class ReturnArrayClassMethodToYieldRectorTest extends AbstractRectorTestCase
{
public function test(): void
{
$this->doTestFiles([
__DIR__ . '/Fixture/fixture.php.inc',
// @see https://github.com/FriendsOfPHP/PHP-CS-Fixer/commit/53fbbf01ca960f10c88acd0a38689c57bf3ade78
__DIR__ . '/Fixture/data_provider.php.inc',
]);
}
protected function getRectorClass(): string
{
return ReturnArrayClassMethodToYieldRector::class;
}
/**
* @return string[]
*/
protected function getRectorConfiguration(): ?array
{
return [
EventSubscriberInterface::class => ['getSubscribedEvents'],
ParentTestCase::class => ['#(provide|dataProvider)*#'],
];
}
}

View File

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Source;
interface EventSubscriberInterface
{
}

View File

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector\Source;
class ParentTestCase
{
}