Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/set/privatization/privatization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ services:
Rector\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector: null
Rector\Privatization\Rector\ClassConst\PrivatizeLocalClassConstantRector: null
Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector: null
Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php

declare(strict_types=1);

namespace Rector\Privatization\Rector\ClassMethod;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\NodeTypeResolver\Node\AttributeKey;

/**
* @see \Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\PrivatizeFinalClassMethodRectorTest
*/
final class PrivatizeFinalClassMethodRector extends AbstractRector
{
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change protected class method to private if possible', [
new CodeSample(
<<<'PHP'
final class SomeClass
{
protected function someMethod()
{
}
}
PHP
,
<<<'PHP'
final class SomeClass
{
private function someMethod()
{
}
}
PHP

),
]);
}

/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [ClassMethod::class];
}

/**
* @param ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
$class = $node->getAttribute(AttributeKey::CLASS_NODE);
if (! $class instanceof Class_) {
return null;
}

if (! $class->isFinal()) {
return null;
}

if ($this->shouldSkipClassMethod($node)) {
return null;
}

if ($class->extends === null) {
$this->makePrivate($node);
return $node;
}

if ($this->isClassMethodVisibilityGuardedByParent($node, $class)) {
return null;
}

$this->makePrivate($node);

return $node;
}

private function shouldSkipClassMethod(ClassMethod $classMethod): bool
{
if ($this->isName($classMethod, 'createComponent*')) {
return true;
}

return ! $classMethod->isProtected();
}

private function isClassMethodVisibilityGuardedByParent(ClassMethod $classMethod, Class_ $class): bool
{
if ($class->extends === null) {
return false;
}

$parentClasses = $this->getParentClasses($class);
$propertyName = $this->getName($classMethod);

foreach ($parentClasses as $parentClass) {
if (method_exists($parentClass, $propertyName)) {
return true;
}
}

return false;
}

/**
* @return string[]
*/
private function getParentClasses(Class_ $class): array
{
/** @var string $className */
$className = $this->getName($class);

return class_parents($className);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Fixture;

use Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Source\AbstractClassWithProtectedClassMethod;

final class ChangeParentWithoutCare extends AbstractClassWithProtectedClassMethod
{
protected function getSome()
{
}
}

?>
-----
<?php

namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Fixture;

use Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Source\AbstractClassWithProtectedClassMethod;

final class ChangeParentWithoutCare extends AbstractClassWithProtectedClassMethod
{
private function getSome()
{
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Fixture;

final class SomeClass
{
protected function someMethod()
{
}
}

?>
-----
<?php

namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Fixture;

final class SomeClass
{
private function someMethod()
{
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Fixture;

final class KeepCreateComponent
{
protected function createComponentCrab()
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Fixture;

use Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Source\AbstractClassWithProtectedClassMethod;

final class KeepParentProtected extends AbstractClassWithProtectedClassMethod
{
protected function getName()
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector;

use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector;

final class PrivatizeFinalClassMethodRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $file): void
{
$this->doTestFile($file);
}

public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

protected function getRectorClass(): string
{
return PrivatizeFinalClassMethodRector::class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Source;

abstract class AbstractClassWithProtectedClassMethod
{
protected function getName()
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\Fixture;

use Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\AbstractClassWithProtectedProperty;
use Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\Source\AbstractClassWithProtectedProperty;

final class ChangeParentWithoutCare extends AbstractClassWithProtectedProperty
{
Expand All @@ -15,7 +15,7 @@ final class ChangeParentWithoutCare extends AbstractClassWithProtectedProperty

namespace Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\Fixture;

use Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\AbstractClassWithProtectedProperty;
use Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\Source\AbstractClassWithProtectedProperty;

final class ChangeParentWithoutCare extends AbstractClassWithProtectedProperty
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\Fixture;

use Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\AbstractClassWithProtectedProperty;
use Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\Source\AbstractClassWithProtectedProperty;

final class KeepParentProtected extends AbstractClassWithProtectedProperty
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector;
namespace Rector\Privatization\Tests\Rector\Property\PrivatizeFinalClassPropertyRector\Source;

abstract class AbstractClassWithProtectedProperty
{
Expand Down