mirror of
https://github.com/rectorphp/rector.git
synced 2024-07-30 21:30:23 +00:00
Add YieldClassMethodToArrayClassMethodRector
This commit is contained in:
parent
2b4696bb1a
commit
ca1588309b
@ -7,3 +7,6 @@ services:
|
||||
Rector\CodingStyle\Rector\FuncCall\ConsistentImplodeRector: ~
|
||||
Rector\CodingStyle\Rector\FuncCall\SetTypeToCastRector: ~
|
||||
Rector\CodingStyle\Rector\Use_\RemoveUnusedAliasRector: ~
|
||||
|
||||
# requires configuration
|
||||
# Rector\CodingStyle\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector: ~
|
||||
|
@ -0,0 +1,130 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Yield_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
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
|
||||
*/
|
||||
final class YieldClassMethodToArrayClassMethodRector 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;
|
||||
}
|
||||
|
||||
$yieldNodes = $this->collectYieldNodesFromClassMethod($node);
|
||||
if ($yieldNodes === []) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrayNode = $this->nodeTransformer->transformYieldsToArray($yieldNodes);
|
||||
$this->removeNodes($yieldNodes);
|
||||
|
||||
$returnExpression = new Return_($arrayNode);
|
||||
$node->stmts = array_merge($node->stmts, [$returnExpression]);
|
||||
}
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Yield_[]
|
||||
*/
|
||||
private function collectYieldNodesFromClassMethod(ClassMethod $classMethodNode): array
|
||||
{
|
||||
$yieldNodes = [];
|
||||
|
||||
foreach ($classMethodNode->stmts as $statement) {
|
||||
if (! $statement instanceof Expression) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($statement->expr instanceof Yield_) {
|
||||
$yieldNodes[] = $statement->expr;
|
||||
}
|
||||
}
|
||||
|
||||
return $yieldNodes;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector\Fixture;
|
||||
|
||||
use Rector\CodingStyle\Tests\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector\Source\EventSubscriberInterface;
|
||||
|
||||
class SomeEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
yield 'event' => 'callback';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector\Fixture;
|
||||
|
||||
use Rector\CodingStyle\Tests\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector\Source\EventSubscriberInterface;
|
||||
|
||||
class SomeEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return ['event' => 'callback'];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector\Source;
|
||||
|
||||
interface EventSubscriberInterface
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector;
|
||||
|
||||
use Rector\CodingStyle\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector;
|
||||
use Rector\CodingStyle\Tests\Rector\ClassMethod\YieldClassMethodToArrayClassMethodRector\Source\EventSubscriberInterface;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class YieldClassMethodToArrayClassMethodRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$this->doTestFiles([__DIR__ . '/Fixture/fixture.php.inc']);
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return YieldClassMethodToArrayClassMethodRector::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getRectorConfiguration(): ?array
|
||||
{
|
||||
return [
|
||||
EventSubscriberInterface::class => ['getSubscribedEvents'],
|
||||
];
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockAnalyzer;
|
||||
use Rector\PhpParser\Node\Maintainer\ClassMethodMaintainer;
|
||||
use Rector\PhpParser\NodeTransformer;
|
||||
use Rector\Rector\AbstractPHPUnitRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
@ -26,10 +27,19 @@ final class ArrayToYieldDataProviderRector extends AbstractPHPUnitRector
|
||||
*/
|
||||
private $nodeTransformer;
|
||||
|
||||
public function __construct(DocBlockAnalyzer $docBlockAnalyzer, NodeTransformer $nodeTransformer)
|
||||
{
|
||||
/**
|
||||
* @var ClassMethodMaintainer
|
||||
*/
|
||||
private $classMethodMaintainer;
|
||||
|
||||
public function __construct(
|
||||
DocBlockAnalyzer $docBlockAnalyzer,
|
||||
NodeTransformer $nodeTransformer,
|
||||
ClassMethodMaintainer $classMethodMaintainer
|
||||
) {
|
||||
$this->docBlockAnalyzer = $docBlockAnalyzer;
|
||||
$this->nodeTransformer = $nodeTransformer;
|
||||
$this->classMethodMaintainer = $classMethodMaintainer;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
@ -81,7 +91,7 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->hasClassMethodReturnArrayOfArrays($node)) {
|
||||
if (! $this->classMethodMaintainer->hasReturnArrayOfArrays($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -121,41 +131,4 @@ CODE_SAMPLE
|
||||
|
||||
return $this->isName($classMethodNode, '#^(provide|dataProvider)*#');
|
||||
}
|
||||
|
||||
private function hasClassMethodReturnArrayOfArrays(ClassMethod $classMethodNode): bool
|
||||
{
|
||||
$statements = $classMethodNode->stmts;
|
||||
if (! $statements) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($statements as $statement) {
|
||||
if (! $statement instanceof Return_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $statement->expr instanceof Array_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isArrayOfArrays($statement->expr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isArrayOfArrays(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Array_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($node->items as $arrayItem) {
|
||||
if (! $arrayItem->value instanceof Array_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,10 @@
|
||||
namespace Rector\PhpParser\Node\Maintainer;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\PhpParser\Printer\BetterStandardPrinter;
|
||||
@ -60,4 +62,41 @@ final class ClassMethodMaintainer
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasReturnArrayOfArrays(ClassMethod $classMethodNode): bool
|
||||
{
|
||||
$statements = $classMethodNode->stmts;
|
||||
if (! $statements) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($statements as $statement) {
|
||||
if (! $statement instanceof Return_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $statement->expr instanceof Array_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isArrayOfArrays($statement->expr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isArrayOfArrays(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Array_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($node->items as $arrayItem) {
|
||||
if (! $arrayItem->value instanceof Array_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -67,4 +67,14 @@ trait NodeCommandersTrait
|
||||
|
||||
$this->notifyNodeChangeFileInfo($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
*/
|
||||
protected function removeNodes(array $nodes): void
|
||||
{
|
||||
foreach ($nodes as $node) {
|
||||
$this->removeNode($node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user