mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-18 22:08:00 +01:00
init IsIterableRector [ref #638]
This commit is contained in:
parent
6b87d9e545
commit
9e9f5e796f
2
config/level/php/php71.yml
Normal file
2
config/level/php/php71.yml
Normal file
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\Php\Rector\IsIterableRector: ~
|
2
config/level/php/php73.yml
Normal file
2
config/level/php/php73.yml
Normal file
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\Php\Rector\IsCountableRector: ~
|
2
packages/Php/config/config.yml
Normal file
2
packages/Php/config/config.yml
Normal file
@ -0,0 +1,2 @@
|
||||
imports:
|
||||
- { resource: 'services.yml' }
|
8
packages/Php/config/services.yml
Normal file
8
packages/Php/config/services.yml
Normal file
@ -0,0 +1,8 @@
|
||||
services:
|
||||
_defaults:
|
||||
public: true
|
||||
autowire: true
|
||||
|
||||
Rector\Php\:
|
||||
resource: '../src'
|
||||
exclude: '../src/{Rector/**/*Rector.php}'
|
74
packages/Php/src/DualCheckToAble.php
Normal file
74
packages/Php/src/DualCheckToAble.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php;
|
||||
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\BinaryOp\BooleanOr;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Instanceof_;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name;
|
||||
|
||||
final class DualCheckToAble
|
||||
{
|
||||
public function processBooleanOr(BooleanOr $booleanOrNode, string $type, string $newMethodName): ?FuncCall
|
||||
{
|
||||
$split = $this->splitToInstanceOfAndFuncCall($booleanOrNode);
|
||||
if ($split === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
[$instanceOfNode, $funcCallNode] = $split;
|
||||
|
||||
/** @var Instanceof_ $instanceOfNode */
|
||||
if ((string) $instanceOfNode->class !== $type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var FuncCall $funcCallNode */
|
||||
if ((string) $funcCallNode->name !== 'is_array') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// both use same var
|
||||
if (! $funcCallNode->args[0]->value instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var Variable $firstVarNode */
|
||||
$firstVarNode = $funcCallNode->args[0]->value;
|
||||
|
||||
if (! $instanceOfNode->expr instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var Variable $secondVarNode */
|
||||
$secondVarNode = $instanceOfNode->expr;
|
||||
|
||||
// are they same variables
|
||||
if ($firstVarNode->name !== $secondVarNode->name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$funcCallNode = new FuncCall(new Name($newMethodName));
|
||||
$funcCallNode->args[0] = new Arg($firstVarNode);
|
||||
|
||||
return $funcCallNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Instanceof_[]|FuncCall[]
|
||||
*/
|
||||
private function splitToInstanceOfAndFuncCall(BooleanOr $booleanOrNode): ?array
|
||||
{
|
||||
if ($booleanOrNode->left instanceof Instanceof_ && $booleanOrNode->right instanceof FuncCall) {
|
||||
return [$booleanOrNode->left, $booleanOrNode->right];
|
||||
}
|
||||
|
||||
if ($booleanOrNode->right instanceof Instanceof_ && $booleanOrNode->left instanceof FuncCall) {
|
||||
return [$booleanOrNode->right, $booleanOrNode->left];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
57
packages/Php/src/Rector/IsCountableRector.php
Normal file
57
packages/Php/src/Rector/IsCountableRector.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Rector;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\BinaryOp\BooleanOr;
|
||||
use Rector\Php\DualCheckToAble;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
final class IsCountableRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var DualCheckToAble
|
||||
*/
|
||||
private $dualCheckToAble;
|
||||
|
||||
public function __construct(DualCheckToAble $dualCheckToAble)
|
||||
{
|
||||
$this->dualCheckToAble = $dualCheckToAble;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
'Changes is_array + Countable check to is_countable',
|
||||
[
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
is_array($foo) || $foo instanceof Countable;
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
is_countable($foo);
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [BooleanOr::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BooleanOr $booleanOrNode
|
||||
*/
|
||||
public function refactor(Node $booleanOrNode): ?Node
|
||||
{
|
||||
return $this->dualCheckToAble->processBooleanOr($booleanOrNode, 'Countable', 'is_countable') ?: $booleanOrNode;
|
||||
}
|
||||
}
|
57
packages/Php/src/Rector/IsIterableRector.php
Normal file
57
packages/Php/src/Rector/IsIterableRector.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Rector;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\BinaryOp\BooleanOr;
|
||||
use Rector\Php\DualCheckToAble;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
final class IsIterableRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var DualCheckToAble
|
||||
*/
|
||||
private $dualCheckToAble;
|
||||
|
||||
public function __construct(DualCheckToAble $dualCheckToAble)
|
||||
{
|
||||
$this->dualCheckToAble = $dualCheckToAble;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
'Changes is_array + Traversable check to is_iterable',
|
||||
[
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
is_array($foo) || $foo instanceof Traversable;
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
is_iterable($foo);
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [BooleanOr::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BooleanOr $booleanOrNode
|
||||
*/
|
||||
public function refactor(Node $booleanOrNode): ?Node
|
||||
{
|
||||
return $this->dualCheckToAble->processBooleanOr($booleanOrNode, 'Traversable', 'is_iterable') ?: $booleanOrNode;
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
is_countable($foo);
|
@ -0,0 +1,30 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Tests\Rector\IsCountableRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
/**
|
||||
* @covers \Rector\Php\Rector\IsCountableRector
|
||||
*/
|
||||
final class IsCountableRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideWrongToFixedFiles()
|
||||
*/
|
||||
public function test(string $wrong, string $fixed): void
|
||||
{
|
||||
$this->doTestFileMatchesExpectedContent($wrong, $fixed);
|
||||
}
|
||||
|
||||
public function provideWrongToFixedFiles(): Iterator
|
||||
{
|
||||
yield [__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc'];
|
||||
}
|
||||
|
||||
protected function provideConfig(): string
|
||||
{
|
||||
return __DIR__ . '/config.yml';
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
is_array($foo) || $foo instanceof Countable;
|
2
packages/Php/tests/Rector/IsCountableRector/config.yml
Normal file
2
packages/Php/tests/Rector/IsCountableRector/config.yml
Normal file
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\Php\Rector\IsCountableRector: ~
|
@ -0,0 +1,9 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
is_iterable($foo);
|
||||
|
||||
is_string($foo) || $foo instanceof Traversable;
|
||||
|
||||
is_array($foo2) || $foo instanceof Traversable;
|
||||
|
||||
$foo2 || $foo instanceof Traversable;
|
@ -0,0 +1,30 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Tests\Rector\IsIterableRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
/**
|
||||
* @covers \Rector\Php\Rector\IsIterableRector
|
||||
*/
|
||||
final class IsIterableRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideWrongToFixedFiles()
|
||||
*/
|
||||
public function test(string $wrong, string $fixed): void
|
||||
{
|
||||
$this->doTestFileMatchesExpectedContent($wrong, $fixed);
|
||||
}
|
||||
|
||||
public function provideWrongToFixedFiles(): Iterator
|
||||
{
|
||||
yield [__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc'];
|
||||
}
|
||||
|
||||
protected function provideConfig(): string
|
||||
{
|
||||
return __DIR__ . '/config.yml';
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
is_array($foo) || $foo instanceof Traversable;
|
||||
|
||||
is_string($foo) || $foo instanceof Traversable;
|
||||
|
||||
is_array($foo2) || $foo instanceof Traversable;
|
||||
|
||||
$foo2 || $foo instanceof Traversable;
|
2
packages/Php/tests/Rector/IsIterableRector/config.yml
Normal file
2
packages/Php/tests/Rector/IsIterableRector/config.yml
Normal file
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\Php\Rector\IsIterableRector: ~
|
Loading…
x
Reference in New Issue
Block a user