visibilityManipulator = $visibilityManipulator; $this->phpDocInfoFactory = $phpDocInfoFactory; $this->docBlockUpdater = $docBlockUpdater; } public function getRuleDefinition() : RuleDefinition { return new RuleDefinition('Remove useless @readonly annotation on native readonly type', [new CodeSample(<<<'CODE_SAMPLE' final class SomeClass { /** * @readonly */ private readonly string $name; public function __construct(string $name) { $this->name = $name; } } CODE_SAMPLE , <<<'CODE_SAMPLE' final class SomeClass { private readonly string $name; public function __construct(string $name) { $this->name = $name; } } CODE_SAMPLE )]); } /** * @return array> */ public function getNodeTypes() : array { return [Class_::class, Property::class, Param::class]; } /** * @param Class_|Property|Param $node */ public function refactor(Node $node) : ?Node { // for param, only on property promotion if ($node instanceof Param && $node->flags === 0) { return null; } if (!$this->visibilityManipulator->isReadonly($node)) { return null; } $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); $readonlyDoc = $phpDocInfo->getByName('readonly'); if (!$readonlyDoc instanceof PhpDocTagNode) { return null; } if (!$readonlyDoc->value instanceof GenericTagValueNode) { return null; } if ($readonlyDoc->value->value !== '') { return null; } $phpDocInfo->removeByName('readonly'); $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node); return $node; } }