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