rector/src/Rector/Argument/ArgumentRemoverRector.php

154 lines
4.4 KiB
PHP
Raw Normal View History

<?php declare(strict_types=1);
namespace Rector\Rector\Argument;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
2018-07-17 20:52:46 +00:00
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Configuration\Rector\ArgumentRemoverRecipe;
2018-08-14 11:43:32 +00:00
use Rector\NodeTypeResolver\Node\Attribute;
2018-08-01 19:52:44 +00:00
use Rector\RectorDefinition\ConfiguredCodeSample;
use Rector\RectorDefinition\RectorDefinition;
2018-08-01 19:52:44 +00:00
use SomeClass;
final class ArgumentRemoverRector extends AbstractArgumentRector
{
/**
* @var ArgumentRemoverRecipe[]
*/
2018-08-01 19:52:44 +00:00
private $recipes = [];
/**
* @var ArgumentRemoverRecipe[]
*/
2018-08-01 19:52:44 +00:00
private $activeRecipes = [];
/**
* @param mixed[] $argumentChangesByMethodAndType
*/
public function __construct(array $argumentChangesByMethodAndType)
{
foreach ($argumentChangesByMethodAndType as $configurationArray) {
2018-08-01 19:52:44 +00:00
$this->recipes[] = ArgumentRemoverRecipe::createFromArray($configurationArray);
}
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition(
'Removes defined arguments in defined methods and their calls.',
[
2018-08-01 19:52:44 +00:00
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
$someObject = new SomeClass;
$someObject->someMethod(true);
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$someObject = new SomeClass;
$someObject->someMethod();'
CODE_SAMPLE
2018-08-01 19:52:44 +00:00
,
[
'$argumentChangesByMethodAndType' => [
'class' => SomeClass::class,
'method' => 'someMethod',
'position' => 0,
'value' => 'true',
],
]
),
]
);
}
2018-08-14 22:12:41 +00:00
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class, StaticCall::class, ClassMethod::class];
}
/**
* @param MethodCall|StaticCall|ClassMethod $node
*/
2018-08-14 22:12:41 +00:00
public function refactor(Node $node): ?Node
{
$this->activeRecipes = $this->matchArgumentChanges($node);
2018-10-15 13:55:01 +00:00
if (! $this->activeRecipes) {
return null;
}
$argumentsOrParameters = $this->getNodeArgumentsOrParameters($node);
$argumentsOrParameters = $this->processArgumentNodes($argumentsOrParameters);
$this->setNodeArgumentsOrParameters($node, $argumentsOrParameters);
return $node;
}
/**
* @return ArgumentRemoverRecipe[]
*/
private function matchArgumentChanges(Node $node): array
{
$argumentReplacerRecipes = [];
2018-08-01 19:52:44 +00:00
foreach ($this->recipes as $argumentRemoverRecipe) {
if ($this->isNodeToRecipeMatch($node, $argumentRemoverRecipe)) {
$argumentReplacerRecipes[] = $argumentRemoverRecipe;
}
}
return $argumentReplacerRecipes;
}
/**
2018-07-17 20:52:46 +00:00
* @param Arg[]|Param[] $argumentNodes
* @return mixed[]
*/
private function processArgumentNodes(array $argumentNodes): array
{
2018-08-01 19:52:44 +00:00
foreach ($this->activeRecipes as $activeArgumentRemoverRecipe) {
$position = $activeArgumentRemoverRecipe->getPosition();
if ($activeArgumentRemoverRecipe->getValue() === null) {
unset($argumentNodes[$position]);
} elseif ($this->isArgumentValueMatch($argumentNodes[$position], $activeArgumentRemoverRecipe)) {
unset($argumentNodes[$position]);
}
}
return $argumentNodes;
}
2018-07-17 20:52:46 +00:00
/**
* @param Arg|Param $argOrParamNode
*/
private function isArgumentValueMatch($argOrParamNode, ArgumentRemoverRecipe $argumentRemoverRecipe): bool
{
2018-07-17 20:52:46 +00:00
// only argument specific value can be removed
if (! $argOrParamNode instanceof Arg) {
return false;
}
$valueNode = $argOrParamNode->value;
if ($valueNode instanceof ClassConstFetch) {
2018-08-14 11:43:32 +00:00
$valueNodeAsString = $valueNode->class->getAttribute(Attribute::RESOLVED_NAME)->toString()
. '::'
2018-07-25 11:06:07 +00:00
. (string) $valueNode->name;
if ($valueNodeAsString === $argumentRemoverRecipe->getValue()) {
return true;
}
}
return false;
}
}