mirror of
https://github.com/rectorphp/rector.git
synced 2025-02-25 04:03:55 +01:00
Merge pull request #2409 from rectorphp/phalcon-round-2
[Phalcon 4] Add SwapClassMethodArgumentsRector rule
This commit is contained in:
commit
25a5cb0620
@ -1,5 +1,11 @@
|
||||
# https://docs.phalcon.io/4.0/en/upgrade#general-notes
|
||||
services:
|
||||
# !!! be careful not to run this twice, since it swaps arguments back and forth
|
||||
# see https://github.com/rectorphp/rector/issues/2408#issue-534441142
|
||||
Rector\Rector\StaticCall\SwapClassMethodArgumentsRector:
|
||||
Phalcon\Model:
|
||||
assign: [0, 2, 1]
|
||||
|
||||
Rector\Renaming\Rector\Class_\RenameClassRector:
|
||||
Phalcon\Acl\Adapter: 'Phalcon\Acl\Adapter\AbstractAdapter'
|
||||
Phalcon\Acl\Resource: 'Phalcon\Acl\Component'
|
||||
|
@ -20,6 +20,7 @@ use Rector\RectorDefinition\RectorDefinition;
|
||||
final class AddPregQuoteDelimiterRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @see https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
|
||||
*/
|
||||
private const ALL_MODIFIERS = 'imsxeADSUXJu';
|
||||
|
@ -230,3 +230,7 @@ parameters:
|
||||
# mixed removed
|
||||
- '#In method "(.*?)", parameter (.*?) has no type\-hint and no @param annotation\. More info\: http\://bit\.ly/usetypehint#'
|
||||
- '#In method "(.*?)", there is no return type and no @return annotation\. More info\: http\://bit\.ly/usetypehint#'
|
||||
|
||||
-
|
||||
message: '#Class Rector\\Tests\\Rector\\StaticCall\\SwapClassMethodArgumentsRector\\Fixture\\SomeClass not found#'
|
||||
path: tests/Rector/StaticCall/SwapClassMethodArgumentsRector/SwapClassMethodArgumentsRectorTest.php
|
||||
|
38
rector.yaml
38
rector.yaml
@ -13,6 +13,40 @@ parameters:
|
||||
# so Rector code is still PHP 7.1 compatible
|
||||
php_version_features: '7.1'
|
||||
|
||||
|
||||
# @see utils/RectorGenerator/config/config.yaml
|
||||
rector_recipe:
|
||||
package: "Utils"
|
||||
# run "bin/rector create" to create a new Rector + tests from this config
|
||||
package: "Rector"
|
||||
name: "SwapClassMethodArgumentsRector"
|
||||
node_types:
|
||||
# put main node first, it is used to create namespace
|
||||
- "StaticCall"
|
||||
- "MethodCall"
|
||||
- "ClassMethod"
|
||||
|
||||
description: "Reorder class method arguments, including their calls"
|
||||
code_before: >
|
||||
<?php
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public static function run($first, $second)
|
||||
{
|
||||
self::run($first, $second);
|
||||
}
|
||||
}
|
||||
|
||||
code_after: >
|
||||
<?php
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public static function run($second, $first)
|
||||
{
|
||||
self::run($second, $first);
|
||||
}
|
||||
}
|
||||
|
||||
source: # e.g. link to RFC or headline in upgrade guide, 1 or more in the list
|
||||
- ""
|
||||
set: "" # e.g. symfony30, target config to append this rector to
|
||||
|
161
src/Rector/StaticCall/SwapClassMethodArgumentsRector.php
Normal file
161
src/Rector/StaticCall/SwapClassMethodArgumentsRector.php
Normal file
@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Rector\StaticCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\ConfiguredCodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\Rector\StaticCall\SwapClassMethodArgumentsRector\SwapClassMethodArgumentsRectorTest
|
||||
*/
|
||||
final class SwapClassMethodArgumentsRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var int[][][]
|
||||
*/
|
||||
private $newArgumentPositionsByMethodAndClass = [];
|
||||
|
||||
/**
|
||||
* @param int[][][] $newArgumentPositionsByMethodAndClass
|
||||
*/
|
||||
public function __construct(array $newArgumentPositionsByMethodAndClass = [])
|
||||
{
|
||||
$this->newArgumentPositionsByMethodAndClass = $newArgumentPositionsByMethodAndClass;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Reorder class method arguments, including their calls', [
|
||||
new ConfiguredCodeSample(
|
||||
<<<'PHP'
|
||||
class SomeClass
|
||||
{
|
||||
public static function run($first, $second)
|
||||
{
|
||||
self::run($first, $second);
|
||||
}
|
||||
}
|
||||
PHP
|
||||
,
|
||||
<<<'PHP'
|
||||
class SomeClass
|
||||
{
|
||||
public static function run($second, $first)
|
||||
{
|
||||
self::run($second, $first);
|
||||
}
|
||||
}
|
||||
PHP
|
||||
|
||||
,
|
||||
[
|
||||
'$newArgumentPositionsByMethodAndClass' => [
|
||||
'SomeClass' => [
|
||||
'run' => [1, 0],
|
||||
],
|
||||
],
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [StaticCall::class, MethodCall::class, ClassMethod::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StaticCall|MethodCall|ClassMethod $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
foreach ($this->newArgumentPositionsByMethodAndClass as $class => $methodNameAndNewArgumentPositions) {
|
||||
if (! $this->isMethodStaticCallOrClassMethodObjectType($node, $class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($methodNameAndNewArgumentPositions as $methodName => $newArgumentPositions) {
|
||||
if (! $this->isMethodStaticCallOrClassMethodName($node, $methodName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($node instanceof ClassMethod) {
|
||||
$this->swapParameters($node, $newArgumentPositions);
|
||||
} else {
|
||||
$this->swapArguments($node, $newArgumentPositions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StaticCall|MethodCall|ClassMethod $node
|
||||
*/
|
||||
private function isMethodStaticCallOrClassMethodName(Node $node, string $methodName): bool
|
||||
{
|
||||
if ($node instanceof MethodCall || $node instanceof StaticCall) {
|
||||
if ($node->name instanceof Expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isName($node->name, $methodName);
|
||||
}
|
||||
|
||||
if ($node instanceof ClassMethod) {
|
||||
return $this->isName($node->name, $methodName);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MethodCall|StaticCall $node
|
||||
* @param int[] $newArgumentPositions
|
||||
*/
|
||||
private function swapArguments(Node $node, array $newArgumentPositions): void
|
||||
{
|
||||
$newArguments = [];
|
||||
foreach ($newArgumentPositions as $oldPosition => $newPosition) {
|
||||
if (! isset($node->args[$oldPosition]) || ! isset($node->args[$newPosition])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newArguments[$newPosition] = $node->args[$oldPosition];
|
||||
}
|
||||
|
||||
foreach ($newArguments as $newPosition => $argument) {
|
||||
$node->args[$newPosition] = $argument;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $newParameterPositions
|
||||
*/
|
||||
private function swapParameters(ClassMethod $classMethod, array $newParameterPositions): void
|
||||
{
|
||||
$newArguments = [];
|
||||
foreach ($newParameterPositions as $oldPosition => $newPosition) {
|
||||
if (! isset($classMethod->params[$oldPosition]) || ! isset($classMethod->params[$newPosition])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newArguments[$newPosition] = $classMethod->params[$oldPosition];
|
||||
}
|
||||
|
||||
foreach ($newArguments as $newPosition => $argument) {
|
||||
$classMethod->params[$newPosition] = $argument;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\Rector\StaticCall\SwapClassMethodArgumentsRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public static function run($first, $second)
|
||||
{
|
||||
self::run($first, $second);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\Rector\StaticCall\SwapClassMethodArgumentsRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public static function run($second, $first)
|
||||
{
|
||||
self::run($second, $first);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Rector\StaticCall\SwapClassMethodArgumentsRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Rector\StaticCall\SwapClassMethodArgumentsRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\Tests\Rector\StaticCall\SwapClassMethodArgumentsRector\Fixture\SomeClass;
|
||||
|
||||
final class SwapClassMethodArgumentsRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideDataForTest()
|
||||
*/
|
||||
public function test(string $file): void
|
||||
{
|
||||
$this->doTestFile($file);
|
||||
}
|
||||
|
||||
public function provideDataForTest(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorsWithConfiguration(): array
|
||||
{
|
||||
return [
|
||||
SwapClassMethodArgumentsRector::class => [
|
||||
'newArgumentPositionsByMethodAndClass' => [
|
||||
SomeClass::class => [
|
||||
'run' => [1, 0],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
@ -12,35 +12,35 @@ services:
|
||||
|
||||
parameters:
|
||||
rector_recipe:
|
||||
# run "bin/rector create" to create a new Rector + tests from this config
|
||||
package: "Celebrity"
|
||||
name: "SplitToExplodeRector"
|
||||
node_types:
|
||||
# put main node first, it is used to create namespace
|
||||
- "Assign"
|
||||
|
||||
description: "Removes unneeded $a = $a assigns"
|
||||
code_before: >
|
||||
<?php
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$a = $a;
|
||||
}
|
||||
}
|
||||
|
||||
code_after: >
|
||||
<?php
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
source: # e.g. link to RFC or headline in upgrade guide, 1 or more in the list
|
||||
- ""
|
||||
set: "" # e.g. symfony30, target config to append this rector to
|
||||
# # run "bin/rector create" to create a new Rector + tests from this config
|
||||
# package: "Celebrity"
|
||||
# name: "SplitToExplodeRector"
|
||||
# node_types:
|
||||
# # put main node first, it is used to create namespace
|
||||
# - ""
|
||||
#
|
||||
# description: "Removes unneeded $a = $a assigns"
|
||||
# code_before: >
|
||||
# <?php
|
||||
#
|
||||
# class SomeClass
|
||||
# {
|
||||
# public function run()
|
||||
# {
|
||||
# $a = $a;
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# code_after: >
|
||||
# <?php
|
||||
#
|
||||
# class SomeClass
|
||||
# {
|
||||
# public function run()
|
||||
# {
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# source: # e.g. link to RFC or headline in upgrade guide, 1 or more in the list
|
||||
# - ""
|
||||
# set: "" # e.g. symfony30, target config to append this rector to
|
||||
|
Loading…
x
Reference in New Issue
Block a user