From a43edd929cfe004a429ee873789b308832867cf1 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 16 Apr 2021 05:54:00 +0700 Subject: [PATCH] [Rector] Copy RemoveDefaultArgumentValueRector to utils/Rector --- rector.php | 2 +- tests/system/CommonFunctionsTest.php | 2 +- .../RemoveDefaultArgumentValueRector.php | 212 ++++++++++++++++++ 3 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 utils/Rector/RemoveDefaultArgumentValueRector.php diff --git a/rector.php b/rector.php index 47cd364fca45..f54dd11beb61 100644 --- a/rector.php +++ b/rector.php @@ -16,7 +16,7 @@ use Rector\Core\ValueObject\PhpVersion; use Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector; use Rector\DeadCode\Rector\Foreach_\RemoveUnusedForeachKeyRector; -use Rector\DeadCode\Rector\MethodCall\RemoveDefaultArgumentValueRector; +use Utils\Rector\RemoveDefaultArgumentValueRector; use Rector\DeadCode\Rector\Switch_\RemoveDuplicatedCaseInSwitchRector; use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; use Rector\EarlyReturn\Rector\If_\ChangeIfElseValueAssignToEarlyReturnRector; diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index a8e4d3b0abaf..0a92d5a01642 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -212,7 +212,7 @@ public function testInvisible() public function testInvisibleEncoded() { - $this->assertEquals('Javascript', remove_invisible_characters('Java%0cscript', true)); + $this->assertEquals('Javascript', remove_invisible_characters('Java%0cscript')); } public function testAppTimezone() diff --git a/utils/Rector/RemoveDefaultArgumentValueRector.php b/utils/Rector/RemoveDefaultArgumentValueRector.php new file mode 100644 index 000000000000..21b48b843956 --- /dev/null +++ b/utils/Rector/RemoveDefaultArgumentValueRector.php @@ -0,0 +1,212 @@ +callDefaultParamValuesResolver = $callDefaultParamValuesResolver; + $this->reflectionProvider = $reflectionProvider; + } + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition('Remove argument value, if it is the same as default value', [ + new CodeSample( + <<<'CODE_SAMPLE' +class SomeClass +{ + public function run() + { + $this->runWithDefault([]); + $card = self::runWithStaticDefault([]); + } + + public function runWithDefault($items = []) + { + return $items; + } + + public function runStaticWithDefault($cards = []) + { + return $cards; + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +class SomeClass +{ + public function run() + { + $this->runWithDefault(); + $card = self::runWithStaticDefault(); + } + + public function runWithDefault($items = []) + { + return $items; + } + + public function runStaticWithDefault($cards = []) + { + return $cards; + } +} +CODE_SAMPLE + ), + ]); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [ + MethodCall::class, + StaticCall::class, + FuncCall::class, + ]; + } + + /** + * @param MethodCall|StaticCall|FuncCall $node + */ + public function refactor(Node $node): ?Node + { + if ($this->shouldSkip($node)) + { + return null; + } + + $defaultValues = $this->callDefaultParamValuesResolver->resolveFromCall($node); + + $keysToRemove = $this->resolveKeysToRemove($node, $defaultValues); + if ($keysToRemove === []) + { + return null; + } + + foreach ($keysToRemove as $keyToRemove) + { + if (! isset($defaultValues[$keyToRemove])) + { + continue; + } + + $this->nodeRemover->removeArg($node, $keyToRemove); + } + + return $node; + } + + /** + * @param MethodCall|StaticCall|FuncCall $node + */ + private function shouldSkip(Node $node): bool + { + if ($node->args === []) + { + return true; + } + + if (! $node instanceof FuncCall) + { + return false; + } + + if (! $node->name instanceof Name) + { + return true; + } + + $functionName = $this->getName($node); + if ($functionName === null) + { + return false; + } + + $name = new Name($functionName); + if (! $this->reflectionProvider->hasFunction($name, null)) + { + return false; + } + + $reflectionFunction = $this->reflectionProvider->getFunction($name, null); + + // skip native functions, hard to analyze without stubs (stubs would make working with IDE non-practical) + return $reflectionFunction->isBuiltin(); + } + + /** + * @param StaticCall|MethodCall|FuncCall $node + * @param Expr[]|mixed[] $defaultValues + * @return int[] + */ + private function resolveKeysToRemove(Node $node, array $defaultValues): array + { + $keysToKeep = []; + + /** + * @var int $key +*/ + foreach ($node->args as $key => $arg) + { + if (! isset($defaultValues[$key])) + { + $keysToKeep[] = $key; + continue; + } + + if (! $this->nodeComparator->areNodesEqual($defaultValues[$key], $arg->value)) + { + $keysToKeep[] = $key; + } + } + + $lastKeyToKeep = end($keysToKeep); + $maxKey = count($node->args) - 1; + + if ($lastKeyToKeep === false) + { + return range(0, $maxKey); + } + + $startremove = $lastKeyToKeep + 1; + if ($maxKey < $startremove) + { + return []; + } + + return range($startremove, $maxKey); + } +}