Skip to content

Commit

Permalink
Fix trait property visibility in PrivatizeFinalClassPropertyRector (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Dec 10, 2022
1 parent 91f4cae commit e1f7637
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

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

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

final class SkipTraitReserved
{
use SomeTraitWithProtectedProperty;

protected $value = 100;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);

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

trait SomeTraitWithProtectedProperty
{
protected $value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\TraitUse;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Rector\AbstractRector;
use Rector\Privatization\Guard\ParentPropertyLookupGuard;
use Rector\Privatization\NodeManipulator\VisibilityManipulator;
Expand All @@ -20,7 +22,8 @@ final class PrivatizeFinalClassPropertyRector extends AbstractRector
{
public function __construct(
private readonly VisibilityManipulator $visibilityManipulator,
private readonly ParentPropertyLookupGuard $parentPropertyLookupGuard
private readonly ParentPropertyLookupGuard $parentPropertyLookupGuard,
private readonly ReflectionProvider $reflectionProvider,
) {
}

Expand Down Expand Up @@ -50,42 +53,85 @@ final class SomeClass
*/
public function getNodeTypes(): array
{
return [Property::class];
return [Class_::class];
}

/**
* @param Property $node
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
$classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
if (! $classLike instanceof Class_) {
if (! $node->isFinal()) {
return null;
}

if (! $classLike->isFinal()) {
return null;
}
$traitPropertyNames = $this->resolveTraitPropertyNames($node);

if ($this->shouldSkipProperty($node)) {
return null;
$hasChanged = false;

foreach ($node->getProperties() as $property) {
if ($this->shouldSkipProperty($property, $traitPropertyNames)) {
continue;
}

if (! $this->parentPropertyLookupGuard->isLegal($property)) {
continue;
}

$this->visibilityManipulator->makePrivate($property);
$hasChanged = true;
}

if (! $this->parentPropertyLookupGuard->isLegal($node)) {
return null;
if ($hasChanged) {
return $node;
}

$this->visibilityManipulator->makePrivate($node);
return null;
}

/**
* @return string[]
*/
private function resolveTraitPropertyNames(Class_ $class): array
{
$traitPropertyNames = [];

foreach ($class->stmts as $classStmt) {
if (! $classStmt instanceof TraitUse) {
continue;
}

foreach ($classStmt->traits as $trait) {
$traitName = $this->getName($trait);
if (! $this->reflectionProvider->hasClass($traitName)) {
continue;
}

$traitReflection = $this->reflectionProvider->getClass($traitName);
$nativeTraitReflection = $traitReflection->getNativeReflection();

foreach ($nativeTraitReflection->getProperties() as $propertyReflection) {
$traitPropertyNames[] = $propertyReflection->getName();
}
}
}

return $node;
return $traitPropertyNames;
}

private function shouldSkipProperty(Property $property): bool
/**
* @param string[] $traitPropertyNames
*/
private function shouldSkipProperty(Property $property, array $traitPropertyNames): bool
{
if (count($property->props) !== 1) {
return true;
}

return ! $property->isProtected();
if (! $property->isProtected()) {
return true;
}

return $this->isNames($property, $traitPropertyNames);
}
}

0 comments on commit e1f7637

Please sign in to comment.