[ArgumentReplacerRector] unite API to be compatible with rest of rectors

This commit is contained in:
TomasVotruba 2017-11-01 17:36:48 +01:00
parent a9b9721bb5
commit e3b7cb4d21
6 changed files with 56 additions and 70 deletions

View File

@ -3,8 +3,8 @@
namespace Rector\DeprecationExtractor\RectorGuess;
use PhpParser\Node;
use Rector\Rector\Dynamic\ClassReplacerRector;
use Rector\Rector\Dynamic\ArgumentReplacerRector;
use Rector\Rector\Dynamic\ClassReplacerRector;
use Rector\Rector\Dynamic\MethodNameReplacerRector;
final class RectorGuessFactory

View File

@ -6,8 +6,8 @@ use PhpParser\Node\Stmt\Nop;
use Rector\DeprecationExtractor\Deprecation\Deprecation;
use Rector\DeprecationExtractor\Rector\RectorGuesser;
use Rector\DeprecationExtractor\RectorGuess\RectorGuess;
use Rector\Rector\Dynamic\ClassReplacerRector;
use Rector\Rector\Dynamic\ArgumentReplacerRector;
use Rector\Rector\Dynamic\ClassReplacerRector;
use Rector\Rector\Dynamic\MethodNameReplacerRector;
use Rector\Tests\AbstractContainerAwareTestCase;

View File

@ -6,8 +6,8 @@ use PhpParser\Node\Stmt\Nop;
use PHPUnit\Framework\TestCase;
use Rector\DeprecationExtractor\RectorGuess\RectorGuess;
use Rector\DeprecationExtractor\RectorGuess\RectorGuessFactory;
use Rector\Rector\Dynamic\ClassReplacerRector;
use Rector\Rector\Dynamic\ArgumentReplacerRector;
use Rector\Rector\Dynamic\ClassReplacerRector;
use Rector\Rector\Dynamic\MethodNameReplacerRector;
final class RectorGuessFactoryTest extends TestCase

View File

