Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CodeQuality] Add FuncGetArgsToVariadicParamRector #6318

Merged
merged 3 commits into from
May 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}