Skip to content

Commit

Permalink
move check to ForbiddenPropertyRemovalAnalyzer service
Browse files Browse the repository at this point in the history
  • Loading branch information
samsonasik committed Nov 12, 2021
1 parent 098b6c7 commit 12bf694
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 103 deletions.
126 changes: 126 additions & 0 deletions rules/Removing/NodeAnalyzer/ForbiddenPropertyRemovalAnalyzer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

declare(strict_types=1);

namespace Rector\Removing\NodeAnalyzer;

use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Clone_;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Type\ObjectType;
use PHPStan\Type\ThisType;
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;

final class ForbiddenPropertyRemovalAnalyzer
{
public function __construct(
private BetterNodeFinder $betterNodeFinder,
private NodeComparator $nodeComparator,
private NodeNameResolver $nodeNameResolver,
private NodeTypeResolver $nodeTypeResolver,
private PropertyFetchAnalyzer $propertyFetchAnalyzer
) {
}

public function isForbiddenInNewCurrentClassNameSelfClone(string $propertyName, ?ClassLike $classLike): bool
{
if (! $classLike instanceof ClassLike) {
return false;
}

$methods = $classLike->getMethods();
foreach ($methods as $method) {
$isInNewCurrentClassNameSelfClone = (bool) $this->betterNodeFinder->findFirst(
(array) $method->getStmts(),
function (Node $subNode) use ($classLike, $propertyName): bool {
if ($subNode instanceof New_) {
return $this->isPropertyNameUsedAfterNewOrClone($subNode, $classLike, $propertyName);
}

if ($subNode instanceof Clone_) {
return $this->isPropertyNameUsedAfterNewOrClone($subNode, $classLike, $propertyName);
}

return false;
}
);

if ($isInNewCurrentClassNameSelfClone) {
return true;
}
}

return false;
}

private function isPropertyNameUsedAfterNewOrClone(
New_|Clone_ $expr,
ClassLike $classLike,
string $propertyName
): bool {
$parentAssign = $this->betterNodeFinder->findParentType($expr, Assign::class);
if (! $parentAssign instanceof Assign) {
return false;
}

$className = (string) $this->nodeNameResolver->getName($classLike);
$type = $expr instanceof New_
? $this->nodeTypeResolver->getType($expr->class)
: $this->nodeTypeResolver->getType($expr->expr);

if ($expr instanceof Clone_ && $type instanceof ThisType) {
$type = $type->getStaticObjectType();
}

if ($type instanceof ObjectType) {
return $this->isFoundAfterCloneOrNew($type, $expr, $parentAssign, $className, $propertyName);
}

return false;
}

private function isFoundAfterCloneOrNew(
ObjectType $objectType,
Clone_|New_ $expr,
Assign $parentAssign,
string $className,
string $propertyName
): bool {
if ($objectType->getClassName() !== $className) {
return false;
}

return (bool) $this->betterNodeFinder->findFirstNext($expr, function (Node $subNode) use (
$parentAssign,
$propertyName
): bool {
if (! $this->propertyFetchAnalyzer->isPropertyFetch($subNode)) {
return false;
}

/** @var PropertyFetch|StaticPropertyFetch $subNode */
$propertyFetchName = (string) $this->nodeNameResolver->getName($subNode);
if ($subNode instanceof PropertyFetch) {
if (! $this->nodeComparator->areNodesEqual($subNode->var, $parentAssign->var)) {
return false;
}

return $propertyFetchName === $propertyName;
}

if (! $this->nodeComparator->areNodesEqual($subNode->class, $parentAssign->var)) {
return false;
}

return $propertyFetchName === $propertyName;
});
}
}
109 changes: 6 additions & 103 deletions rules/Removing/NodeManipulator/ComplexNodeRemover.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,13 @@

use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Clone_;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PHPStan\Type\ObjectType;
use PHPStan\Type\ThisType;
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder;
Expand All @@ -26,7 +21,7 @@
use Rector\NodeRemoval\AssignRemover;
use Rector\NodeRemoval\NodeRemover;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\Removing\NodeAnalyzer\ForbiddenPropertyRemovalAnalyzer;