@ -7,14 +7,13 @@ use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use Rector\NodeAnalyzer\MethodCallAnalyzer;
use Rector\Rector\AbstractRector;
use Rector\Rector\Dynamic\ArgumentWrapper\MethodChange;
final class ArgumentReplacerRector extends AbstractRector
{
/**
* @var MethodChange[]
* @var mixed[]
*/
private $methodChanges = [];
private $argumentChangesMethodAndClass = [];
/**
* @var MethodCallAnalyzer
@ -22,34 +21,30 @@ final class ArgumentReplacerRector extends AbstractRector
private $methodCallAnalyzer;
/**
* @var MethodChange|null
* @var mixed[]|null
*/
private $activeMethodChange;
private $activeArgumentChangesByPosition;
/**
* @param mixed[] $methodChanges
* @param mixed[] $argumentChangesByMethodAndType
*/
public function __construct(array $methodChanges, MethodCallAnalyzer $methodCallAnalyzer)
public function __construct(array $argumentChangesByMethodAndType, MethodCallAnalyzer $methodCallAnalyzer)
{
foreach ($methodChanges as $methodChange) {
$this->methodChanges[] = MethodChange::createFromMethodChange($methodChange);
}
$this->argumentChangesMethodAndClass = $argumentChangesByMethodAndType;
$this->methodCallAnalyzer = $methodCallAnalyzer;
}
public function isCandidate(Node $node): bool
{
$this->activeMethodChange = $this->resolveMethodChangeForNode($node);
if ($this->activeMethodChange === null) {
$this->activeArgumentChangesByPosition = $this->matchArgumentChanges($node);
if ($this->activeArgumentChangesByPosition === null) {
return false;
}
/** @var MethodCall $node */
if ($this->activeMethodChange->getType() === MethodChange::TYPE_ADDED) {
foreach ($this->activeArgumentChangesByPosition as $position => $argumentChange) {
$argumentCount = count($node->args);
if ($argumentCount < $this->activeMethodChange->getPosition() + 1) {
if ($argumentCount < $position + 1) {
return true;
}
}
@ -66,43 +61,38 @@ final class ArgumentReplacerRector extends AbstractRector
{
$arguments = $methodCallNode->args;
if ($this->activeMethodChange->getType() === MethodChange::TYPE_ADDED) {
if (count($arguments) < $this->activeMethodChange->getPosition() + 1) {
$defaultValue = $this->activeMethodChange->getDefaultValue();
$defaultValueNode = BuilderHelpers::normalizeValue($defaultValue);
foreach ($this->activeArgumentChangesByPosition as $position => $argumentChange) {
if (count($arguments) < $position + 1) {
$key = key($argumentChange);
$value = array_shift($argumentChange);
$arguments[$this->activeMethodChange->getPosition()] = $defaultValueNode;
if ($key === '~') { // new default value
$arguments[$position] = BuilderHelpers::normalizeValue($value);
}
}
}
// @todo: other types
$methodCallNode->args = $arguments;
return $methodCallNode;
}
private function resolveMethodChangeForNode(Node $node): ?MethodChange
/**
* @return mixed[]|null
*/
private function matchArgumentChanges(Node $node): ?array
{
if (! $node instanceof MethodCall) {
return null;
}
foreach ($this->methodChanges as $methodChange) {
if ($this->matchesMethodChange($node, $methodChange)) {
return $methodChange;
foreach ($this->argumentChangesMethodAndClass as $type => $argumentChangesByMethod) {
$methods = array_keys($argumentChangesByMethod);
if ($this->methodCallAnalyzer->isTypeAndMethods($node, $type, $methods)) {
return $argumentChangesByMethod[$node->name->toString()];
}
}
return null;
}
private function matchesMethodChange(Node $node, MethodChange $methodChange): bool
{
return $this->methodCallAnalyzer->isTypeAndMethod(
$node,
$methodChange->getClass(),
$methodChange->getMethod()
);
}
}

View File

@ -9,20 +9,20 @@ final class Test extends AbstractConfigurableRectorTestCase
{
public function test(): void
{
// $this->doTestFileMatchesExpectedContent(
// __DIR__ . '/wrong/wrong.php.inc',
// __DIR__ . '/correct/correct.php.inc'
// );
//
// $this->doTestFileMatchesExpectedContent(
// __DIR__ . '/wrong/wrong2.php.inc',
// __DIR__ . '/correct/correct2.php.inc'
// );
$this->doTestFileMatchesExpectedContent(
__DIR__ . '/wrong/wrong.php.inc',
__DIR__ . '/correct/correct.php.inc'
);
$this->doTestFileMatchesExpectedContent(
__DIR__ . '/wrong/wrong3.php.inc',
__DIR__ . '/correct/correct3.php.inc'
__DIR__ . '/wrong/wrong2.php.inc',
__DIR__ . '/correct/correct2.php.inc'
);
// $this->doTestFileMatchesExpectedContent(
// __DIR__ . '/wrong/wrong3.php.inc',
// __DIR__ . '/correct/correct3.php.inc'
// );
}
protected function provideConfig(): string

View File

@ -1,23 +1,19 @@
rectors:
Rector\Rector\Dynamic\ArgumentReplacerRector:
-
class: Symfony\Component\DependencyInjection\ContainerBuilder
method: compile
position: 0
type: added
default_value: false
'Symfony\Component\DependencyInjection\ContainerBuilder':
'compile':
0:
# added default value
~: false
'addCompilerPass':
2:
# added default value
~: 0
-
class: Symfony\Component\DependencyInjection\ContainerBuilder
method: addCompilerPass
position: 2
type: added
default_value: 0
-
class: Symfony\Component\DependencyInjection\ContainerBuilder
method: setScope
position: 1
type: added # drop this, just 'old' => 'new'; check usage in configs!
# use replace table, not only one change for all
default_value: false
# -
# class: Symfony\Component\DependencyInjection\ContainerBuilder
# method: setScope
# position: 1
# type: added # drop this, just 'old' => 'new'; check usage in configs!
# # use replace table, not only one change for all
# default_value: false