From bb6d7422b2541217089d8134a8bb610ad6fd9d9c Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 22 Oct 2026 23:44:58 +0200 Subject: [PATCH 1/2] [Renaming] Deprecate RenameAnnotationRector as niche, never used and needs context --- .../Fixture/fixture.php.inc | 31 ------ .../Fixture/rename_everywhere.php.inc | 35 ------- ...ip_method_with_comment_not_php_doc.php.inc | 18 ---- .../RenameAnnotationRectorTest.php | 28 ------ .../config/configured_rule.php | 15 --- .../Contract/RenameAnnotationInterface.php | 3 + .../ClassMethod/RenameAnnotationRector.php | 99 ++----------------- .../ValueObject/RenameAnnotationByType.php | 3 + 8 files changed, 14 insertions(+), 218 deletions(-) delete mode 100644 rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/fixture.php.inc delete mode 100644 rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/rename_everywhere.php.inc delete mode 100644 rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/skip_method_with_comment_not_php_doc.php.inc delete mode 100644 rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/RenameAnnotationRectorTest.php delete mode 100644 rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/config/configured_rule.php diff --git a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/fixture.php.inc b/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/fixture.php.inc deleted file mode 100644 index cc311c2eedc..00000000000 --- a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/fixture.php.inc +++ /dev/null @@ -1,31 +0,0 @@ - ------ - diff --git a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/rename_everywhere.php.inc b/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/rename_everywhere.php.inc deleted file mode 100644 index d516f0b9cc9..00000000000 --- a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/rename_everywhere.php.inc +++ /dev/null @@ -1,35 +0,0 @@ - ------ - diff --git a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/skip_method_with_comment_not_php_doc.php.inc b/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/skip_method_with_comment_not_php_doc.php.inc deleted file mode 100644 index a370ce8ef56..00000000000 --- a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/Fixture/skip_method_with_comment_not_php_doc.php.inc +++ /dev/null @@ -1,18 +0,0 @@ - diff --git a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/RenameAnnotationRectorTest.php b/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/RenameAnnotationRectorTest.php deleted file mode 100644 index e83237b853f..00000000000 --- a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/RenameAnnotationRectorTest.php +++ /dev/null @@ -1,28 +0,0 @@ -doTestFile($filePath); - } - - public static function provideData(): Iterator - { - return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); - } - - public function provideConfigFilePath(): string - { - return __DIR__ . '/config/configured_rule.php'; - } -} diff --git a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/config/configured_rule.php b/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/config/configured_rule.php deleted file mode 100644 index 7557046253c..00000000000 --- a/rules-tests/Renaming/Rector/ClassMethod/RenameAnnotationRector/config/configured_rule.php +++ /dev/null @@ -1,15 +0,0 @@ -ruleWithConfiguration(RenameAnnotationRector::class, [ - new RenameAnnotationByType('PHPUnit\Framework\TestCase', 'scenario', 'test'), - new RenameAnnotation('psalm-ignore', 'phpstan-ignore'), - ]); -}; diff --git a/rules/Renaming/Contract/RenameAnnotationInterface.php b/rules/Renaming/Contract/RenameAnnotationInterface.php index 326a70e1afa..14d8800e8e0 100644 --- a/rules/Renaming/Contract/RenameAnnotationInterface.php +++ b/rules/Renaming/Contract/RenameAnnotationInterface.php @@ -4,6 +4,9 @@ namespace Rector\Renaming\Contract; +/** + * @api used in deprecated RenameAnnotationRector configs + */ interface RenameAnnotationInterface { public function getOldAnnotation(): string; diff --git a/rules/Renaming/Rector/ClassMethod/RenameAnnotationRector.php b/rules/Renaming/Rector/ClassMethod/RenameAnnotationRector.php index 1178a2d8f52..c1c31360147 100644 --- a/rules/Renaming/Rector/ClassMethod/RenameAnnotationRector.php +++ b/rules/Renaming/Rector/ClassMethod/RenameAnnotationRector.php @@ -6,38 +6,20 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; -use PhpParser\Node\Stmt\Property; -use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; -use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; -use Rector\Comments\NodeDocBlock\DocBlockUpdater; +use Rector\Configuration\Deprecation\Contract\DeprecatedInterface; use Rector\Contract\Rector\ConfigurableRectorInterface; -use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockTagReplacer; +use Rector\Exception\ShouldNotHappenException; use Rector\Rector\AbstractRector; -use Rector\Renaming\Contract\RenameAnnotationInterface; use Rector\Renaming\ValueObject\RenameAnnotationByType; use Rector\RuleDoc\CodeSample\ConfiguredCodeSample; use Rector\RuleDoc\RuleDefinition; -use Webmozart\Assert\Assert; /** - * @see \Rector\Tests\Renaming\Rector\ClassMethod\RenameAnnotationRector\RenameAnnotationRectorTest + * @deprecated This rule is deprecated, as too niche, never used and needs project context. Write a custom rule for the exact project case instead. */ -final class RenameAnnotationRector extends AbstractRector implements ConfigurableRectorInterface +final class RenameAnnotationRector extends AbstractRector implements ConfigurableRectorInterface, DeprecatedInterface { - /** - * @var RenameAnnotationInterface[] - */ - private array $renameAnnotations = []; - - public function __construct( - private readonly DocBlockTagReplacer $docBlockTagReplacer, - private readonly DocBlockUpdater $docBlockUpdater, - private readonly PhpDocInfoFactory $phpDocInfoFactory, - ) { - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -91,47 +73,10 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - if ($node instanceof Expression) { - return $this->refactorExpression($node); - } - - $hasChanged = false; - foreach ($node->stmts as $stmt) { - if (! $stmt instanceof ClassMethod && ! $stmt instanceof Property) { - continue; - } - - $phpDocInfo = $this->phpDocInfoFactory->createFromNode($stmt); - if (! $phpDocInfo instanceof PhpDocInfo) { - continue; - } - - foreach ($this->renameAnnotations as $renameAnnotation) { - if ($renameAnnotation instanceof RenameAnnotationByType && ! $this->isObjectType( - $node, - $renameAnnotation->getObjectType() - )) { - continue; - } - - $hasDocBlockChanged = $this->docBlockTagReplacer->replaceTagByAnother( - $phpDocInfo, - $renameAnnotation->getOldAnnotation(), - $renameAnnotation->getNewAnnotation() - ); - - if ($hasDocBlockChanged) { - $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($stmt); - $hasChanged = true; - } - } - } - - if (! $hasChanged) { - return null; - } - - return $node; + throw new ShouldNotHappenException(sprintf( + '"%s" rule is deprecated, as too niche and part of no set; write a custom rule for the exact project case instead', + self::class + )); } /** @@ -139,33 +84,5 @@ public function refactor(Node $node): ?Node */ public function configure(array $configuration): void { - Assert::allIsAOf($configuration, RenameAnnotationInterface::class); - $this->renameAnnotations = $configuration; - } - - private function refactorExpression(Expression $expression): ?Expression - { - $hasChanged = false; - - $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($expression); - - foreach ($this->renameAnnotations as $renameAnnotation) { - $hasDocBlockChanged = $this->docBlockTagReplacer->replaceTagByAnother( - $phpDocInfo, - $renameAnnotation->getOldAnnotation(), - $renameAnnotation->getNewAnnotation() - ); - - if ($hasDocBlockChanged) { - $hasChanged = true; - } - } - - if ($hasChanged) { - $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($expression); - return $expression; - } - - return null; } } diff --git a/rules/Renaming/ValueObject/RenameAnnotationByType.php b/rules/Renaming/ValueObject/RenameAnnotationByType.php index 5cbcff35380..5832e73d5ee 100644 --- a/rules/Renaming/ValueObject/RenameAnnotationByType.php +++ b/rules/Renaming/ValueObject/RenameAnnotationByType.php @@ -8,6 +8,9 @@ use Rector\Renaming\Contract\RenameAnnotationInterface; use Rector\Validation\RectorAssert; +/** + * @api used in deprecated RenameAnnotationRector configs + */ final readonly class RenameAnnotationByType implements RenameAnnotationInterface { public function __construct( From c24e42f0a0e5278f975d3708c7cff73c112f4f25 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 22 Oct 2026 23:48:38 +0200 Subject: [PATCH 2/2] skip downstream-only DocBlockTagReplacer in class-leak --- .github/workflows/code_analysis.yaml | 2 +- .../PhpDoc/NodeAnalyzer/DocBlockTagReplacer.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index 831ebb1012f..41cea584a83 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -53,7 +53,7 @@ jobs: - name: 'Active Classes' run: | - vendor/bin/class-leak check bin config src rules utils --skip-suffix "Rector" --skip-type="Rector\\Utils\\Compiler\\Unprefixer" --skip-type="Rector\\NodeCollector\\BinaryOpConditionsCollector" --skip-type="Rector\\DependencyInjection\\PHPStan\\RichParserFactory" --skip-path="Source" + vendor/bin/class-leak check bin config src rules utils --skip-suffix "Rector" --skip-type="Rector\\Utils\\Compiler\\Unprefixer" --skip-type="Rector\\NodeCollector\\BinaryOpConditionsCollector" --skip-type="Rector\\DependencyInjection\\PHPStan\\RichParserFactory" --skip-type="Rector\\NodeTypeResolver\\PhpDoc\\NodeAnalyzer\\DocBlockTagReplacer" --skip-path="Source" - name: 'Compatible PHPStan versions' diff --git a/src/NodeTypeResolver/PhpDoc/NodeAnalyzer/DocBlockTagReplacer.php b/src/NodeTypeResolver/PhpDoc/NodeAnalyzer/DocBlockTagReplacer.php index 61d923780ea..0d85c1c1906 100644 --- a/src/NodeTypeResolver/PhpDoc/NodeAnalyzer/DocBlockTagReplacer.php +++ b/src/NodeTypeResolver/PhpDoc/NodeAnalyzer/DocBlockTagReplacer.php @@ -9,6 +9,9 @@ use Rector\BetterPhpDocParser\Annotation\AnnotationNaming; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; +/** + * @api used by extension packages to rename doc tags + */ final readonly class DocBlockTagReplacer { public function __construct(