diff --git a/rules-tests/Php81/Rector/ClassConst/FinalizePublicClassConstantRector/Fixture/class_inheritance.php.inc b/rules-tests/Php81/Rector/ClassConst/FinalizePublicClassConstantRector/Fixture/class_inheritance.php.inc new file mode 100644 index 00000000000..7b7fb7e61a2 --- /dev/null +++ b/rules-tests/Php81/Rector/ClassConst/FinalizePublicClassConstantRector/Fixture/class_inheritance.php.inc @@ -0,0 +1,29 @@ + +----- + diff --git a/rules/Php81/Rector/ClassConst/FinalizePublicClassConstantRector.php b/rules/Php81/Rector/ClassConst/FinalizePublicClassConstantRector.php index c8d4fccbcf2..851a1c1765f 100644 --- a/rules/Php81/Rector/ClassConst/FinalizePublicClassConstantRector.php +++ b/rules/Php81/Rector/ClassConst/FinalizePublicClassConstantRector.php @@ -7,8 +7,11 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassConst; +use PHPStan\Reflection\ReflectionProvider; +use Rector\Core\NodeAnalyzer\ClassAnalyzer; use Rector\Core\Rector\AbstractRector; use Rector\Core\ValueObject\PhpVersionFeature; +use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer; use Rector\Privatization\NodeManipulator\VisibilityManipulator; use Rector\VersionBonding\Contract\MinPhpVersionInterface; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -22,13 +25,16 @@ final class FinalizePublicClassConstantRector extends AbstractRector implements MinPhpVersionInterface { public function __construct( + private readonly FamilyRelationsAnalyzer $familyRelationsAnalyzer, + private readonly ReflectionProvider $reflectionProvider, + private readonly ClassAnalyzer $classAnalyzer, private readonly VisibilityManipulator $visibilityManipulator ) { } public function getRuleDefinition(): RuleDefinition { - return new RuleDefinition('Add final to constants that', [ + return new RuleDefinition('Add final to constants that does not have children', [ new CodeSample( <<<'CODE_SAMPLE' class SomeClass @@ -61,13 +67,13 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - $parentClass = $this->betterNodeFinder->findParentType($node, Class_::class); + $class = $this->betterNodeFinder->findParentType($node, Class_::class); - if (! $parentClass instanceof Class_) { + if (! $class instanceof Class_) { return null; } - if ($parentClass->isFinal()) { + if ($class->isFinal()) { return null; } @@ -83,6 +89,10 @@ public function refactor(Node $node): ?Node return null; } + if ($this->isClassHasChildren($class)) { + return null; + } + $this->visibilityManipulator->makeFinal($node); return $node; } @@ -91,4 +101,20 @@ public function provideMinPhpVersion(): int { return PhpVersionFeature::FINAL_CLASS_CONSTANTS; } + + private function isClassHasChildren(Class_ $class): bool + { + if ($this->classAnalyzer->isAnonymousClass($class)) { + return false; + } + + $className = (string) $this->nodeNameResolver->getName($class); + if (! $this->reflectionProvider->hasClass($className)) { + return false; + } + + $classReflection = $this->reflectionProvider->getClass($className); + + return $this->familyRelationsAnalyzer->getChildrenOfClassReflection($classReflection) !== []; + } }