[NodeTraverser] use it instead of Dispatcher and own solution

This commit is contained in:
TomasVotruba 2017-07-18 23:59:43 +02:00
parent e32453e2be
commit 3a6eee57f3
22 changed files with 126 additions and 92 deletions

View File

@ -9,8 +9,8 @@ This tool will *reconstruct* (change) your code - **run it only in a new clean g
## All Reconstructors
- `InjectAnnotationToConstructorReconstructor` ([Nette](https://github.com/nette/))
- `NamedServicesToConstructorReconstructor` ([Symfony](https://github.com/symfony/))
- `InjectAnnotationToConstructorNodeTraverser` ([Nette](https://github.com/nette/))
- `NamedServicesToConstructorNodeTraverser` ([Symfony](https://github.com/symfony/))
## Install

View File

@ -2,8 +2,8 @@
namespace Rector\Application;
use PhpParser\NodeTraverser;
use PhpParser\Parser;
use Rector\Dispatcher\NodeDispatcher;
use Rector\Printer\CodeStyledPrinter;
use SplFileInfo;
@ -14,21 +14,21 @@ final class FileProcessor
*/
private $parser;
/**
* @var NodeDispatcher
*/
private $nodeDispatcher;
/**
* @var CodeStyledPrinter
*/
private $codeStyledPrinter;
public function __construct(Parser $parser, CodeStyledPrinter $codeStyledPrinter, NodeDispatcher $nodeDispatcher)
/**
* @var NodeTraverser
*/
private $nodeTraverser;
public function __construct(Parser $parser, CodeStyledPrinter $codeStyledPrinter, NodeTraverser $nodeTraverser)
{
$this->parser = $parser;
$this->nodeDispatcher = $nodeDispatcher;
$this->codeStyledPrinter = $codeStyledPrinter;
$this->nodeTraverser = $nodeTraverser;
}
/**
@ -51,9 +51,9 @@ final class FileProcessor
$originalNodes = $this->cloneArrayOfObjects($nodes);
foreach ($nodes as $node) {
$this->nodeDispatcher->dispatch($node);
}
$this->nodeTraverser->traverse($nodes);
$this->codeStyledPrinter->printToFile($file, $originalNodes, $nodes);
}

View File

@ -1,12 +0,0 @@
<?php declare(strict_types=1);
namespace Rector\Contract\Dispatcher;
use PhpParser\Node;
interface ReconstructorInterface
{
public function isCandidate(Node $node): bool;
public function reconstruct(Node $classNode): void;
}

View File

@ -2,6 +2,8 @@
namespace Rector\DependencyInjection\CompilerPass;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor;
use Rector\Contract\Dispatcher\ReconstructorInterface;
use Rector\Dispatcher\NodeDispatcher;
use Symfony\Component\Console\Application;
@ -15,7 +17,7 @@ final class CollectorCompilerPass implements CompilerPassInterface
public function process(ContainerBuilder $containerBuilder): void
{
$this->collectCommandsToConsoleApplication($containerBuilder);
$this->collectReconstructorsToNodeDispatcher($containerBuilder);
$this->collectNodeVisitorsToTraverser($containerBuilder);
}
private function collectCommandsToConsoleApplication(ContainerBuilder $containerBuilder): void
@ -28,13 +30,13 @@ final class CollectorCompilerPass implements CompilerPassInterface
);
}
private function collectReconstructorsToNodeDispatcher(ContainerBuilder $containerBuilder): void
private function collectNodeVisitorsToTraverser(ContainerBuilder $containerBuilder): void
{
DefinitionCollector::loadCollectorWithType(
$containerBuilder,
NodeDispatcher::class,
ReconstructorInterface::class,
'addReconstructor'
NodeTraverser::class,
NodeVisitor::class,
'addVisitor'
);
}
}

View File

@ -1,29 +0,0 @@
<?php declare(strict_types=1);
namespace Rector\Dispatcher;
use PhpParser\Node;
use Rector\Contract\Dispatcher\ReconstructorInterface;
final class NodeDispatcher
{
/**
* @var ReconstructorInterface[]
*/
private $reconstructors;
public function addReconstructor(ReconstructorInterface $reconstructor): void
{
$this->reconstructors[] = $reconstructor;
}
public function dispatch(Node $node): void
{
// todo: build hash map
foreach ($this->reconstructors as $reconstructor) {
if ($reconstructor->isCandidate($node)) {
$reconstructor->reconstruct($node);
}
}
}
}

View File

@ -1,16 +1,17 @@
<?php declare(strict_types=1);
namespace Rector\Reconstructor\DependencyInjection;
namespace Rector\NodeVisitor\DependencyInjection;
use PhpCsFixer\DocBlock\DocBlock;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
use Rector\Builder\ConstructorMethodBuilder;
use Rector\Contract\Dispatcher\ReconstructorInterface;
final class InjectAnnotationToConstructorReconstructor implements ReconstructorInterface
final class InjectAnnotationToConstructorNodeVisitor extends NodeVisitorAbstract
{
/**
* @var ConstructorMethodBuilder
@ -75,4 +76,53 @@ final class InjectAnnotationToConstructorReconstructor implements ReconstructorI
$propertyNode->setDocComment(new Doc($propertyDocBlock->getContent()));
}
/**
* Called when entering a node.
*
* Return value semantics:
* * null
* => $node stays as-is
* * NodeTraverser::DONT_TRAVERSE_CHILDREN
* => Children of $node are not traversed. $node stays as-is
* * NodeTraverser::STOP_TRAVERSAL
* => Traversal is aborted. $node stays as-is
* * otherwise
* => $node is set to the return value
*
* @return null|int|Node Replacement node (or special return value)
*/
public function enterNode(Node $node)
{
if ($node instanceof Class_) {
$this->reconstruct($node);
return $node;
}
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
/**
* Called when leaving a node.
*
* Return value semantics:
* * null
* => $node stays as-is
* * NodeTraverser::REMOVE_NODE
* => $node is removed from the parent array
* * NodeTraverser::STOP_TRAVERSAL
* => Traversal is aborted. $node stays as-is
* * array (of Nodes)
* => The return value is merged into the parent array (at the position of the $node)
* * otherwise
* => $node is set to the return value
*
* @param Node $node Node
*
* @return null|int|Node|Node[] Replacement node (or special return value)
*/
public function leaveNode(Node $node)
{
// TODO: Implement leaveNode() method.
}
}

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Reconstructor\DependencyInjection;
namespace Rector\NodeVisitor\DependencyInjection;
use PhpParser\Node;
use PhpParser\Node\Expr;
@ -11,16 +11,16 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\NodeVisitorAbstract;
use Rector\Analyzer\ClassAnalyzer;
use Rector\Builder\ConstructorMethodBuilder;
use Rector\Builder\Naming\NameResolver;
use Rector\Builder\PropertyBuilder;
use Rector\Contract\Dispatcher\ReconstructorInterface;
use Rector\Tests\Reconstructor\DependencyInjection\NamedServicesToConstructorReconstructor\Source\LocalKernel;
use Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorReconstructor\Source\LocalKernel;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Kernel;
final class NamedServicesToConstructorReconstructor implements ReconstructorInterface
final class NamedServicesToConstructorNodeVisitor extends NodeVisitorAbstract
{
/**
* @var ConstructorMethodBuilder
@ -54,7 +54,7 @@ final class NamedServicesToConstructorReconstructor implements ReconstructorInte
$this->classAnalyzer = $classAnalyzer;
}
public function isCandidate(Node $node): bool
private function isCandidate(Node $node): bool
{
// OR? Maybe listen on MethodCall... $this-> +get('...')
@ -208,4 +208,26 @@ final class NamedServicesToConstructorReconstructor implements ReconstructorInte
);
}
/**
* Called when entering a node.
*
* Return value semantics:
* * null
* => $node stays as-is
* * NodeTraverser::DONT_TRAVERSE_CHILDREN
* => Children of $node are not traversed. $node stays as-is
* * NodeTraverser::STOP_TRAVERSAL
* => Traversal is aborted. $node stays as-is
* * otherwise
* => $node is set to the return value
*
* @param Node $node Node
*
* @return null|int|Node Replacement node (or special return value)
*/
public function enterNode(Node $node)
{
return $this->isCandidate($node);
}
}

View File

@ -5,10 +5,8 @@ namespace Rector\Testing\Application;
use PhpParser\Lexer;
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor;
use PhpParser\NodeVisitor;
use PhpParser\Parser;
use PhpParser\PrettyPrinter\Standard;
use Rector\Contract\Dispatcher\ReconstructorInterface;
use Rector\Printer\CodeStyledPrinter;
use SplFileInfo;
@ -26,17 +24,23 @@ final class FileReconstructor
/**
* @var Lexer
*/
private $lexer;
public function __construct(Parser $parser, CodeStyledPrinter $codeStyledPrinter, Lexer $lexer)
private $lexer;
/**
* @var NodeTraverser
*/
private $nodeTraverser;
public function __construct(Parser $parser, CodeStyledPrinter $codeStyledPrinter, Lexer $lexer, NodeTraverser $nodeTraverser)
{
$this->parser = $parser;
$this->codeStyledPrinter = $codeStyledPrinter;
$this->lexer = $lexer;
$this->nodeTraverser = $nodeTraverser;
}
# ref: https://github.com/nikic/PHP-Parser/issues/344#issuecomment-298162516
public function processFileWithReconstructor(SplFileInfo $file, ReconstructorInterface $reconstructor): string
public function processFileWithReconstructor(SplFileInfo $file, NodeVisitor $nodeVisitor): string
{
$fileContent = file_get_contents($file->getRealPath());
@ -47,18 +51,9 @@ final class FileReconstructor
// keep format printer
$oldTokens = $this->lexer->getTokens();
$traverser = new NodeTraverser;
$traverser->addVisitor(new CloningVisitor);
$newStmts = $traverser->traverse($oldStmts);
foreach ($oldStmts as $node) {
if ($reconstructor->isCandidate($node)) {
$reconstructor->reconstruct($node);
}
}
// after reconstruct evnet?
$this->nodeTraverser->addVisitor($nodeVisitor);
$newStmts = $this->nodeTraverser->traverse($oldStmts);
return $this->codeStyledPrinter->printToString($oldStmts, $newStmts, $oldTokens);
}

View File

@ -2,6 +2,7 @@
namespace Rector\Testing\PHPUnit;
use PhpParser\NodeVisitor;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Rector\Contract\Dispatcher\ReconstructorInterface;
@ -38,7 +39,7 @@ abstract class AbstractReconstructorTestCase extends TestCase
abstract protected function getReconstructorClass(): string;
private function getReconstructor(): ReconstructorInterface
private function getReconstructor(): NodeVisitor
{
return $this->container->get($this->getReconstructorClass());
}

View File

@ -16,4 +16,9 @@ services:
PhpParser\Lexer:
factory: ['@Rector\Parser\LexerFactory', 'create']
PhpParser\BuilderFactory: ~
# Traverser
PhpParser\NodeTraverser: ~
# Printer
PhpParser\NodeVisitor\CloningVisitor: ~
PhpParser\PrettyPrinter\Standard: ~

View File

@ -1,8 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\Tests\Reconstructor\DependencyInjection\InjectAnnotationToConstructorReconstructor;
namespace Rector\Tests\NodeVisitor\DependencyInjection\InjectAnnotationToConstructorReconstructor;
use Rector\Reconstructor\DependencyInjection\InjectAnnotationToConstructorReconstructor;
use Rector\NodeVisitor\DependencyInjection\InjectAnnotationToConstructorNodeVisitor;
use Rector\Testing\PHPUnit\AbstractReconstructorTestCase;
final class Test extends AbstractReconstructorTestCase
@ -17,7 +17,7 @@ final class Test extends AbstractReconstructorTestCase
protected function getReconstructorClass(): string
{
return InjectAnnotationToConstructorReconstructor::class;
return InjectAnnotationToConstructorNodeVisitor::class;
}
}

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
namespace Rector\Tests\Reconstructor\DependencyInjection\NamedServicesToConstructorReconstructor\Source;
namespace Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorReconstructor\Source;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;

View File

@ -1,8 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\Tests\Reconstructor\DependencyInjection\NamedServicesToConstructorReconstructor;
namespace Rector\Tests\NodeVisitor\DependencyInjection\NamedServicesToConstructorReconstructor;
use Rector\Reconstructor\DependencyInjection\NamedServicesToConstructorReconstructor;
use Rector\NodeVisitor\DependencyInjection\NamedServicesToConstructorNodeVisitor;
use Rector\Testing\PHPUnit\AbstractReconstructorTestCase;
final class Test extends AbstractReconstructorTestCase
@ -17,6 +17,6 @@ final class Test extends AbstractReconstructorTestCase
protected function getReconstructorClass(): string
{
return NamedServicesToConstructorReconstructor::class;
return NamedServicesToConstructorNodeVisitor::class;
}
}