final class ComplexNodeRemover
{
Expand All @@ -37,8 +32,7 @@ public function __construct(
private BetterNodeFinder $betterNodeFinder,
private NodeRemover $nodeRemover,
private NodeComparator $nodeComparator,
private NodeTypeResolver $nodeTypeResolver,
private PropertyFetchAnalyzer $propertyFetchAnalyzer
private ForbiddenPropertyRemovalAnalyzer $forbiddenPropertyRemovalAnalyzer
) {
}

Expand Down Expand Up @@ -86,100 +80,6 @@ private function processRemovePropertyAssigns(array $assigns): void
}
}

private function isPropertyNameInNewCurrentClassNameSelfClone(string $propertyName, ?ClassLike $classLike): bool
{
if (! $classLike instanceof ClassLike) {
return false;
}

$methods = $classLike->getMethods();
foreach ($methods as $method) {
$isInNewCurrentClassNameSelfClone = (bool) $this->betterNodeFinder->findFirst(
(array) $method->getStmts(),
function (Node $subNode) use ($classLike, $propertyName): bool {
if ($subNode instanceof New_) {
return $this->isPropertyNameUsedAfterNewOrClone($subNode, $classLike, $propertyName);
}

if ($subNode instanceof Clone_) {
return $this->isPropertyNameUsedAfterNewOrClone($subNode, $classLike, $propertyName);
}

return false;
}
);

if ($isInNewCurrentClassNameSelfClone) {
return true;
}
}

return false;
}

private function isFoundAfterCloneOrNew(
ObjectType $objectType,
Clone_|New_ $expr,
Assign $parentAssign,
string $className,
string $propertyName
): bool {
if ($objectType->getClassName() !== $className) {
return false;
}

return (bool) $this->betterNodeFinder->findFirstNext($expr, function (Node $subNode) use (
$parentAssign,
$propertyName
): bool {
if (! $this->propertyFetchAnalyzer->isPropertyFetch($subNode)) {
return false;
}

/** @var PropertyFetch|StaticPropertyFetch $subNode */
$propertyFetchName = (string) $this->nodeNameResolver->getName($subNode);
if ($subNode instanceof PropertyFetch) {
if (! $this->nodeComparator->areNodesEqual($subNode->var, $parentAssign->var)) {
return false;
}

return $propertyFetchName === $propertyName;
}

if (! $this->nodeComparator->areNodesEqual($subNode->class, $parentAssign->var)) {
return false;
}

return $propertyFetchName === $propertyName;
});
}

private function isPropertyNameUsedAfterNewOrClone(
New_|Clone_ $expr,
ClassLike $classLike,
string $propertyName
): bool {
$parentAssign = $this->betterNodeFinder->findParentType($expr, Assign::class);
if (! $parentAssign instanceof Assign) {
return false;
}

$className = (string) $this->nodeNameResolver->getName($classLike);
$type = $expr instanceof New_
? $this->nodeTypeResolver->getType($expr->class)
: $this->nodeTypeResolver->getType($expr->expr);

if ($expr instanceof Clone_ && $type instanceof ThisType) {
$type = $type->getStaticObjectType();
}

if ($type instanceof ObjectType) {
return $this->isFoundAfterCloneOrNew($type, $expr, $parentAssign, $className, $propertyName);
}

return false;
}

/**
* @param string[] $classMethodNamesToSkip
*/
Expand Down Expand Up @@ -220,7 +120,10 @@ private function resolveAssign(PropertyFetch | StaticPropertyFetch $expr): ?Assi
$classLike = $this->betterNodeFinder->findParentType($expr, ClassLike::class);
$propertyName = (string) $this->nodeNameResolver->getName($expr);

if ($this->isPropertyNameInNewCurrentClassNameSelfClone($propertyName, $classLike)) {
if ($this->forbiddenPropertyRemovalAnalyzer->isForbiddenInNewCurrentClassNameSelfClone(
$propertyName,
$classLike
)) {
return null;
}

Expand Down

0 comments on commit 12bf694

Please sign in to comment.