diff --git a/rules-tests/Privatization/NodeManipulator/VisibilityManipulatorTest.php b/rules-tests/Privatization/NodeManipulator/VisibilityManipulatorTest.php index 7dbe3df34d1..dc7008b4339 100644 --- a/rules-tests/Privatization/NodeManipulator/VisibilityManipulatorTest.php +++ b/rules-tests/Privatization/NodeManipulator/VisibilityManipulatorTest.php @@ -7,6 +7,7 @@ use PhpParser\Node\Stmt\ClassMethod; use Rector\Privatization\NodeManipulator\VisibilityManipulator; use Rector\Testing\PHPUnit\AbstractLazyTestCase; +use Rector\ValueObject\MethodName; use Rector\ValueObject\Visibility; final class VisibilityManipulatorTest extends AbstractLazyTestCase @@ -21,4 +22,26 @@ public function test(): void $visibilityManipulator->changeNodeVisibility($classMethod, Visibility::PROTECTED); $this->assertSame(Visibility::PROTECTED | Visibility::STATIC, $classMethod->flags); } + + public function testMakePrivateRemovesFinal(): void + { + $visibilityManipulator = $this->make(VisibilityManipulator::class); + + $classMethod = new ClassMethod('run'); + $classMethod->flags = Visibility::PROTECTED | Visibility::FINAL; + + $visibilityManipulator->makePrivate($classMethod); + $this->assertSame(Visibility::PRIVATE, $classMethod->flags); + } + + public function testMakePrivateKeepsFinalOnConstructor(): void + { + $visibilityManipulator = $this->make(VisibilityManipulator::class); + + $classMethod = new ClassMethod(MethodName::CONSTRUCT); + $classMethod->flags = Visibility::PROTECTED | Visibility::FINAL; + + $visibilityManipulator->makePrivate($classMethod); + $this->assertSame(Visibility::PRIVATE | Visibility::FINAL, $classMethod->flags); + } } diff --git a/rules-tests/Privatization/Rector/ClassConst/PrivatizeFinalClassConstantRector/Fixture/remove_final_modifier.php.inc b/rules-tests/Privatization/Rector/ClassConst/PrivatizeFinalClassConstantRector/Fixture/remove_final_modifier.php.inc new file mode 100644 index 00000000000..ccd2f570844 --- /dev/null +++ b/rules-tests/Privatization/Rector/ClassConst/PrivatizeFinalClassConstantRector/Fixture/remove_final_modifier.php.inc @@ -0,0 +1,21 @@ + +----- + diff --git a/rules-tests/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector/Fixture/remove_final_modifier.php.inc b/rules-tests/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector/Fixture/remove_final_modifier.php.inc new file mode 100644 index 00000000000..ad89edcd17b --- /dev/null +++ b/rules-tests/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector/Fixture/remove_final_modifier.php.inc @@ -0,0 +1,25 @@ + +----- + diff --git a/rules-tests/Privatization/Rector/Property/PrivatizeFinalClassPropertyRector/Fixture/remove_final_modifier.php.inc b/rules-tests/Privatization/Rector/Property/PrivatizeFinalClassPropertyRector/Fixture/remove_final_modifier.php.inc new file mode 100644 index 00000000000..8adaa5c80c6 --- /dev/null +++ b/rules-tests/Privatization/Rector/Property/PrivatizeFinalClassPropertyRector/Fixture/remove_final_modifier.php.inc @@ -0,0 +1,21 @@ + +----- + diff --git a/rules-tests/Privatization/Rector/Property/PrivatizeFinalClassPropertyRector/Fixture/remove_final_modifier_promoted_property.php.inc b/rules-tests/Privatization/Rector/Property/PrivatizeFinalClassPropertyRector/Fixture/remove_final_modifier_promoted_property.php.inc new file mode 100644 index 00000000000..44ca97b7e2b --- /dev/null +++ b/rules-tests/Privatization/Rector/Property/PrivatizeFinalClassPropertyRector/Fixture/remove_final_modifier_promoted_property.php.inc @@ -0,0 +1,25 @@ + +----- + diff --git a/rules/CodingStyle/Rector/Use_/SeparateMultiUseImportsRector.php b/rules/CodingStyle/Rector/Use_/SeparateMultiUseImportsRector.php index ad3946c6f4e..01224f9aafa 100644 --- a/rules/CodingStyle/Rector/Use_/SeparateMultiUseImportsRector.php +++ b/rules/CodingStyle/Rector/Use_/SeparateMultiUseImportsRector.php @@ -127,7 +127,7 @@ private function refactorTraitUse(TraitUse $traitUse): ?array } $traitNames = array_map( - static fn (Name $trait): string => $trait->toString(), + static fn (Name $name): string => $name->toString(), $traitUse->traits ); diff --git a/rules/Privatization/NodeManipulator/VisibilityManipulator.php b/rules/Privatization/NodeManipulator/VisibilityManipulator.php index 455583f46a8..a83d600b4da 100644 --- a/rules/Privatization/NodeManipulator/VisibilityManipulator.php +++ b/rules/Privatization/NodeManipulator/VisibilityManipulator.php @@ -10,14 +10,21 @@ use PhpParser\Node\Stmt\ClassConst; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Property; +use Rector\NodeNameResolver\NodeNameResolver; +use Rector\ValueObject\MethodName; use Rector\ValueObject\Visibility; use Webmozart\Assert\Assert; /** * @see \Rector\Tests\Privatization\NodeManipulator\VisibilityManipulatorTest */ -final class VisibilityManipulator +final readonly class VisibilityManipulator { + public function __construct( + private NodeNameResolver $nodeNameResolver + ) { + } + public function hasVisibility(Class_|ClassMethod|Property|ClassConst|Param $node, int $visibility): bool { return (bool) ($node->flags & $visibility); @@ -105,6 +112,13 @@ public function makeProtected(ClassMethod|Property|ClassConst $node): void public function makePrivate(ClassMethod|Property|ClassConst|Param $node): void { $this->replaceVisibilityFlag($node, Visibility::PRIVATE); + + // only constructor can be both private and final + if ($node instanceof ClassMethod && $this->nodeNameResolver->isName($node, MethodName::CONSTRUCT)) { + return; + } + + $node->flags &= ~Modifiers::FINAL; } /**