2018-05-01 17:31:41 +00:00
|
|
|
<?php declare(strict_types=1);
|
|
|
|
|
2018-08-01 18:29:40 +00:00
|
|
|
namespace Rector\Rector\Argument;
|
2018-05-01 17:31:41 +00:00
|
|
|
|
|
|
|
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-08-14 09:35:18 +00:00
|
|
|
use Rector\NodeTypeResolver\Node\Attribute as RectorAttribute;
|
2018-08-01 19:52:44 +00:00
|
|
|
use Rector\RectorDefinition\ConfiguredCodeSample;
|
2018-05-01 17:31:41 +00:00
|
|
|
use Rector\RectorDefinition\RectorDefinition;
|
2018-08-01 19:52:44 +00:00
|
|
|
use SomeClass;
|
2018-05-01 17:31:41 +00:00
|
|
|
|
|
|
|
final class ArgumentRemoverRector extends AbstractArgumentRector
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var ArgumentRemoverRecipe[]
|
|
|
|
*/
|
2018-08-01 19:52:44 +00:00
|
|
|
private $recipes = [];
|
2018-05-01 17:31:41 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var ArgumentRemoverRecipe[]
|
|
|
|
*/
|
2018-08-01 19:52:44 +00:00
|
|
|
private $activeRecipes = [];
|
2018-05-01 17:31:41 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param mixed[] $argumentChangesByMethodAndType
|
|
|
|
*/
|
2018-07-18 12:56:04 +00:00
|
|
|
public function __construct(array $argumentChangesByMethodAndType)
|
|
|
|
{
|
|
|
|
foreach ($argumentChangesByMethodAndType as $configurationArray) {
|
2018-08-01 19:52:44 +00:00
|
|
|
$this->recipes[] = ArgumentRemoverRecipe::createFromArray($configurationArray);
|
2018-07-18 12:56:04 +00:00
|
|
|
}
|
2018-05-01 17:31:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getDefinition(): RectorDefinition
|
|
|
|
{
|
|
|
|
return new RectorDefinition(
|
2018-08-01 13:34:55 +00:00
|
|
|
'Removes defined arguments in defined methods and their calls.',
|
2018-05-01 17:31:41 +00:00
|
|
|
[
|
2018-08-01 19:52:44 +00:00
|
|
|
new ConfiguredCodeSample(
|
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-08-01 19:52:44 +00:00
|
|
|
,
|
|
|
|
[
|
|
|
|
'$argumentChangesByMethodAndType' => [
|
|
|
|
'class' => SomeClass::class,
|
|
|
|
'method' => 'someMethod',
|
|
|
|
'position' => 0,
|
|
|
|
'value' => 'true',
|
|
|
|
],
|
|
|
|
]
|
2018-05-01 17:31:41 +00:00
|
|
|
),
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function isCandidate(Node $node): bool
|
|
|
|
{
|
|
|
|
if (! $this->isValidInstance($node)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-08-01 19:52:44 +00:00
|
|
|
$this->activeRecipes = $this->matchArgumentChanges($node);
|
2018-05-01 17:31:41 +00:00
|
|
|
|
2018-08-01 19:52:44 +00:00
|
|
|
return (bool) $this->activeRecipes;
|
2018-05-01 17:31:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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 = [];
|
|
|
|
|
2018-08-01 19:52:44 +00:00
|
|
|
foreach ($this->recipes as $argumentRemoverRecipe) {
|
2018-05-01 17:31:41 +00:00
|
|
|
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
|
|
|
|
{
|
2018-08-01 19:52:44 +00:00
|
|
|
foreach ($this->activeRecipes as $activeArgumentRemoverRecipe) {
|
2018-05-01 17:31:41 +00:00
|
|
|
$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) {
|
2018-08-14 09:35:18 +00:00
|
|
|
$valueNodeAsString = $valueNode->class->getAttribute(RectorAttribute::RESOLVED_NAME)->toString()
|
2018-07-17 20:48:31 +00:00
|
|
|
. '::'
|
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
|
|
|
}
|