Skip to content

Commit

Permalink
[CodeQuality] Add FuncGetArgsToVariadicParamRector (#6318)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed May 3, 2021
1 parent 2e6d188 commit 21bf53f
Show file tree
Hide file tree
Showing 15 changed files with 486 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/code_analysis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
actions:
-
name: 'Composer Validate'
run: composer validate --strict --ansi
run: composer validate --ansi

-
name: 'Validate Max File Length'
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/packages_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ jobs:
with:
php-version: 7.3
coverage: none
-
run: composer require nikic/php-parser:4.10.4 --no-update

-
run: composer install --ansi

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"nette/caching": "^3.1",
"nette/robot-loader": "^3.4",
"nette/utils": "^3.2",
"nikic/php-parser": "^4.10.4",
"nikic/php-parser": "4.10.4",
"phpstan/phpdoc-parser": "^0.5.4",
"phpstan/phpstan": "^0.12.83",
"phpstan/phpstan-phpunit": "^0.12.18",
Expand Down
1 change: 1 addition & 0 deletions config/set/code-quality.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,5 @@
$services->set(SingularSwitchToIfRector::class);
$services->set(SimplifyIfNullableReturnRector::class);
$services->set(NarrowUnionTypeDocRector::class);
$services->set(\Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector::class);
};
238 changes: 238 additions & 0 deletions preload.php

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector\Fixture;

function skip_already_param($someParam)
{
$args = \func_get_args();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector\Fixture;

final class SomePropertyAssign
{
public function run()
{
$this->someProperty = \func_get_args();
}
}

?>
-----
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector\Fixture;

final class SomePropertyAssign
{
public function run(...$args)
{
$this->someProperty = $args;
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector\Fixture;

function run()
{
$args = \func_get_args();
}

?>
-----
<?php

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector\Fixture;

function run(...$args)
{
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;

final class FuncGetArgsToVariadicParamRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}

/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

use Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(FuncGetArgsToVariadicParamRector::class);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Rector\Tests\DowngradePhp71\Rector\String_\DowngradeNegativeStringOffsetToStrlenRector\Fixture;

class Variable
final class SomeVariable
{
public function run(string $var)
{
Expand All @@ -16,7 +16,7 @@ class Variable

namespace Rector\Tests\DowngradePhp71\Rector\String_\DowngradeNegativeStringOffsetToStrlenRector\Fixture;

class Variable
final class SomeVariable
{
public function run(string $var)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Rector\Tests\LeagueEvent\Rector\MethodCall\DispatchStringToObjectRector\Fixture;

class Variable
final class SomeVariable
{
/** @var \League\Event\EventDispatcher */
private $dispatcher;
Expand All @@ -20,7 +20,7 @@ class Variable

namespace Rector\Tests\LeagueEvent\Rector\MethodCall\DispatchStringToObjectRector\Fixture;

class Variable
final class SomeVariable
{
/** @var \League\Event\EventDispatcher */
private $dispatcher;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

declare(strict_types=1);

namespace Rector\CodingStyle\Rector\ClassMethod;

use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @changelog https://3v4l.org/d4tBd
*
* @see \Rector\Tests\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector\FuncGetArgsToVariadicParamRectorTest
*/
final class FuncGetArgsToVariadicParamRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Refactor func_get_args() in to a variadic param', [
new CodeSample(
<<<'CODE_SAMPLE'
function run()
{
$args = \func_get_args();
}
CODE_SAMPLE

,
<<<'CODE_SAMPLE'
function run(...$args)
{
}
CODE_SAMPLE

),
]);
}

/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [ClassMethod::class, Function_::class];
}

/**
* @param ClassMethod|Function_ $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isAtLeastPhpVersion(PhpVersionFeature::VARIADIC_PARAM)) {
return null;
}

if ($node->params !== []) {
return null;
}

$assign = $this->matchFuncGetArgsVariableAssign($node);
if (! $assign instanceof Assign) {
return null;
}

if ($assign->var instanceof Variable) {
$variableName = $this->getName($assign->var);
if ($variableName === null) {
return null;
}

$this->removeNode($assign);
} else {
$variableName = 'args';
$assign->expr = new Variable('args');
}

$node->params[] = $this->createVariadicParam($variableName);

return $node;
}

/**
* @param ClassMethod|Function_ $functionLike
*/
private function matchFuncGetArgsVariableAssign(FunctionLike $functionLike): ?Assign
{
/** @var Assign[] $assigns */
$assigns = $this->betterNodeFinder->findInstanceOf((array) $functionLike->stmts, Assign::class);

foreach ($assigns as $assign) {
if (! $assign->expr instanceof FuncCall) {
continue;
}

if (! $this->isName($assign->expr, 'func_get_args')) {
continue;
}

return $assign;
}

return null;
}

private function createVariadicParam(string $variableName): Param
{
$variable = new Variable($variableName);
return new Param($variable, null, null, false, true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Scalar\String_;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

Expand Down Expand Up @@ -65,6 +66,10 @@ public function getNodeTypes(): array
*/
public function refactor(Node $node): ?Node
{
if (! $this->isAtLeastPhpVersion(PhpVersionFeature::ARRAY_SPREAD)) {
return null;
}

if (! $this->isName($node, 'call_user_func_array')) {
return null;
}
Expand All @@ -88,7 +93,7 @@ public function refactor(Node $node): ?Node
private function createFuncCall(Expr $expr, string $functionName): FuncCall
{
$args = [];
$args[] = new Arg($expr, false, true);
$args[] = $this->createUnpackedArg($expr);

return $this->nodeFactory->createFuncCall($functionName, $args);
}
Expand Down Expand Up @@ -118,9 +123,15 @@ private function createMethodCall(Array_ $array, Expr $secondExpr): ?MethodCall
$string = $secondItem->value;
$methodName = $string->value;

return new MethodCall($firstItem->value, $methodName, [new Arg($secondExpr, false, true)]);
$arg = $this->createUnpackedArg($secondExpr);
return new MethodCall($firstItem->value, $methodName, [$arg]);
}

return null;
}

private function createUnpackedArg(Expr $expr): Arg
{
return new Arg($expr, false, true);
}
}
6 changes: 6 additions & 0 deletions src/ValueObject/PhpVersionFeature.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,10 @@ final class PhpVersionFeature
* @var int
*/
public const NEVER_TYPE = PhpVersion::PHP_81;

/**
* @see https://wiki.php.net/rfc/variadics
* @var int
*/
public const VARIADIC_PARAM = PhpVersion::PHP_56;
}

0 comments on commit 21bf53f

Please sign in to comment.