diff --git a/src/NodeTraverser/StateHolder.php b/src/NodeTraverser/StateHolder.php deleted file mode 100644 index 941bf55845e..00000000000 --- a/src/NodeTraverser/StateHolder.php +++ /dev/null @@ -1,21 +0,0 @@ -isAfterTraverseCalled = true; - } - - public function isAfterTraverseCalled(): bool - { - return $this->isAfterTraverseCalled; - } -} diff --git a/src/NodeTraverser/TokenSwitcher.php b/src/NodeTraverser/TokenSwitcher.php new file mode 100644 index 00000000000..ecaa4395d10 --- /dev/null +++ b/src/NodeTraverser/TokenSwitcher.php @@ -0,0 +1,21 @@ +isEnabled = true; + } + + public function isEnabled(): bool + { + return $this->isEnabled; + } +} diff --git a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php deleted file mode 100644 index 996fd4bc59e..00000000000 --- a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorNodeVisitor.php +++ /dev/null @@ -1,107 +0,0 @@ -constructorMethodBuilder = $constructorMethodBuilder; - } - - public function isCandidate(Node $node): bool - { - return $node instanceof Class_; - } - - /** - * 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_) { - return $this->reconstruct($node); - } - - return null; - } - - private function reconstruct(Class_ $classNode): Node - { - foreach ($classNode->stmts as $classElementStatement) { - if (! $classElementStatement instanceof Property) { - continue; - } - - $propertyNode = $classElementStatement; - - $propertyDocBlock = $this->createDocBlockFromProperty($propertyNode); - $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); - if (! $injectAnnotations) { - continue; - } - - $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock); - $this->makePropertyPrivate($propertyNode); - - $propertyType = $propertyDocBlock->getAnnotationsOfType('var')[0] - ->getTypes()[0]; - $propertyName = (string) $propertyNode->props[0]->name; - - $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); - } - - return $classNode; - } - - private function createDocBlockFromProperty(Property $propertyNode): DocBlock - { - return new DocBlock($propertyNode->getDocComment()); - } - - private function makePropertyPrivate(Property $propertyNode): void - { - $propertyNode->flags = Class_::MODIFIER_PRIVATE; - } - - private function removeInjectAnnotationFromProperty(Property $propertyNode, DocBlock $propertyDocBlock): void - { - $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); - - foreach ($injectAnnotations as $injectAnnotation) { - $injectAnnotation->remove(); - } - - $propertyNode->setDocComment(new Doc($propertyDocBlock->getContent())); - } -} diff --git a/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php new file mode 100644 index 00000000000..567c0113f63 --- /dev/null +++ b/src/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector.php @@ -0,0 +1,127 @@ +constructorMethodBuilder = $constructorMethodBuilder; +// } + + public function __construct(TokenSwitcher $tokenSwitcher) + { + $this->tokenSwitcher = $tokenSwitcher; + } + + public function enterNode(Node $node): ?Node + { + if (! $this->isCandidate($node)) { + return null; + } + + return $this->reconstructProperty($node); + } + + public function isCandidate(Node $node): bool + { + if (! $node instanceof Property) { + return false; + } + + if (! $this->hasInjectAnnotation($node)) { + return false; + } + + $this->tokenSwitcher->enable(); + return true; + } + +// private function reconstruct(Class_ $classNode): Node +// { +// dump($classNode); +// die; +// +// foreach ($classNode->stmts as $classElementStatement) { +// if (! $classElementStatement instanceof Property) { +// continue; +// } +// +// $propertyNode = $classElementStatement; +// +// $propertyDocBlock = $this->createDocBlockFromNode($propertyNode); +// $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); +// if (! $injectAnnotations) { +// continue; +// } +// +// $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock); +// $this->makePropertyPrivate($propertyNode); +// +// $propertyType = $propertyDocBlock->getAnnotationsOfType('var')[0] +// ->getTypes()[0]; +// $propertyName = (string) $propertyNode->props[0]->name; +// +// $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); +// } +// +// return $classNode; +// } + + private function reconstructProperty($propertyNode): Property + { + $propertyDocBlock = $this->createDocBlockFromNode($propertyNode); + $propertyNode = $this->removeInjectAnnotationFromProperty($propertyNode, $propertyDocBlock); + +// $propertyNode->flags = Class_::MODIFIER_PRIVATE; + + return $propertyNode; + } + + private function hasInjectAnnotation(Property $propertyNode): bool + { + $propertyDocBlock = $this->createDocBlockFromNode($propertyNode); + + return (bool) $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); + } + + private function createDocBlockFromNode(Node $node): DocBlock + { + return new DocBlock($node->getDocComment()); + } + + private function removeInjectAnnotationFromProperty(Property $propertyNode, DocBlock $propertyDocBlock): Property + { + $injectAnnotations = $propertyDocBlock->getAnnotationsOfType(self::ANNOTATION_INJECT); + + foreach ($injectAnnotations as $injectAnnotation) { + $injectAnnotation->remove(); + } + + $propertyNode->setDocComment(new Doc($propertyDocBlock->getContent())); + + return $propertyNode; + } +} diff --git a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php index 0b9fbfd2b99..857f8630dea 100644 --- a/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php +++ b/src/NodeVisitor/DependencyInjection/NamedServicesToConstructor/AddPropertiesToClassNodeVisitor.php @@ -8,7 +8,7 @@ use PhpParser\NodeVisitorAbstract; use Rector\Builder\Class_\ClassPropertyCollector; use Rector\Builder\ConstructorMethodBuilder; use Rector\Builder\PropertyBuilder; -use Rector\NodeTraverser\StateHolder; +use Rector\NodeTraverser\TokenSwitcher; /** * Add new propertis to class and to contructor. @@ -31,20 +31,20 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract private $newClassPropertyCollector; /** - * @var StateHolder + * @var TokenSwitcher */ - private $stateHolder; + private $tokenSwitcher; public function __construct( ConstructorMethodBuilder $constructorMethodBuilder, PropertyBuilder $propertyBuilder, ClassPropertyCollector $newClassPropertyCollector, - StateHolder $stateHolder + TokenSwitcher $tokenSwitcher ) { $this->constructorMethodBuilder = $constructorMethodBuilder; $this->propertyBuilder = $propertyBuilder; $this->newClassPropertyCollector = $newClassPropertyCollector; - $this->stateHolder = $stateHolder; + $this->tokenSwitcher = $tokenSwitcher; } /** @@ -68,7 +68,7 @@ final class AddPropertiesToClassNodeVisitor extends NodeVisitorAbstract $propertiesForClass = $this->newClassPropertyCollector->getPropertiesforClass($className); foreach ($propertiesForClass as $propertyType => $propertyName) { - $this->stateHolder->setAfterTraverserIsCalled(); + $this->tokenSwitcher->enable(); $this->constructorMethodBuilder->addPropertyAssignToClass($classNode, $propertyType, $propertyName); $this->propertyBuilder->addPropertyToClass($classNode, $propertyType, $propertyName); } diff --git a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php index 3d9f6452b55..0810daee324 100644 --- a/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php +++ b/src/Rector/Contrib/Nette/NetteObjectToSmartTraitRector.php @@ -8,6 +8,7 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\TraitUse; use Rector\Builder\StatementGlue; use Rector\Deprecation\SetNames; +use Rector\NodeTraverser\TokenSwitcher; use Rector\Rector\AbstractRector; /** @@ -20,9 +21,15 @@ final class NetteObjectToSmartTraitRector extends AbstractRector */ private $statementGlue; - public function __construct(StatementGlue $statementGlue) + /** + * @var TokenSwitcher + */ + private $tokenSwitcher; + + public function __construct(StatementGlue $statementGlue, TokenSwitcher $tokenSwitcher) { $this->statementGlue = $statementGlue; + $this->tokenSwitcher = $tokenSwitcher; } public function getSetName(): string @@ -47,6 +54,7 @@ final class NetteObjectToSmartTraitRector extends AbstractRector return false; } + $this->tokenSwitcher->enable(); return true; } @@ -58,12 +66,12 @@ final class NetteObjectToSmartTraitRector extends AbstractRector */ public function refactor($classNode): ?Node { - // remove parent class - $classNode->extends = null; - $traitUseNode = $this->createTraitUse('Nette\SmartObject'); $this->statementGlue->addAsFirstTrait($classNode, $traitUseNode); + // remove parent class + $classNode->extends = null; + return $classNode; } diff --git a/src/Testing/Application/FileReconstructor.php b/src/Testing/Application/FileReconstructor.php index c4597646564..67e4ac22fd3 100644 --- a/src/Testing/Application/FileReconstructor.php +++ b/src/Testing/Application/FileReconstructor.php @@ -5,6 +5,7 @@ namespace Rector\Testing\Application; use PhpParser\Lexer; use PhpParser\NodeTraverser; use PhpParser\Parser; +use Rector\NodeTraverser\TokenSwitcher; use Rector\Printer\FormatPerservingPrinter; use SplFileInfo; @@ -30,16 +31,23 @@ final class FileReconstructor */ private $nodeTraverser; + /** + * @var TokenSwitcher + */ + private $tokenSwitcher; + public function __construct( Parser $parser, FormatPerservingPrinter $codeStyledPrinter, Lexer $lexer, - NodeTraverser $nodeTraverser + NodeTraverser $nodeTraverser, + TokenSwitcher $tokenSwitcher ) { $this->parser = $parser; $this->codeStyledPrinter = $codeStyledPrinter; $this->lexer = $lexer; $this->nodeTraverser = $nodeTraverser; + $this->tokenSwitcher = $tokenSwitcher; } // ref: https://github.com/nikic/PHP-Parser/issues/344#issuecomment-298162516 @@ -51,6 +59,10 @@ final class FileReconstructor $oldTokens = $this->lexer->getTokens(); $newStmts = $this->nodeTraverser->traverse($oldStmts); + if ($this->tokenSwitcher->isEnabled()) { + [$oldStmts, $newStmts] = [$newStmts, $oldStmts]; + } + return $this->codeStyledPrinter->printToString($newStmts, $oldStmts, $oldTokens); } } diff --git a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/Test.php b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/Test.php similarity index 92% rename from tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/Test.php rename to tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/Test.php index 76095660d82..7d7f2a93ab6 100644 --- a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/Test.php +++ b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/Test.php @@ -1,6 +1,6 @@ property = $property; diff --git a/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/wrong/wrong.php.inc b/tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/wrong/wrong.php.inc similarity index 100% rename from tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorReconstructor/wrong/wrong.php.inc rename to tests/NodeVisitor/DependencyInjection/InjectAnnotationToConstructorRector/wrong/wrong.php.inc