mirror of
https://github.com/rectorphp/rector.git
synced 2025-04-21 07:52:01 +02:00
[Polyfill] Add UnwrapFutureCompatibleIfRector
This commit is contained in:
parent
84e1e98a51
commit
a37a7d1dad
@ -105,7 +105,8 @@
|
||||
"Rector\\PhpDeglobalize\\": "packages/PhpDeglobalize/src",
|
||||
"Rector\\Phalcon\\": "packages/Phalcon/src",
|
||||
"Rector\\DoctrineGedmoToKnplabs\\": "packages/DoctrineGedmoToKnplabs/src",
|
||||
"Rector\\MinimalScope\\": "packages/MinimalScope/src"
|
||||
"Rector\\MinimalScope\\": "packages/MinimalScope/src",
|
||||
"Rector\\Polyfill\\": "packages/Polyfill/src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
@ -166,7 +167,8 @@
|
||||
"Rector\\PhpDeglobalize\\Tests\\": "packages/PhpDeglobalize/tests",
|
||||
"Rector\\Phalcon\\Tests\\": "packages/Phalcon/tests",
|
||||
"Rector\\DoctrineGedmoToKnplabs\\Tests\\": "packages/DoctrineGedmoToKnplabs/tests",
|
||||
"Rector\\MinimalScope\\Tests\\": "packages/MinimalScope/tests"
|
||||
"Rector\\MinimalScope\\Tests\\": "packages/MinimalScope/tests",
|
||||
"Rector\\Polyfill\\Tests\\": "packages/Polyfill/tests"
|
||||
},
|
||||
"classmap": [
|
||||
"packages/Symfony/tests/Rector/FrameworkBundle/AbstractToConstructorInjectionRectorSource",
|
||||
|
2
config/set/polyfill/unwrap-compat.yaml
Normal file
2
config/set/polyfill/unwrap-compat.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\Polyfill\Rector\If_\UnwrapFutureCompatibleIfRector: null
|
9
packages/Polyfill/config/config.yaml
Normal file
9
packages/Polyfill/config/config.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
services:
|
||||
_defaults:
|
||||
public: true
|
||||
autowire: true
|
||||
|
||||
Rector\Polyfill\:
|
||||
resource: '../src'
|
||||
exclude:
|
||||
- '../src/Rector/**/*Rector.php'
|
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Polyfill\FeatureSupport;
|
||||
|
||||
use Rector\Php\PhpVersionProvider;
|
||||
|
||||
final class FunctionSupportResolver
|
||||
{
|
||||
/**
|
||||
* @var string[][]
|
||||
*/
|
||||
private const FUNCTIONS_BY_VERSION = [
|
||||
'5.6' => ['session_abort'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @var PhpVersionProvider
|
||||
*/
|
||||
private $phpVersionProvider;
|
||||
|
||||
public function __construct(PhpVersionProvider $phpVersionProvider)
|
||||
{
|
||||
$this->phpVersionProvider = $phpVersionProvider;
|
||||
}
|
||||
|
||||
public function isFunctionSupported(string $desiredFunction): bool
|
||||
{
|
||||
foreach (self::FUNCTIONS_BY_VERSION as $version => $functions) {
|
||||
foreach ($functions as $function) {
|
||||
if ($desiredFunction !== $function) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->phpVersionProvider->isAtLeast($version)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Polyfill\Rector\If_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use Rector\PhpParser\Node\Manipulator\IfManipulator;
|
||||
use Rector\Polyfill\FeatureSupport\FunctionSupportResolver;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\Polyfill\Tests\Rector\If_\UnwrapFutureCompatibleIfRector\UnwrapFutureCompatibleIfRectorTest
|
||||
*/
|
||||
final class UnwrapFutureCompatibleIfRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var IfManipulator
|
||||
*/
|
||||
private $ifManipulator;
|
||||
|
||||
/**
|
||||
* @var FunctionSupportResolver
|
||||
*/
|
||||
private $functionSupportResolver;
|
||||
|
||||
public function __construct(IfManipulator $ifManipulator, FunctionSupportResolver $functionSupportResolver)
|
||||
{
|
||||
$this->ifManipulator = $ifManipulator;
|
||||
$this->functionSupportResolver = $functionSupportResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Remove functions exists if with else for always existing', [
|
||||
new CodeSample(
|
||||
<<<'PHP'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
// session locking trough other addons
|
||||
if (function_exists('session_abort')) {
|
||||
session_abort();
|
||||
} else {
|
||||
session_write_close();
|
||||
}
|
||||
}
|
||||
}
|
||||
PHP
|
||||
,
|
||||
<<<'PHP'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
// session locking trough other addons
|
||||
session_abort();
|
||||
}
|
||||
}
|
||||
PHP
|
||||
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [If_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param If_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$match = $this->ifManipulator->isIfElseWithFunctionCondition($node, 'function_exists');
|
||||
if ($match === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var Node\Expr\FuncCall $funcCall */
|
||||
$funcCall = $node->cond;
|
||||
|
||||
$functionToExistName = $this->getValue($funcCall->args[0]->value);
|
||||
if (! is_string($functionToExistName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->functionSupportResolver->isFunctionSupported($functionToExistName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($node->stmts as $key => $ifStmt) {
|
||||
if ($key === 0) {
|
||||
// move comment from if to first element to keep it
|
||||
$ifStmt->setAttribute('comments', $node->getComments());
|
||||
}
|
||||
|
||||
$this->addNodeAfterNode($ifStmt, $node);
|
||||
}
|
||||
|
||||
$this->removeNode($node);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Polyfill\Tests\Rector\If_\UnwrapFutureCompatibleIfRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
// session locking trough other addons
|
||||
if (function_exists('session_abort')) {
|
||||
session_abort();
|
||||
} else {
|
||||
session_write_close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Polyfill\Tests\Rector\If_\UnwrapFutureCompatibleIfRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
// session locking trough other addons
|
||||
session_abort();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Polyfill\Tests\Rector\If_\UnwrapFutureCompatibleIfRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Polyfill\Rector\If_\UnwrapFutureCompatibleIfRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class UnwrapFutureCompatibleIfRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideDataForTest()
|
||||
*/
|
||||
public function test(string $file): void
|
||||
{
|
||||
$this->doTestFile($file);
|
||||
}
|
||||
|
||||
public function provideDataForTest(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return UnwrapFutureCompatibleIfRector::class;
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\BinaryOp\Identical;
|
||||
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Continue_;
|
||||
use PhpParser\Node\Stmt\Do_;
|
||||
@ -18,6 +19,7 @@ use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\Node\Stmt\Throw_;
|
||||
use PhpParser\Node\Stmt\While_;
|
||||
use PhpParser\NodeTraverser;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
use Rector\PhpParser\NodeTraverser\CallableNodeTraverser;
|
||||
use Rector\PhpParser\Printer\BetterStandardPrinter;
|
||||
|
||||
@ -53,16 +55,23 @@ final class IfManipulator
|
||||
*/
|
||||
private $stmtsManipulator;
|
||||
|
||||
/**
|
||||
* @var NameResolver
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
public function __construct(
|
||||
BetterStandardPrinter $betterStandardPrinter,
|
||||
ConstFetchManipulator $constFetchManipulator,
|
||||
CallableNodeTraverser $callableNodeTraverser,
|
||||
StmtsManipulator $stmtsManipulator
|
||||
StmtsManipulator $stmtsManipulator,
|
||||
NameResolver $nameResolver
|
||||
) {
|
||||
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||
$this->constFetchManipulator = $constFetchManipulator;
|
||||
$this->callableNodeTraverser = $callableNodeTraverser;
|
||||
$this->stmtsManipulator = $stmtsManipulator;
|
||||
$this->nameResolver = $nameResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -233,6 +242,29 @@ final class IfManipulator
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches:
|
||||
* if (<some_function>) {
|
||||
* } else {
|
||||
* }
|
||||
*/
|
||||
public function isIfElseWithFunctionCondition(If_ $if, string $functionName): bool
|
||||
{
|
||||
if (! $this->isIfWithElse($if)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $if->cond instanceof FuncCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->nameResolver->isName($if->cond, $functionName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function matchComparedAndReturnedNode(NotIdentical $notIdentical, Return_ $returnNode): ?Expr
|
||||
{
|
||||
if ($this->betterStandardPrinter->areNodesEqual($notIdentical->left, $returnNode->expr)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user