|
4 | 4 |
|
5 | 5 | namespace Rector\DowngradePhp85\Rector\Class_; |
6 | 6 |
|
7 | | -use PhpParser\Comment\Doc; |
| 7 | +use PhpParser\Builder\Property; |
8 | 8 | use PhpParser\Modifiers; |
9 | 9 | use PhpParser\Node; |
10 | 10 | use PhpParser\Node\Param; |
11 | | -use PhpParser\Node\Stmt\Class_; |
12 | 11 | use PhpParser\Node\Stmt\ClassMethod; |
13 | | -use PhpParser\Node\Stmt\Trait_; |
| 12 | +use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode; |
| 13 | +use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode; |
14 | 14 | use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; |
15 | | -use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger; |
16 | | -use Rector\PhpParser\Node\BetterNodeFinder; |
17 | | -use Rector\PhpParser\Printer\BetterStandardPrinter; |
| 15 | +use Rector\Comments\NodeDocBlock\DocBlockUpdater; |
| 16 | +use Rector\Privatization\NodeManipulator\VisibilityManipulator; |
18 | 17 | use Rector\Rector\AbstractRector; |
19 | 18 | use Rector\ValueObject\MethodName; |
| 19 | +use Rector\ValueObject\Visibility; |
20 | 20 | use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; |
21 | 21 | use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; |
22 | 22 |
|
|
27 | 27 | */ |
28 | 28 | final class DowngradeFinalPropertyPromotionRector extends AbstractRector |
29 | 29 | { |
| 30 | + /** |
| 31 | + * @var string |
| 32 | + */ |
| 33 | + private const TAGNAME = 'final'; |
| 34 | + |
| 35 | + public function __construct( |
| 36 | + private readonly VisibilityManipulator $visibilityManipulator, |
| 37 | + private readonly DocBlockUpdater $docBlockUpdater, |
| 38 | + private readonly PhpDocInfoFactory $phpDocInfoFactory, |
| 39 | + ) { |
| 40 | + } |
| 41 | + |
30 | 42 | public function getRuleDefinition(): RuleDefinition |
31 | 43 | { |
32 | 44 | return new RuleDefinition('Change constructor final property promotion to @final annotation assign', [ |
@@ -59,30 +71,59 @@ public function __construct( |
59 | 71 | */ |
60 | 72 | public function getNodeTypes(): array |
61 | 73 | { |
62 | | - return [Class_::class, Trait_::class]; |
| 74 | + return [ClassMethod::class]; |
63 | 75 | } |
64 | 76 |
|
65 | 77 | /** |
66 | | - * @param Class_|Trait_ $node |
| 78 | + * @param ClassMethod $node |
67 | 79 | */ |
68 | 80 | public function refactor(Node $node): null |
69 | 81 | { |
70 | | - $constructorClassMethod = $node->getMethod(MethodName::CONSTRUCT); |
71 | | - if (! $constructorClassMethod instanceof ClassMethod) { |
| 82 | + |
| 83 | + if (! $this->isName($node, MethodName::CONSTRUCT)) { |
72 | 84 | return null; |
73 | 85 | } |
74 | 86 |
|
75 | | - foreach ($constructorClassMethod->params as $promotedParam) { |
76 | | - if (($promotedParam->flags & Modifiers::FINAL) !== 0) { |
77 | | - $promotedParam->flags &= ~Modifiers::FINAL; |
78 | | - |
79 | | - $existingDoc = $promotedParam->getDocComment(); |
80 | | - if (! $existingDoc) { |
81 | | - $promotedParam->setDocComment(new Doc('/** @final */')); |
82 | | - } |
| 87 | + foreach ($node->params as $param) { |
| 88 | + if (! $param->isPromoted()) { |
| 89 | + continue; |
| 90 | + } |
| 91 | + if (! $this->visibilityManipulator->hasVisibility($param, Visibility::FINAL)) { |
| 92 | + continue; |
83 | 93 | } |
| 94 | + |
| 95 | + $this->makeNonFinal($param); |
| 96 | + |
| 97 | + $this->addPhpDocTag($param); |
| 98 | + |
84 | 99 | } |
85 | 100 |
|
86 | 101 | return null; |
87 | 102 | } |
| 103 | + |
| 104 | + public function makeNonFinal(Param $node): void |
| 105 | + { |
| 106 | + if (! $this->isFinal($node)) { |
| 107 | + return; |
| 108 | + } |
| 109 | + |
| 110 | + $node->flags -= Modifiers::FINAL; |
| 111 | + } |
| 112 | + |
| 113 | + private function isFinal(Param $node): bool{ |
| 114 | + return (bool) ($node->flags & Modifiers::FINAL); |
| 115 | + } |
| 116 | + |
| 117 | + private function addPhpDocTag(Property|Param $node): bool |
| 118 | + { |
| 119 | + $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); |
| 120 | + |
| 121 | + if ($phpDocInfo->hasByName(self::TAGNAME)) { |
| 122 | + return false; |
| 123 | + } |
| 124 | + |
| 125 | + $phpDocInfo->addPhpDocTagNode(new PhpDocTagNode('@' . self::TAGNAME, new GenericTagValueNode(''))); |
| 126 | + $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node); |
| 127 | + return true; |
| 128 | + } |
88 | 129 | } |
0 commit comments