From b745b18311eb2e0e9eaf36acd24c5e970468b07a Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 22 Jun 2026 21:22:57 +0700 Subject: [PATCH 1/6] [AutoImport] Avoid used import into param that skipped from removal rule --- stubs/Config/App.php | 11 ++++ .../Fixture/keep_import_used_in_param.php.inc | 51 +++++++++++++++++++ .../config/configured_rule.php | 10 +++- 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 stubs/Config/App.php create mode 100644 tests/Issues/ImportFullyQualifiedIdentifierDocblock/Fixture/keep_import_used_in_param.php.inc diff --git a/stubs/Config/App.php b/stubs/Config/App.php new file mode 100644 index 00000000000..f75c070cc5f --- /dev/null +++ b/stubs/Config/App.php @@ -0,0 +1,11 @@ + +----- + diff --git a/tests/Issues/ImportFullyQualifiedIdentifierDocblock/config/configured_rule.php b/tests/Issues/ImportFullyQualifiedIdentifierDocblock/config/configured_rule.php index f145ce3083e..f1825a9c5a5 100644 --- a/tests/Issues/ImportFullyQualifiedIdentifierDocblock/config/configured_rule.php +++ b/tests/Issues/ImportFullyQualifiedIdentifierDocblock/config/configured_rule.php @@ -3,8 +3,14 @@ declare(strict_types=1); use Rector\Config\RectorConfig; +use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedConstructorParamRector; use Rector\Tests\Issues\ImportFullyQualifiedIdentifierDocblock\Source\AddFullyQualifiedIdentifierDocblockRector; return RectorConfig::configure() - ->withRules([AddFullyQualifiedIdentifierDocblockRector::class]) - ->withImportNames(); + ->withRules([AddFullyQualifiedIdentifierDocblockRector::class, RemoveUnusedConstructorParamRector::class]) + ->withImportNames() + ->withSkip([ + RemoveUnusedConstructorParamRector::class => [ + realpath(__DIR__ . '/../Fixture') . '/keep_import_used_in_param.php', + ], + ]); From 8d57c3636d1fdcb19676005ee5273eb8ab336b99 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 22 Jun 2026 21:34:47 +0700 Subject: [PATCH 2/6] fix --- src/PostRector/Rector/UnusedImportRemovingPostRector.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/PostRector/Rector/UnusedImportRemovingPostRector.php b/src/PostRector/Rector/UnusedImportRemovingPostRector.php index 8ba338c9ad6..d581cef5e00 100644 --- a/src/PostRector/Rector/UnusedImportRemovingPostRector.php +++ b/src/PostRector/Rector/UnusedImportRemovingPostRector.php @@ -153,12 +153,11 @@ private function findNamesInDocBlocks(Namespace_|FileNode $rootNode): array return null; } - $totalDocs = count($docs); foreach ($docs as $doc) { - $nodeToCheck = $totalDocs === 1 ? $node : clone $node; - if ($totalDocs > 1) { - $nodeToCheck->setDocComment($doc); - } + // parse the current comment independently of potentially mutated cached PHPDoc + $nodeToCheck = clone $node; + $nodeToCheck->setAttribute(AttributeKey::PHP_DOC_INFO, null); + $nodeToCheck->setDocComment($doc); $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($nodeToCheck); $names = [...$names, ...$phpDocInfo->getAnnotationClassNames()]; From de88dba3bbae535a3ea7b3d3120eabe2e7d60ca1 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 22 Jun 2026 21:36:30 +0700 Subject: [PATCH 3/6] avoid repeated clone --- src/PostRector/Rector/UnusedImportRemovingPostRector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PostRector/Rector/UnusedImportRemovingPostRector.php b/src/PostRector/Rector/UnusedImportRemovingPostRector.php index d581cef5e00..108047ae709 100644 --- a/src/PostRector/Rector/UnusedImportRemovingPostRector.php +++ b/src/PostRector/Rector/UnusedImportRemovingPostRector.php @@ -153,9 +153,9 @@ private function findNamesInDocBlocks(Namespace_|FileNode $rootNode): array return null; } + $nodeToCheck = clone $node; foreach ($docs as $doc) { // parse the current comment independently of potentially mutated cached PHPDoc - $nodeToCheck = clone $node; $nodeToCheck->setAttribute(AttributeKey::PHP_DOC_INFO, null); $nodeToCheck->setDocComment($doc); From 43a813acdf0e840bb78ce486bb12c92260a02d69 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 22 Jun 2026 21:39:57 +0700 Subject: [PATCH 4/6] Revert "avoid repeated clone" This reverts commit de88dba3bbae535a3ea7b3d3120eabe2e7d60ca1. --- src/PostRector/Rector/UnusedImportRemovingPostRector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PostRector/Rector/UnusedImportRemovingPostRector.php b/src/PostRector/Rector/UnusedImportRemovingPostRector.php index 108047ae709..d581cef5e00 100644 --- a/src/PostRector/Rector/UnusedImportRemovingPostRector.php +++ b/src/PostRector/Rector/UnusedImportRemovingPostRector.php @@ -153,9 +153,9 @@ private function findNamesInDocBlocks(Namespace_|FileNode $rootNode): array return null; } - $nodeToCheck = clone $node; foreach ($docs as $doc) { // parse the current comment independently of potentially mutated cached PHPDoc + $nodeToCheck = clone $node; $nodeToCheck->setAttribute(AttributeKey::PHP_DOC_INFO, null); $nodeToCheck->setDocComment($doc); From e5327d4ddc6cf789705b238b5af9beef2c54ace2 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 22 Jun 2026 21:47:08 +0700 Subject: [PATCH 5/6] handle set php doc info null on AbstractRector --- .../Rector/UnusedImportRemovingPostRector.php | 9 +++++---- src/Rector/AbstractRector.php | 11 ++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/PostRector/Rector/UnusedImportRemovingPostRector.php b/src/PostRector/Rector/UnusedImportRemovingPostRector.php index d581cef5e00..8ba338c9ad6 100644 --- a/src/PostRector/Rector/UnusedImportRemovingPostRector.php +++ b/src/PostRector/Rector/UnusedImportRemovingPostRector.php @@ -153,11 +153,12 @@ private function findNamesInDocBlocks(Namespace_|FileNode $rootNode): array return null; } + $totalDocs = count($docs); foreach ($docs as $doc) { - // parse the current comment independently of potentially mutated cached PHPDoc - $nodeToCheck = clone $node; - $nodeToCheck->setAttribute(AttributeKey::PHP_DOC_INFO, null); - $nodeToCheck->setDocComment($doc); + $nodeToCheck = $totalDocs === 1 ? $node : clone $node; + if ($totalDocs > 1) { + $nodeToCheck->setDocComment($doc); + } $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($nodeToCheck); $names = [...$names, ...$phpDocInfo->getAnnotationClassNames()]; diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index abb90e8f46f..9f73e35fe8a 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -281,7 +281,16 @@ protected function mirrorComments(Node $newNode, Node $oldNode): void private function cloneNode(Node $node): Node { $nodeTraverser = new NodeTraverser(new CloningVisitor()); - return $nodeTraverser->traverse([$node])[0]; + $clonedNode = $nodeTraverser->traverse([$node])[0]; + + $this->simpleCallableNodeTraverser->traverseNodesWithCallable( + $clonedNode, + static function (Node $subNode): void { + $subNode->setAttribute(AttributeKey::PHP_DOC_INFO, null); + } + ); + + return $clonedNode; } /** From d94599a7b8c068b994c18d2b8c9e1ed39805cad5 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 22 Jun 2026 21:50:17 +0700 Subject: [PATCH 6/6] add visitor --- .../PhpDocInfoRemovingNodeVisitor.php | 18 ++++++++++++++++++ src/Rector/AbstractRector.php | 14 +++----------- 2 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 src/PhpParser/NodeVisitor/PhpDocInfoRemovingNodeVisitor.php diff --git a/src/PhpParser/NodeVisitor/PhpDocInfoRemovingNodeVisitor.php b/src/PhpParser/NodeVisitor/PhpDocInfoRemovingNodeVisitor.php new file mode 100644 index 00000000000..986decbb129 --- /dev/null +++ b/src/PhpParser/NodeVisitor/PhpDocInfoRemovingNodeVisitor.php @@ -0,0 +1,18 @@ +setAttribute(AttributeKey::PHP_DOC_INFO, null); + return $node; + } +} diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index 9f73e35fe8a..9988b66a6f2 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -35,6 +35,7 @@ use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser; use Rector\PhpParser\Comparing\NodeComparator; use Rector\PhpParser\Node\NodeFactory; +use Rector\PhpParser\NodeVisitor\PhpDocInfoRemovingNodeVisitor; use Rector\Skipper\Skipper\Skipper; use Rector\Skipper\ValueObject\SkipMatch; use Rector\ValueObject\Application\File; @@ -280,17 +281,8 @@ protected function mirrorComments(Node $newNode, Node $oldNode): void */ private function cloneNode(Node $node): Node { - $nodeTraverser = new NodeTraverser(new CloningVisitor()); - $clonedNode = $nodeTraverser->traverse([$node])[0]; - - $this->simpleCallableNodeTraverser->traverseNodesWithCallable( - $clonedNode, - static function (Node $subNode): void { - $subNode->setAttribute(AttributeKey::PHP_DOC_INFO, null); - } - ); - - return $clonedNode; + $nodeTraverser = new NodeTraverser(new CloningVisitor(), new PhpDocInfoRemovingNodeVisitor()); + return $nodeTraverser->traverse([$node])[0]; } /**