From 2f9deae3d31aaf62f34b69dc97188b8aae15ed12 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 3 May 2021 20:58:34 +0200 Subject: [PATCH 1/3] [CodeQuality] Add FuncGetArgsToVariadicParamRector --- config/set/code-quality.php | 1 + .../Fixture/skip_already_param.php.inc | 8 ++ .../Fixture/skip_property_assign.php.inc | 27 ++++ .../Fixture/some_class.php.inc | 20 +++ .../FuncGetArgsToVariadicParamRectorTest.php | 30 +++++ .../config/configured_rule.php | 11 ++ .../Fixture/variable.php.inc | 4 +- .../Fixture/variable.php.inc | 4 +- .../FuncGetArgsToVariadicParamRector.php | 119 ++++++++++++++++++ .../CallUserFuncCallToVariadicRector.php | 15 ++- src/ValueObject/PhpVersionFeature.php | 6 + 11 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/Fixture/skip_already_param.php.inc create mode 100644 rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/Fixture/skip_property_assign.php.inc create mode 100644 rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/Fixture/some_class.php.inc create mode 100644 rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/FuncGetArgsToVariadicParamRectorTest.php create mode 100644 rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/config/configured_rule.php create mode 100644 rules/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector.php diff --git a/config/set/code-quality.php b/config/set/code-quality.php index a935ba54b62c..450bfdc5124f 100644 --- a/config/set/code-quality.php +++ b/config/set/code-quality.php @@ -171,4 +171,5 @@ $services->set(SingularSwitchToIfRector::class); $services->set(SimplifyIfNullableReturnRector::class); $services->set(NarrowUnionTypeDocRector::class); + $services->set(\Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector::class); }; diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/Fixture/skip_already_param.php.inc b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/Fixture/skip_already_param.php.inc new file mode 100644 index 000000000000..824f5cd8bfc5 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/Fixture/skip_already_param.php.inc @@ -0,0 +1,8 @@ +someProperty = \func_get_args(); + } +} + +?> +----- +someProperty = $args; + } +} + +?> diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/Fixture/some_class.php.inc b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/Fixture/some_class.php.inc new file mode 100644 index 000000000000..e447efee759c --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/Fixture/some_class.php.inc @@ -0,0 +1,20 @@ + +----- + diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/FuncGetArgsToVariadicParamRectorTest.php b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/FuncGetArgsToVariadicParamRectorTest.php new file mode 100644 index 000000000000..4e873988e395 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/FuncGetArgsToVariadicParamRectorTest.php @@ -0,0 +1,30 @@ +doTestFileInfo($fileInfo); + } + + public function provideData(): Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/config/configured_rule.php b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/config/configured_rule.php new file mode 100644 index 000000000000..93c3a0d0edb7 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/config/configured_rule.php @@ -0,0 +1,11 @@ +services(); + $services->set(FuncGetArgsToVariadicParamRector::class); +}; diff --git a/rules-tests/DowngradePhp71/Rector/String_/DowngradeNegativeStringOffsetToStrlenRector/Fixture/variable.php.inc b/rules-tests/DowngradePhp71/Rector/String_/DowngradeNegativeStringOffsetToStrlenRector/Fixture/variable.php.inc index 5685f88071ce..11b703f975bb 100644 --- a/rules-tests/DowngradePhp71/Rector/String_/DowngradeNegativeStringOffsetToStrlenRector/Fixture/variable.php.inc +++ b/rules-tests/DowngradePhp71/Rector/String_/DowngradeNegativeStringOffsetToStrlenRector/Fixture/variable.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\DowngradePhp71\Rector\String_\DowngradeNegativeStringOffsetToStrlenRector\Fixture; -class Variable +final class SomeVariable { public function run(string $var) { @@ -16,7 +16,7 @@ class Variable namespace Rector\Tests\DowngradePhp71\Rector\String_\DowngradeNegativeStringOffsetToStrlenRector\Fixture; -class Variable +final class SomeVariable { public function run(string $var) { diff --git a/rules-tests/LeagueEvent/Rector/MethodCall/DispatchStringToObjectRector/Fixture/variable.php.inc b/rules-tests/LeagueEvent/Rector/MethodCall/DispatchStringToObjectRector/Fixture/variable.php.inc index 09936d99499b..c4ce3dddf036 100644 --- a/rules-tests/LeagueEvent/Rector/MethodCall/DispatchStringToObjectRector/Fixture/variable.php.inc +++ b/rules-tests/LeagueEvent/Rector/MethodCall/DispatchStringToObjectRector/Fixture/variable.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\LeagueEvent\Rector\MethodCall\DispatchStringToObjectRector\Fixture; -class Variable +final class SomeVariable { /** @var \League\Event\EventDispatcher */ private $dispatcher; @@ -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; diff --git a/rules/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector.php b/rules/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector.php new file mode 100644 index 000000000000..9dff99ddb740 --- /dev/null +++ b/rules/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector.php @@ -0,0 +1,119 @@ +> + */ + 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 === null) { + 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(Node\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); + } +} diff --git a/rules/CodingStyle/Rector/FuncCall/CallUserFuncCallToVariadicRector.php b/rules/CodingStyle/Rector/FuncCall/CallUserFuncCallToVariadicRector.php index 2e0eab87e6c2..e2ee0dd0a612 100644 --- a/rules/CodingStyle/Rector/FuncCall/CallUserFuncCallToVariadicRector.php +++ b/rules/CodingStyle/Rector/FuncCall/CallUserFuncCallToVariadicRector.php @@ -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; @@ -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; } @@ -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); } @@ -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); + } } diff --git a/src/ValueObject/PhpVersionFeature.php b/src/ValueObject/PhpVersionFeature.php index cbaed078c60d..3c34538a4608 100644 --- a/src/ValueObject/PhpVersionFeature.php +++ b/src/ValueObject/PhpVersionFeature.php @@ -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; } From 6e40f67e041363eef7ae528e2f73bf5754e2bfd4 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 3 May 2021 22:08:38 +0200 Subject: [PATCH 2/3] lock php-parser to 4.10.4 for T_ENUM conflict --- .github/workflows/code_analysis.yaml | 2 +- composer.json | 2 +- .../FuncGetArgsToVariadicParamRectorTest.php | 3 +++ .../Rector/ClassMethod/FuncGetArgsToVariadicParamRector.php | 5 +++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index c47cef6580dc..d9f9474df3b7 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -15,7 +15,7 @@ jobs: actions: - name: 'Composer Validate' - run: composer validate --strict --ansi + run: composer validate --ansi - name: 'Validate Max File Length' diff --git a/composer.json b/composer.json index 530b3804c1ca..852a0b335ca1 100644 --- a/composer.json +++ b/composer.json @@ -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", diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/FuncGetArgsToVariadicParamRectorTest.php b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/FuncGetArgsToVariadicParamRectorTest.php index 4e873988e395..54da08e510d5 100644 --- a/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/FuncGetArgsToVariadicParamRectorTest.php +++ b/rules-tests/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector/FuncGetArgsToVariadicParamRectorTest.php @@ -18,6 +18,9 @@ public function test(SmartFileInfo $fileInfo): void $this->doTestFileInfo($fileInfo); } + /** + * @return Iterator + */ public function provideData(): Iterator { return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); diff --git a/rules/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector.php b/rules/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector.php index 9dff99ddb740..9aa7398dc4a5 100644 --- a/rules/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector.php +++ b/rules/CodingStyle/Rector/ClassMethod/FuncGetArgsToVariadicParamRector.php @@ -8,6 +8,7 @@ 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_; @@ -67,7 +68,7 @@ public function refactor(Node $node): ?Node } $assign = $this->matchFuncGetArgsVariableAssign($node); - if ($assign === null) { + if (! $assign instanceof Assign) { return null; } @@ -91,7 +92,7 @@ public function refactor(Node $node): ?Node /** * @param ClassMethod|Function_ $functionLike */ - private function matchFuncGetArgsVariableAssign(Node\FunctionLike $functionLike): ?Assign + private function matchFuncGetArgsVariableAssign(FunctionLike $functionLike): ?Assign { /** @var Assign[] $assigns */ $assigns = $this->betterNodeFinder->findInstanceOf((array) $functionLike->stmts, Assign::class); From 318a12c7b7cd846a6eacd4d55d0c87e8c480d196 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 3 May 2021 22:19:29 +0200 Subject: [PATCH 3/3] rebuild preload.php --- .github/workflows/packages_tests.yaml | 3 + preload.php | 238 ++++++++++++++++++++++++++ 2 files changed, 241 insertions(+) diff --git a/.github/workflows/packages_tests.yaml b/.github/workflows/packages_tests.yaml index 751b34feccbe..7461483033a1 100644 --- a/.github/workflows/packages_tests.yaml +++ b/.github/workflows/packages_tests.yaml @@ -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 diff --git a/preload.php b/preload.php index bebc37d8b72d..55adaca6d14c 100644 --- a/preload.php +++ b/preload.php @@ -1,3 +1,241 @@