mirror of
https://github.com/rectorphp/rector.git
synced 2025-02-25 04:03:55 +01:00
add ArgumentReplacerItemRecipe, use typed config structure
This commit is contained in:
parent
3e8644fec1
commit
e08aea0139
@ -8,20 +8,20 @@ use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Rector\NodeAnalyzer\ClassMethodAnalyzer;
|
||||
use Rector\NodeAnalyzer\MethodCallAnalyzer;
|
||||
use Rector\NodeAnalyzer\StaticMethodCallAnalyzer;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\Rector\Dynamic\Configuration\ArgumentReplacerItemRecipe;
|
||||
|
||||
final class ArgumentReplacerRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var mixed[]
|
||||
* @var ArgumentReplacerItemRecipe[]
|
||||
*/
|
||||
private $argumentChangesMethodAndClass = [];
|
||||
private $argumentReplacerItemRecipes = [];
|
||||
|
||||
/**
|
||||
* @var MethodCallAnalyzer
|
||||
@ -29,9 +29,9 @@ final class ArgumentReplacerRector extends AbstractRector
|
||||
private $methodCallAnalyzer;
|
||||
|
||||
/**
|
||||
* @var mixed[][]
|
||||
* @var argumentReplacerItemRecipe[]
|
||||
*/
|
||||
private $activeArgumentChangesByPosition = [];
|
||||
private $activeArgumentReplacerItemRecipes = [];
|
||||
|
||||
/**
|
||||
* @var ClassMethodAnalyzer
|
||||
@ -58,7 +58,7 @@ final class ArgumentReplacerRector extends AbstractRector
|
||||
StaticMethodCallAnalyzer $staticMethodCallAnalyzer,
|
||||
ConstExprEvaluator $constExprEvaluator
|
||||
) {
|
||||
$this->argumentChangesMethodAndClass = $argumentChangesByMethodAndType;
|
||||
$this->loadArgumentReplacerItemRecipes($argumentChangesByMethodAndType);
|
||||
$this->methodCallAnalyzer = $methodCallAnalyzer;
|
||||
$this->classMethodAnalyzer = $classMethodAnalyzer;
|
||||
$this->staticMethodCallAnalyzer = $staticMethodCallAnalyzer;
|
||||
@ -67,9 +67,9 @@ final class ArgumentReplacerRector extends AbstractRector
|
||||
|
||||
public function isCandidate(Node $node): bool
|
||||
{
|
||||
$this->activeArgumentChangesByPosition = $this->matchArgumentChanges($node);
|
||||
$this->activeArgumentReplacerItemRecipes = $this->matchArgumentChanges($node);
|
||||
|
||||
return (bool) $this->activeArgumentChangesByPosition;
|
||||
return (bool) $this->activeArgumentReplacerItemRecipes;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,25 +79,23 @@ final class ArgumentReplacerRector extends AbstractRector
|
||||
{
|
||||
$argumentsOrParameters = $this->getNodeArgumentsOrParameters($node);
|
||||
|
||||
foreach ($this->activeArgumentChangesByPosition as $position => $argumentChange) {
|
||||
$key = key($argumentChange);
|
||||
$value = array_shift($argumentChange);
|
||||
foreach ($this->activeArgumentReplacerItemRecipes as $argumentReplacerItemRecipe) {
|
||||
// @todo constants and own methods
|
||||
if ($argumentReplacerItemRecipe->getType() === 'removed') {
|
||||
unset($argumentsOrParameters[$argumentReplacerItemRecipe->getPosition()]);
|
||||
|
||||
if ($key === '~') {
|
||||
if ($value === null) { // remove argument
|
||||
unset($argumentsOrParameters[$position]);
|
||||
} else { // new default value
|
||||
$argumentsOrParameters[$position] = BuilderHelpers::normalizeValue($value);
|
||||
}
|
||||
} else {
|
||||
// replace old value with new one
|
||||
} elseif ($argumentReplacerItemRecipe->getType() === 'changed') {
|
||||
$argumentsOrParameters[$argumentReplacerItemRecipe->getPosition()] = BuilderHelpers::normalizeValue($argumentReplacerItemRecipe->getDefaultValue());
|
||||
} elseif ($argumentReplacerItemRecipe->getType() === 'replace_default_value') {
|
||||
/** @var Arg $argumentOrParameter */
|
||||
$argumentOrParameter = $argumentsOrParameters[$position];
|
||||
|
||||
$argumentOrParameter = $argumentsOrParameters[$argumentReplacerItemRecipe->getPosition()];
|
||||
$resolvedValue = $this->constExprEvaluator->evaluateDirectly($argumentOrParameter->value);
|
||||
|
||||
if ($resolvedValue === $key) {
|
||||
$argumentsOrParameters[$position] = BuilderHelpers::normalizeValue($value);
|
||||
$replaceMap = $argumentReplacerItemRecipe->getReplaceMap();
|
||||
foreach ($replaceMap as $oldValue => $newValue) {
|
||||
if ($resolvedValue === $oldValue) {
|
||||
$argumentsOrParameters[$argumentReplacerItemRecipe->getPosition()] = BuilderHelpers::normalizeValue($newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,7 +106,7 @@ final class ArgumentReplacerRector extends AbstractRector
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[][]
|
||||
* @return ArgumentReplacerItemRecipe[]
|
||||
*/
|
||||
private function matchArgumentChanges(Node $node): array
|
||||
{
|
||||
@ -116,17 +114,16 @@ final class ArgumentReplacerRector extends AbstractRector
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach ($this->argumentChangesMethodAndClass as $type => $argumentChangesByMethod) {
|
||||
$methods = array_keys($argumentChangesByMethod);
|
||||
if ($this->isTypeAndMethods($node, $type, $methods)) {
|
||||
/** @var Identifier $identifierNode */
|
||||
$identifierNode = $node->name;
|
||||
$argumentReplacerItemRecipes = [];
|
||||
|
||||
return $argumentChangesByMethod[$identifierNode->toString()];
|
||||
foreach ($this->argumentReplacerItemRecipes as $argumentReplacerItemRecipe) {
|
||||
|
||||
if ($this->isTypeAndMethods($node, $argumentReplacerItemRecipe->getClass(), [$argumentReplacerItemRecipe->getMethod()])) {
|
||||
$argumentReplacerItemRecipes[] = $argumentReplacerItemRecipe;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
return $argumentReplacerItemRecipes;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,4 +170,11 @@ final class ArgumentReplacerRector extends AbstractRector
|
||||
|
||||
return $this->classMethodAnalyzer->isTypeAndMethods($node, $type, $methods);
|
||||
}
|
||||
|
||||
private function loadArgumentReplacerItemRecipes(array $configurationArrays): void
|
||||
{
|
||||
foreach ($configurationArrays as $configurationArray) {
|
||||
$this->argumentReplacerItemRecipes[] = ArgumentReplacerItemRecipe::createFromArray($configurationArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
107
src/Rector/Dynamic/Configuration/ArgumentReplacerItemRecipe.php
Normal file
107
src/Rector/Dynamic/Configuration/ArgumentReplacerItemRecipe.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Rector\Dynamic\Configuration;
|
||||
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class ArgumentReplacerItemRecipe
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $class;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $method;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $position;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $defaultValue;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $replaceMap = [];
|
||||
|
||||
/**
|
||||
* @param mixed $defaultValue
|
||||
* @param string[] $replaceMap
|
||||
*/
|
||||
private function __construct(string $class, string $method, int $position, string $type, $defaultValue = null, array $replaceMap)
|
||||
{
|
||||
$this->class = $class;
|
||||
$this->method = $method;
|
||||
$this->position = $position;
|
||||
$this->type = $type;
|
||||
$this->defaultValue = $defaultValue;
|
||||
$this->replaceMap = $replaceMap;
|
||||
}
|
||||
|
||||
public static function createFromArray(array $data): self
|
||||
{
|
||||
// @todo: make exceptions clear for end user
|
||||
Assert::keyExists($data, 'class');
|
||||
Assert::keyExists($data, 'method');
|
||||
Assert::keyExists($data, 'position');
|
||||
Assert::keyExists($data, 'type');
|
||||
|
||||
if ($data['type'] === 'replace_default_value') {
|
||||
Assert::keyExists($data, 'replace_map');
|
||||
}
|
||||
|
||||
return new self(
|
||||
$data['class'],
|
||||
$data['method'],
|
||||
$data['position'],
|
||||
$data['type'],
|
||||
$data['default_value'] ?? null,
|
||||
$data['replace_map'] ?? []
|
||||
);
|
||||
}
|
||||
|
||||
public function getClass(): string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
public function getMethod(): string
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
public function getPosition(): int
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
return $this->defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getReplaceMap(): array
|
||||
{
|
||||
return $this->replaceMap;
|
||||
}
|
||||
}
|
@ -1,23 +1,41 @@
|
||||
rectors:
|
||||
Rector\Rector\Dynamic\ArgumentReplacerRector:
|
||||
'Symfony\Component\DependencyInjection\ContainerBuilder':
|
||||
'compile':
|
||||
0:
|
||||
# added default value
|
||||
'~': false
|
||||
'addCompilerPass':
|
||||
2:
|
||||
# added default value
|
||||
'~': 0
|
||||
# value object approach
|
||||
-
|
||||
class: 'Symfony\Component\DependencyInjection\ContainerBuilder'
|
||||
method: 'addCompilerPass'
|
||||
position: 2
|
||||
type: 'added'
|
||||
default_value: 0
|
||||
|
||||
'Doctrine\ORM\Persisters\Entity\AbstractEntityInheritancePersister':
|
||||
'getSelectJoinColumnSQL':
|
||||
4:
|
||||
# remove completely
|
||||
'~': ~
|
||||
# added default value
|
||||
-
|
||||
class: 'Symfony\Component\DependencyInjection\ContainerBuilder'
|
||||
method: 'compile'
|
||||
type: 'changed'
|
||||
position: 0
|
||||
default_value: false
|
||||
|
||||
'Symfony\Component\DependencyInjection\Definition':
|
||||
'setScope':
|
||||
0:
|
||||
# replace by new value
|
||||
'Symfony\Component\DependencyInjection\ContainerBuilder::SCOPE_PROTOTYPE': false
|
||||
# added default value
|
||||
-
|
||||
class: 'Symfony\Component\DependencyInjection\ContainerBuilder'
|
||||
method: 'addCompilerPass'
|
||||
type: 'changed'
|
||||
position: 0
|
||||
default_value: 0
|
||||
|
||||
# remove argument
|
||||
-
|
||||
class: 'Doctrine\ORM\Persisters\Entity\AbstractEntityInheritancePersister'
|
||||
method: 'getSelectJoinColumnSQL'
|
||||
position: 4
|
||||
type: 'remove'
|
||||
|
||||
# replace default value
|
||||
-
|
||||
class: 'Symfony\Component\DependencyInjection\Definition'
|
||||
method: 'setScope'
|
||||
position: 0
|
||||
type: 'replace_default_value'
|
||||
replace_map:
|
||||
'Symfony\Component\DependencyInjection\ContainerBuilder::SCOPE_PROTOTYPE': false
|
||||
|
Loading…
x
Reference in New Issue
Block a user