diff --git a/src/BetterPhpDocParser/Comment/CommentsMerger.php b/src/BetterPhpDocParser/Comment/CommentsMerger.php index 7462b77dd18..ea053957846 100644 --- a/src/BetterPhpDocParser/Comment/CommentsMerger.php +++ b/src/BetterPhpDocParser/Comment/CommentsMerger.php @@ -5,10 +5,48 @@ namespace Rector\BetterPhpDocParser\Comment; use PhpParser\Node; +use PhpParser\Node\Stmt\InlineHTML; +use PhpParser\Node\Stmt\Nop; +use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\NodeTypeResolver\Node\AttributeKey; +use Rector\PhpParser\Comparing\NodeComparator; -final class CommentsMerger +final readonly class CommentsMerger { + public function __construct( + private NodeComparator $nodeComparator, + ) { + } + + public function mirrorComments(Node $newNode, Node $oldNode): void + { + if ($oldNode instanceof InlineHTML) { + return; + } + + if ($this->nodeComparator->areSameNode($newNode, $oldNode)) { + return; + } + + $oldPhpDocInfo = $oldNode->getAttribute(AttributeKey::PHP_DOC_INFO); + $newPhpDocInfo = $newNode->getAttribute(AttributeKey::PHP_DOC_INFO); + + if ($newPhpDocInfo instanceof PhpDocInfo) { + if (! $oldPhpDocInfo instanceof PhpDocInfo) { + return; + } + + if ((string) $oldPhpDocInfo->getPhpDocNode() !== (string) $newPhpDocInfo->getPhpDocNode()) { + return; + } + } + + $newNode->setAttribute(AttributeKey::PHP_DOC_INFO, $oldPhpDocInfo); + if (! $newNode instanceof Nop) { + $newNode->setAttribute(AttributeKey::COMMENTS, $oldNode->getAttribute(AttributeKey::COMMENTS)); + } + } + /** * @param Node[] $mergedNodes */ diff --git a/src/DependencyInjection/LazyContainerFactory.php b/src/DependencyInjection/LazyContainerFactory.php index 07c8b196614..5065871eae1 100644 --- a/src/DependencyInjection/LazyContainerFactory.php +++ b/src/DependencyInjection/LazyContainerFactory.php @@ -17,6 +17,7 @@ use Rector\Application\ChangedNodeScopeRefresher; use Rector\Application\FileProcessor; use Rector\Application\Provider\CurrentFileProvider; +use Rector\BetterPhpDocParser\Comment\CommentsMerger; use Rector\BetterPhpDocParser\Contract\BasePhpDocNodeVisitorInterface; use Rector\BetterPhpDocParser\Contract\PhpDocParser\PhpDocNodeDecoratorInterface; use Rector\BetterPhpDocParser\PhpDocNodeMapper; @@ -558,6 +559,7 @@ static function (AbstractRector $rector, Container $container): void { $container->get(CurrentFileProvider::class), $container->get(CreatedByRuleDecorator::class), $container->get(ChangedNodeScopeRefresher::class), + $container->get(CommentsMerger::class), ); } ); diff --git a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ContextNodeVisitor.php b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ContextNodeVisitor.php index 50dff6b611b..19c4da6f1b5 100644 --- a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ContextNodeVisitor.php +++ b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ContextNodeVisitor.php @@ -58,7 +58,10 @@ public function enterNode(Node $node): ?Node } if ($node instanceof Unset_) { - $this->processContextInUnset($node); + foreach ($node->vars as $var) { + $var->setAttribute(AttributeKey::IS_UNSET_VAR, true); + } + return null; } @@ -130,13 +133,6 @@ static function (Node $subNode): null { ); } - private function processContextInUnset(Unset_ $unset): void - { - foreach ($unset->vars as $var) { - $var->setAttribute(AttributeKey::IS_UNSET_VAR, true); - } - } - private function processContextInIf(If_|Else_|ElseIf_ $node): void { foreach ($node->stmts as $stmt) { diff --git a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/PhpVersionConditionNodeVisitor.php b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/PhpVersionConditionNodeVisitor.php index 7127ae5deb2..b81f526c00d 100644 --- a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/PhpVersionConditionNodeVisitor.php +++ b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/PhpVersionConditionNodeVisitor.php @@ -27,7 +27,7 @@ public function enterNode(Node $node): ?Node if (($node instanceof Ternary || $node instanceof If_) && $this->hasVersionCompareCond($node)) { if ($node instanceof Ternary) { $nodes = [$node->else]; - if ($node->if instanceof \PhpParser\Node) { + if ($node->if instanceof Node) { $nodes[] = $node->if; } } else { diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index cabf128dd16..d8110732a47 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -9,9 +9,7 @@ use PhpParser\Node\PropertyItem; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Const_; -use PhpParser\Node\Stmt\InlineHTML; use PhpParser\Node\Stmt\Interface_; -use PhpParser\Node\Stmt\Nop; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\Trait_; use PhpParser\NodeVisitor; @@ -21,7 +19,7 @@ use PHPStan\Type\Type; use Rector\Application\ChangedNodeScopeRefresher; use Rector\Application\Provider\CurrentFileProvider; -use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; +use Rector\BetterPhpDocParser\Comment\CommentsMerger; use Rector\ChangesReporting\ValueObject\RectorWithLineChange; use Rector\Contract\Rector\HTMLAverseRectorInterface; use Rector\Contract\Rector\RectorInterface; @@ -71,6 +69,8 @@ abstract class AbstractRector extends NodeVisitorAbstract implements RectorInter private CurrentFileProvider $currentFileProvider; + private CommentsMerger $commentsMerger; + /** * @var array */ @@ -89,7 +89,8 @@ public function autowire( NodeComparator $nodeComparator, CurrentFileProvider $currentFileProvider, CreatedByRuleDecorator $createdByRuleDecorator, - ChangedNodeScopeRefresher $changedNodeScopeRefresher + ChangedNodeScopeRefresher $changedNodeScopeRefresher, + CommentsMerger $commentsMerger ): void { $this->nodeNameResolver = $nodeNameResolver; $this->nodeTypeResolver = $nodeTypeResolver; @@ -100,6 +101,7 @@ public function autowire( $this->currentFileProvider = $currentFileProvider; $this->createdByRuleDecorator = $createdByRuleDecorator; $this->changedNodeScopeRefresher = $changedNodeScopeRefresher; + $this->commentsMerger = $commentsMerger; } /** @@ -189,6 +191,8 @@ final public function enterNode(Node $node): int|Node|null /** * Replacing nodes in leaveNode() method avoids infinite recursion * see"infinite recursion" in https://github.com/nikic/PHP-Parser/blob/master/doc/component/Walking_the_AST.markdown + * + * @return Node|Node[]|NodeVisitor::REMOVE_NODE|null */ final public function leaveNode(Node $node): array|int|Node|null { @@ -268,31 +272,7 @@ protected function traverseNodesWithCallable(Node | array $nodes, callable $call protected function mirrorComments(Node $newNode, Node $oldNode): void { - if ($this->nodeComparator->areSameNode($newNode, $oldNode)) { - return; - } - - if ($oldNode instanceof InlineHTML) { - return; - } - - $oldPhpDocInfo = $oldNode->getAttribute(AttributeKey::PHP_DOC_INFO); - $newPhpDocInfo = $newNode->getAttribute(AttributeKey::PHP_DOC_INFO); - - if ($newPhpDocInfo instanceof PhpDocInfo) { - if (! $oldPhpDocInfo instanceof PhpDocInfo) { - return; - } - - if ((string) $oldPhpDocInfo->getPhpDocNode() !== (string) $newPhpDocInfo->getPhpDocNode()) { - return; - } - } - - $newNode->setAttribute(AttributeKey::PHP_DOC_INFO, $oldPhpDocInfo); - if (! $newNode instanceof Nop) { - $newNode->setAttribute(AttributeKey::COMMENTS, $oldNode->getAttribute(AttributeKey::COMMENTS)); - } + $this->commentsMerger->mirrorComments($newNode, $oldNode); } private function decorateCurrentAndChildren(Node $node): void