decouple to AbstractRector

This commit is contained in:
TomasVotruba 2017-10-19 01:02:47 +02:00
parent 7f423aa47e
commit c58b55796d
3 changed files with 79 additions and 65 deletions

View File

@ -3,10 +3,14 @@
namespace Rector\Rector;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Nop;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
use Rector\Contract\Rector\RectorInterface;
use Rector\Node\Attribute;
use SplObjectStorage;
abstract class AbstractRector extends NodeVisitorAbstract implements RectorInterface
{
@ -15,6 +19,22 @@ abstract class AbstractRector extends NodeVisitorAbstract implements RectorInter
*/
protected $shouldRemoveNode = false;
/**
* @var SplObjectStorage|Expression[]
*/
private $expressionsToPrepend = [];
/**
* @param Node[] $nodes
* @return Node[]
*/
final public function beforeTraverse(array $nodes): array
{
$this->expressionsToPrepend = new SplObjectStorage;
return $nodes;
}
/**
* @return null|int|Node
*/
@ -44,4 +64,57 @@ abstract class AbstractRector extends NodeVisitorAbstract implements RectorInter
return null;
}
/**
* @param Node[] $nodes
* @return Node[]
*/
public function afterTraverse(array $nodes): array
{
return $this->prependExpressionNodes($nodes);
}
protected function prependNodeBehindNode(Expr $nodeToPrepend, Node $positionNode): void
{
/** @var Node $parentNode */
$parentNode = $positionNode->getAttribute(Attribute::PARENT_NODE);
if (! $parentNode instanceof Expression) {
// validate?
return;
}
$expressionToPrepend = new Expression($nodeToPrepend);
if (isset($this->expressionsToPrepend[$parentNode])) {
$this->expressionsToPrepend[$parentNode] = array_merge(
$this->expressionsToPrepend[$parentNode],
[$expressionToPrepend]
);
} else {
$this->expressionsToPrepend[$parentNode] = [$expressionToPrepend];
}
}
/**
* @param Node[] $nodes
* @return Node[] array
*/
private function prependExpressionNodes(array $nodes): array
{
foreach ($nodes as $i => $node) {
if ($node instanceof Expression) {
if (! isset($this->expressionsToPrepend[$node])) {
continue;
}
array_splice($nodes, $i + 1, 0, $this->expressionsToPrepend[$node]);
unset($this->expressionsToPrepend[$node]);
} elseif (isset($node->stmts)) {
$node->stmts = $this->prependExpressionNodes($node->stmts);
}
}
return $nodes;
}
}

View File

@ -5,12 +5,8 @@ namespace Rector\Rector\Contrib\Nette\DI;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Expression;
use Rector\Builder\StatementGlue;
use Rector\Node\Attribute;
use Rector\NodeAnalyzer\MethodCallAnalyzer;
use Rector\Rector\AbstractRector;
use SplObjectStorage;
/**
* Nette\DI\Compiler::compile arguments are deprecated, use Compiler::addConfig() and Compiler::setClassName().
@ -30,21 +26,9 @@ final class CompilerArgumentsRector extends AbstractRector
*/
private $methodCallAnalyzer;
/**
* @var SplObjectStorage|Expression[]
*/
private $expressionsToPrepend = [];
/**
* @var StatementGlue
*/
private $statementGlue;
public function __construct(MethodCallAnalyzer $methodCallAnalyzer, StatementGlue $statementGlue)
public function __construct(MethodCallAnalyzer $methodCallAnalyzer)
{
$this->expressionsToPrepend = new SplObjectStorage;
$this->methodCallAnalyzer = $methodCallAnalyzer;
$this->statementGlue = $statementGlue;
}
public function isCandidate(Node $node): bool
@ -57,31 +41,19 @@ final class CompilerArgumentsRector extends AbstractRector
return count($node->args) >= 1;
}
/**
* @todo build into abstract?
*
* @param Node[] $nodes
* @return Node[]
*/
public function afterTraverse(array $nodes): array
{
return $this->processNodes($nodes);
}
/**
* @param MethodCall $methodCallNode
*/
public function refactor(Node $methodCallNode): ?Node
{
$oldArguments = $methodCallNode->args;
$nodesToPrepend = [];
$addConfigMethodCallNode = $this->cloneMethodWithNameAndArgument(
$methodCallNode,
'addConfig',
$oldArguments[0]
);
$nodesToPrepend[] = new Expression($addConfigMethodCallNode);
$this->prependNodeBehindNode($addConfigMethodCallNode, $methodCallNode);
if (isset($oldArguments[1])) {
$setClassNameMethodCallNode = $this->cloneMethodWithNameAndArgument(
@ -89,39 +61,14 @@ final class CompilerArgumentsRector extends AbstractRector
'setClassName',
$oldArguments[1]
);
$nodesToPrepend[] = new Expression($setClassNameMethodCallNode);
$this->prependNodeBehindNode($setClassNameMethodCallNode, $methodCallNode);
}
$parentExpressionNode = $methodCallNode->getAttribute(Attribute::PARENT_NODE);
$this->expressionsToPrepend[$parentExpressionNode] = $nodesToPrepend;
$methodCallNode->args = [];
return $methodCallNode;
}
/**
* @param Node[] $nodes
* @return Node[] array
*/
private function processNodes(array $nodes): array
{
foreach ($nodes as $i => $node) {
if ($node instanceof Expression) {
if (! isset($this->expressionsToPrepend[$node])) {
continue;
}
$nodes = $this->statementGlue->insertNewNodesAfter($nodes, $this->expressionsToPrepend[$node], $i);
$this->expressionsToPrepend[$node] = null;
} elseif (isset($node->stmts)) {
$node->stmts = $this->processNodes($node->stmts);
}
}
return $nodes;
}
private function cloneMethodWithNameAndArgument(
MethodCall $methodCallNode,
string $method,

View File

@ -55,15 +55,6 @@ final class PseudoNamespaceToNamespaceRector extends AbstractRector
$this->statementGlue = $statementGlue;
}
/**
* @param mixed[] $nodes
*/
public function beforeTraverse(array $nodes): void
{
$this->newNamespace = null;
$this->oldToNewUseStatements = [];
}
public function isCandidate(Node $node): bool
{
$name = $this->resolveNameFromNode($node);
@ -134,6 +125,9 @@ final class PseudoNamespaceToNamespaceRector extends AbstractRector
}
}
$this->newNamespace = null;
$this->oldToNewUseStatements = [];
return $nodes;
}