Add ParseStrWithResultArgumentRector

This commit is contained in:
Tomas Votruba 2018-12-15 12:34:42 +01:00
parent f3398e3acb
commit e7e01659ef
5 changed files with 146 additions and 0 deletions

View File

@ -19,3 +19,4 @@ services:
Rector\Php\Rector\FunctionLike\ReturnScalarTypehintRector: ~
Rector\Php\Rector\FuncCall\GetClassOnNullRector: ~
Rector\Php\Rector\FuncCall\IsObjectOnIncompleteClassRector: ~
Rector\Php\Rector\FuncCall\ParseStrWithResultArgumentRector: ~

View File

@ -0,0 +1,93 @@
<?php declare(strict_types=1);
namespace Rector\Php\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Expression;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
/**
* @see https://3v4l.org/u5pes
* @see https://github.com/gueff/blogimus/commit/04086a10320595470efe446c7ddd90e602aa7228
* @see https://github.com/pxgamer/youtube-dl-php/commit/83cb32b8b36844f2e39f82a862a5ab73da77b608
*/
final class ParseStrWithResultArgumentRector extends AbstractRector
{
/**
* @var CallableNodeTraverser
*/
private $callableNodeTraverser;
public function __construct(CallableNodeTraverser $callableNodeTraverser)
{
$this->callableNodeTraverser = $callableNodeTraverser;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Use $result argument in parse_str() function', [
new CodeSample(
<<<'CODE_SAMPLE'
parse_str($this->query);
$data = get_defined_vars();
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
parse_str($this->query, $result);
$data = $result;
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [FuncCall::class];
}
/**
* @param FuncCall $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isName($node, 'parse_str')) {
return null;
}
if (isset($node->args[1])) {
return null;
}
$resultVariable = new Variable('result');
$node->args[1] = new Arg($resultVariable);
/** @var Expression $expression */
$expression = $node->getAttribute(Attribute::CURRENT_EXPRESSION);
// @todo maybe solve in generic way as attribute?
$nextExpression = $expression->getAttribute(Attribute::NEXT_NODE);
$this->callableNodeTraverser->traverseNodesWithCallable([$nextExpression], function (Node $node) use (
$resultVariable
) {
if ($node instanceof FuncCall) {
if ($this->isName($node, 'get_defined_vars')) {
return $resultVariable;
}
}
return null;
});
return $node;
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Rector\Php\Tests\Rector\FuncCall\ParseStrWithResultArgumentRector\Fixture;
class ParsingClass
{
public function run()
{
$query = 'bla';
parse_str($query);
$data = get_defined_vars();
}
}
?>
-----
<?php
namespace Rector\Php\Tests\Rector\FuncCall\ParseStrWithResultArgumentRector\Fixture;
class ParsingClass
{
public function run()
{
$query = 'bla';
parse_str($query, $result);
$data = $result;
}
}
?>

View File

@ -0,0 +1,19 @@
<?php declare(strict_types=1);
namespace Rector\Php\Tests\Rector\FuncCall\ParseStrWithResultArgumentRector;
use Rector\Php\Rector\FuncCall\ParseStrWithResultArgumentRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class ParseStrWithResultArgumentRectorTest extends AbstractRectorTestCase
{
public function test(): void
{
$this->doTestFiles([__DIR__ . '/Fixture/fixture.php.inc']);
}
protected function getRectorClass(): string
{
return ParseStrWithResultArgumentRector::class;
}
}

View File

@ -0,0 +1,2 @@
services:
Rector\Php\Rector\FuncCall\ParseStrWithResultArgumentRector: ~