2019-10-13 05:59:52 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
2018-05-01 17:31:41 +00:00
|
|
|
|
2020-08-18 15:57:30 +00:00
|
|
|
namespace Rector\Generic\Rector\ClassMethod;
|
2018-05-01 17:31:41 +00:00
|
|
|
|
2018-07-17 21:47:21 +00:00
|
|
|
use Nette\Utils\Strings;
|
2018-05-01 17:31:41 +00:00
|
|
|
use PhpParser\BuilderHelpers;
|
|
|
|
use PhpParser\Node;
|
|
|
|
use PhpParser\Node\Arg;
|
|
|
|
use PhpParser\Node\Expr\MethodCall;
|
|
|
|
use PhpParser\Node\Expr\StaticCall;
|
|
|
|
use PhpParser\Node\Stmt\ClassMethod;
|
2020-07-29 23:39:41 +00:00
|
|
|
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
|
2020-02-06 21:48:18 +00:00
|
|
|
use Rector\Core\Rector\AbstractRector;
|
|
|
|
use Rector\Core\RectorDefinition\ConfiguredCodeSample;
|
|
|
|
use Rector\Core\RectorDefinition\RectorDefinition;
|
2020-09-12 21:19:08 +00:00
|
|
|
use Rector\Generic\ValueObject\ArgumentDefaultValueReplacer;
|
2020-08-25 22:21:41 +00:00
|
|
|
use Webmozart\Assert\Assert;
|
2018-05-01 17:31:41 +00:00
|
|
|
|
2019-09-03 09:11:45 +00:00
|
|
|
/**
|
2020-08-18 15:57:30 +00:00
|
|
|
* @see \Rector\Generic\Tests\Rector\ClassMethod\ArgumentDefaultValueReplacerRector\ArgumentDefaultValueReplacerRectorTest
|
2019-09-03 09:11:45 +00:00
|
|
|
*/
|
2020-07-29 23:39:41 +00:00
|
|
|
final class ArgumentDefaultValueReplacerRector extends AbstractRector implements ConfigurableRectorInterface
|
2018-05-01 17:31:41 +00:00
|
|
|
{
|
2020-07-29 23:39:41 +00:00
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
2020-08-25 22:21:41 +00:00
|
|
|
public const REPLACED_ARGUMENTS = 'replaced_arguments';
|
2020-07-29 23:39:41 +00:00
|
|
|
|
2020-05-06 21:39:33 +00:00
|
|
|
/**
|
2020-09-12 21:19:08 +00:00
|
|
|
* @var ArgumentDefaultValueReplacer[]
|
2018-10-31 11:53:59 +00:00
|
|
|
*/
|
2020-08-25 22:21:41 +00:00
|
|
|
private $replacedArguments = [];
|
2018-10-31 11:53:59 +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
|
|
|
'Replaces defined map of 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(
|
2019-09-18 06:14:35 +00:00
|
|
|
<<<'PHP'
|
2018-05-04 12:55:47 +00:00
|
|
|
$someObject = new SomeClass;
|
|
|
|
$someObject->someMethod(SomeClass::OLD_CONSTANT);
|
2019-09-18 06:14:35 +00:00
|
|
|
PHP
|
2018-05-04 12:55:47 +00:00
|
|
|
,
|
2019-09-18 06:14:35 +00:00
|
|
|
<<<'PHP'
|
2018-05-04 12:55:47 +00:00
|
|
|
$someObject = new SomeClass;
|
|
|
|
$someObject->someMethod(false);'
|
2019-09-18 06:14:35 +00:00
|
|
|
PHP
|
2018-08-01 19:52:44 +00:00
|
|
|
,
|
|
|
|
[
|
2020-08-25 22:21:41 +00:00
|
|
|
self::REPLACED_ARGUMENTS => [
|
2020-09-12 21:19:08 +00:00
|
|
|
new ArgumentDefaultValueReplacer(
|
2020-08-25 22:21:41 +00:00
|
|
|
'SomeExampleClass',
|
|
|
|
'someMethod',
|
|
|
|
0,
|
|
|
|
'SomeClass::OLD_CONSTANT',
|
|
|
|
'false'
|
|
|
|
),
|
2018-08-01 19:52:44 +00:00
|
|
|
],
|
|
|
|
]
|
2018-05-01 17:31:41 +00:00
|
|
|
),
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-08-14 22:12:41 +00:00
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getNodeTypes(): array
|
2018-05-01 17:31:41 +00:00
|
|
|
{
|
2018-08-14 21:33:39 +00:00
|
|
|
return [MethodCall::class, StaticCall::class, ClassMethod::class];
|
2018-05-01 17:31:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param MethodCall|StaticCall|ClassMethod $node
|
|
|
|
*/
|
2018-08-14 22:12:41 +00:00
|
|
|
public function refactor(Node $node): ?Node
|
2018-05-01 17:31:41 +00:00
|
|
|
{
|
2020-08-25 22:21:41 +00:00
|
|
|
foreach ($this->replacedArguments as $replacedArgument) {
|
|
|
|
if (! $this->isMethodStaticCallOrClassMethodObjectType($node, $replacedArgument->getClass())) {
|
2018-10-21 19:43:47 +00:00
|
|
|
continue;
|
|
|
|
}
|
2018-07-18 14:06:45 +00:00
|
|
|
|
2020-08-25 22:21:41 +00:00
|
|
|
if (! $this->isName($node->name, $replacedArgument->getMethod())) {
|
|
|
|
continue;
|
2018-10-21 19:43:47 +00:00
|
|
|
}
|
2020-08-25 22:21:41 +00:00
|
|
|
|
|
|
|
$this->processReplaces($node, $replacedArgument);
|
2018-10-21 19:43:47 +00:00
|
|
|
}
|
2018-05-01 17:31:41 +00:00
|
|
|
|
|
|
|
return $node;
|
|
|
|
}
|
|
|
|
|
2020-07-29 23:39:41 +00:00
|
|
|
public function configure(array $configuration): void
|
|
|
|
{
|
2020-08-25 22:21:41 +00:00
|
|
|
$replacedArguments = $configuration[self::REPLACED_ARGUMENTS] ?? [];
|
2020-09-12 21:19:08 +00:00
|
|
|
Assert::allIsInstanceOf($replacedArguments, ArgumentDefaultValueReplacer::class);
|
2020-08-25 22:21:41 +00:00
|
|
|
$this->replacedArguments = $replacedArguments;
|
2020-07-29 23:39:41 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:31:41 +00:00
|
|
|
/**
|
2018-10-21 19:43:47 +00:00
|
|
|
* @param MethodCall|StaticCall|ClassMethod $node
|
2018-05-01 17:31:41 +00:00
|
|
|
*/
|
2020-09-12 21:19:08 +00:00
|
|
|
private function processReplaces(Node $node, ArgumentDefaultValueReplacer $argumentDefaultValueReplacer): ?Node
|
2018-05-01 17:31:41 +00:00
|
|
|
{
|
2020-08-25 22:21:41 +00:00
|
|
|
if ($node instanceof ClassMethod) {
|
2020-09-12 21:19:08 +00:00
|
|
|
if (! isset($node->params[$argumentDefaultValueReplacer->getPosition()])) {
|
2020-08-25 22:21:41 +00:00
|
|
|
return null;
|
2018-05-01 17:31:41 +00:00
|
|
|
}
|
2020-09-12 21:19:08 +00:00
|
|
|
} elseif (isset($node->args[$argumentDefaultValueReplacer->getPosition()])) {
|
|
|
|
$this->processArgs($node, $argumentDefaultValueReplacer);
|
2018-05-01 17:31:41 +00:00
|
|
|
}
|
|
|
|
|
2018-10-21 19:43:47 +00:00
|
|
|
return $node;
|
2018-05-01 17:31:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-10-31 15:34:37 +00:00
|
|
|
* @param MethodCall|StaticCall $node
|
2018-05-01 17:31:41 +00:00
|
|
|
*/
|
2020-09-12 21:19:08 +00:00
|
|
|
private function processArgs(Node $node, ArgumentDefaultValueReplacer $argumentDefaultValueReplacer): void
|
2018-05-01 17:31:41 +00:00
|
|
|
{
|
2020-09-12 21:19:08 +00:00
|
|
|
$position = $argumentDefaultValueReplacer->getPosition();
|
2020-06-03 20:38:24 +00:00
|
|
|
|
2020-08-25 22:21:41 +00:00
|
|
|
$argValue = $this->getValue($node->args[$position]->value);
|
2020-06-03 20:38:24 +00:00
|
|
|
|
2020-09-12 21:19:08 +00:00
|
|
|
if (is_scalar(
|
|
|
|
$argumentDefaultValueReplacer->getValueBefore()
|
|
|
|
) && $argValue === $argumentDefaultValueReplacer->getValueBefore()) {
|
|
|
|
$node->args[$position] = $this->normalizeValueToArgument($argumentDefaultValueReplacer->getValueAfter());
|
|
|
|
} elseif (is_array($argumentDefaultValueReplacer->getValueBefore())) {
|
|
|
|
$newArgs = $this->processArrayReplacement($node->args, $argumentDefaultValueReplacer);
|
2018-05-01 17:31:41 +00:00
|
|
|
|
2020-08-25 22:21:41 +00:00
|
|
|
if ($newArgs) {
|
|
|
|
$node->args = $newArgs;
|
2018-10-31 15:34:37 +00:00
|
|
|
}
|
2018-07-18 12:24:36 +00:00
|
|
|
}
|
2018-07-18 14:06:45 +00:00
|
|
|
}
|
|
|
|
|
2020-07-27 06:56:25 +00:00
|
|
|
/**
|
|
|
|
* @param mixed $value
|
|
|
|
*/
|
2018-10-31 15:34:37 +00:00
|
|
|
private function normalizeValueToArgument($value): Arg
|
|
|
|
{
|
|
|
|
// class constants → turn string to composite
|
2019-05-28 16:34:40 +00:00
|
|
|
if (is_string($value) && Strings::contains($value, '::')) {
|
2018-10-31 15:34:37 +00:00
|
|
|
[$class, $constant] = explode('::', $value);
|
2020-07-19 18:58:54 +00:00
|
|
|
$classConstFetch = $this->createClassConstFetch($class, $constant);
|
2018-10-31 15:34:37 +00:00
|
|
|
|
2020-07-19 18:58:54 +00:00
|
|
|
return new Arg($classConstFetch);
|
2018-10-31 15:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return new Arg(BuilderHelpers::normalizeValue($value));
|
|
|
|
}
|
|
|
|
|
2018-07-17 21:47:21 +00:00
|
|
|
/**
|
2018-07-18 14:06:45 +00:00
|
|
|
* @param Arg[] $argumentNodes
|
2018-10-21 19:43:47 +00:00
|
|
|
* @return Arg[]|null
|
2018-07-17 21:47:21 +00:00
|
|
|
*/
|
2020-09-12 21:19:08 +00:00
|
|
|
private function processArrayReplacement(
|
|
|
|
array $argumentNodes,
|
|
|
|
ArgumentDefaultValueReplacer $argumentDefaultValueReplacer
|
|
|
|
): ?array {
|
|
|
|
$argumentValues = $this->resolveArgumentValuesToBeforeRecipe($argumentNodes, $argumentDefaultValueReplacer);
|
|
|
|
if ($argumentValues !== $argumentDefaultValueReplacer->getValueBefore()) {
|
2018-10-21 19:43:47 +00:00
|
|
|
return null;
|
2018-07-17 21:47:21 +00:00
|
|
|
}
|
|
|
|
|
2020-09-12 21:19:08 +00:00
|
|
|
if (is_string($argumentDefaultValueReplacer->getValueAfter())) {
|
|
|
|
$argumentNodes[$argumentDefaultValueReplacer->getPosition()] = $this->normalizeValueToArgument(
|
|
|
|
$argumentDefaultValueReplacer->getValueAfter()
|
2020-08-25 22:21:41 +00:00
|
|
|
);
|
2018-07-18 14:06:45 +00:00
|
|
|
|
|
|
|
// clear following arguments
|
2020-09-12 21:19:08 +00:00
|
|
|
$argumentCountToClear = count($argumentDefaultValueReplacer->getValueBefore());
|
|
|
|
for ($i = $argumentDefaultValueReplacer->getPosition() + 1; $i <= $argumentDefaultValueReplacer->getPosition() + $argumentCountToClear; ++$i) {
|
2018-10-21 19:43:47 +00:00
|
|
|
unset($argumentNodes[$i]);
|
2018-07-18 14:06:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $argumentNodes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Arg[] $argumentNodes
|
2020-08-11 10:59:04 +00:00
|
|
|
* @return mixed[]
|
2018-07-18 14:06:45 +00:00
|
|
|
*/
|
2020-08-25 22:21:41 +00:00
|
|
|
private function resolveArgumentValuesToBeforeRecipe(
|
|
|
|
array $argumentNodes,
|
2020-09-12 21:19:08 +00:00
|
|
|
ArgumentDefaultValueReplacer $argumentDefaultValueReplacer
|
2020-08-25 22:21:41 +00:00
|
|
|
): array {
|
2018-07-18 14:06:45 +00:00
|
|
|
$argumentValues = [];
|
|
|
|
|
2020-08-25 22:21:41 +00:00
|
|
|
/** @var mixed[] $valueBefore */
|
2020-09-12 21:19:08 +00:00
|
|
|
$valueBefore = $argumentDefaultValueReplacer->getValueBefore();
|
2020-08-25 22:21:41 +00:00
|
|
|
$beforeArgumentCount = count($valueBefore);
|
2018-07-18 14:06:45 +00:00
|
|
|
|
|
|
|
for ($i = 0; $i < $beforeArgumentCount; ++$i) {
|
2020-09-12 21:19:08 +00:00
|
|
|
if (! isset($argumentNodes[$argumentDefaultValueReplacer->getPosition() + $i])) {
|
2020-06-03 20:38:24 +00:00
|
|
|
continue;
|
2018-07-18 14:06:45 +00:00
|
|
|
}
|
2020-06-03 20:38:24 +00:00
|
|
|
|
2020-09-12 21:19:08 +00:00
|
|
|
$nextArg = $argumentNodes[$argumentDefaultValueReplacer->getPosition() + $i];
|
2020-06-03 20:38:24 +00:00
|
|
|
$argumentValues[] = $this->getValue($nextArg->value);
|
2018-07-17 21:47:21 +00:00
|
|
|
}
|
|
|
|
|
2018-07-18 14:06:45 +00:00
|
|
|
return $argumentValues;
|
2018-07-17 21:47:21 +00:00
|
|
|
}
|
2018-05-01 17:31:41 +00:00
|
|
|
}
|