2019-11-05 16:33:38 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
2020-02-06 22:48:18 +01:00
|
|
|
namespace Rector\Core\Rector\AbstractRector;
|
2019-11-05 16:33:38 +01:00
|
|
|
|
|
|
|
use PhpParser\Node;
|
|
|
|
use PhpParser\Node\Expr;
|
|
|
|
use PhpParser\Node\Expr\Assign;
|
|
|
|
use PhpParser\Node\Expr\PropertyFetch;
|
|
|
|
use PhpParser\Node\Expr\StaticPropertyFetch;
|
2020-03-26 22:57:56 +01:00
|
|
|
use PhpParser\Node\Stmt\Class_;
|
2019-11-05 16:33:38 +01:00
|
|
|
use PhpParser\Node\Stmt\ClassMethod;
|
|
|
|
use PhpParser\Node\Stmt\Property;
|
2020-02-06 22:48:18 +01:00
|
|
|
use Rector\Core\Exception\ShouldNotHappenException;
|
|
|
|
use Rector\Core\PhpParser\Node\Manipulator\PropertyManipulator;
|
2020-03-26 22:57:56 +01:00
|
|
|
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
|
2020-07-30 01:39:41 +02:00
|
|
|
use Rector\Core\ValueObject\MethodName;
|
2020-02-09 12:31:31 +01:00
|
|
|
use Rector\DeadCode\NodeManipulator\LivingCodeManipulator;
|
2020-02-10 10:05:15 +01:00
|
|
|
use Rector\NodeCollector\NodeCollector\ParsedNodeCollector;
|
2020-11-16 17:50:38 +00:00
|
|
|
use Rector\NodeRemoval\AssignRemover;
|
|
|
|
use Rector\NodeRemoval\ClassMethodRemover;
|
2019-11-05 16:33:38 +01:00
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
2020-03-31 18:39:08 +02:00
|
|
|
use Rector\PostRector\Collector\NodesToRemoveCollector;
|
2019-11-05 16:33:38 +01:00
|
|
|
|
|
|
|
/**
|
2020-02-09 12:31:31 +01:00
|
|
|
* Located in another trait ↓
|
2020-03-31 18:39:08 +02:00
|
|
|
* @property NodesToRemoveCollector $nodesToRemoveCollector
|
2019-11-05 16:33:38 +01:00
|
|
|
*/
|
|
|
|
trait ComplexRemovalTrait
|
|
|
|
{
|
|
|
|
/**
|
2020-02-09 11:05:37 +01:00
|
|
|
* @var ParsedNodeCollector
|
2019-11-05 16:33:38 +01:00
|
|
|
*/
|
2020-02-09 11:05:37 +01:00
|
|
|
protected $parsedNodeCollector;
|
2019-11-05 16:33:38 +01:00
|
|
|
|
2020-02-09 12:31:31 +01:00
|
|
|
/**
|
|
|
|
* @var LivingCodeManipulator
|
|
|
|
*/
|
|
|
|
protected $livingCodeManipulator;
|
|
|
|
|
2020-03-26 22:57:56 +01:00
|
|
|
/**
|
|
|
|
* @var BetterStandardPrinter
|
|
|
|
*/
|
|
|
|
protected $betterStandardPrinter;
|
|
|
|
|
2019-11-05 16:33:38 +01:00
|
|
|
/**
|
2020-02-09 11:05:37 +01:00
|
|
|
* @var PropertyManipulator
|
2019-11-05 16:33:38 +01:00
|
|
|
*/
|
2020-02-09 11:05:37 +01:00
|
|
|
private $propertyManipulator;
|
2019-11-05 16:33:38 +01:00
|
|
|
|
2020-11-16 17:50:38 +00:00
|
|
|
/**
|
|
|
|
* @var ClassMethodRemover
|
|
|
|
*/
|
|
|
|
private $classMethodRemover;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var AssignRemover
|
|
|
|
*/
|
|
|
|
private $assignRemover;
|
|
|
|
|
2019-11-05 16:33:38 +01:00
|
|
|
/**
|
|
|
|
* @required
|
|
|
|
*/
|
2020-10-02 17:29:18 +07:00
|
|
|
public function autowireComplexRemovalTrait(
|
2019-11-09 00:12:44 +01:00
|
|
|
PropertyManipulator $propertyManipulator,
|
2020-02-09 11:05:37 +01:00
|
|
|
ParsedNodeCollector $parsedNodeCollector,
|
2020-03-26 22:57:56 +01:00
|
|
|
LivingCodeManipulator $livingCodeManipulator,
|
2020-11-16 17:50:38 +00:00
|
|
|
BetterStandardPrinter $betterStandardPrinter,
|
|
|
|
ClassMethodRemover $classMethodRemover,
|
|
|
|
AssignRemover $assignRemover
|
2019-11-09 00:12:44 +01:00
|
|
|
): void {
|
2020-02-09 11:05:37 +01:00
|
|
|
$this->parsedNodeCollector = $parsedNodeCollector;
|
2019-11-09 00:12:44 +01:00
|
|
|
$this->propertyManipulator = $propertyManipulator;
|
2020-02-09 12:31:31 +01:00
|
|
|
$this->livingCodeManipulator = $livingCodeManipulator;
|
2020-03-26 22:57:56 +01:00
|
|
|
$this->betterStandardPrinter = $betterStandardPrinter;
|
2020-11-16 17:50:38 +00:00
|
|
|
$this->classMethodRemover = $classMethodRemover;
|
|
|
|
$this->assignRemover = $assignRemover;
|
2019-11-05 16:33:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function removeClassMethodAndUsages(ClassMethod $classMethod): void
|
|
|
|
{
|
2020-11-16 17:50:38 +00:00
|
|
|
$this->classMethodRemover->removeClassMethodAndUsages($classMethod);
|
2019-11-05 16:33:38 +01:00
|
|
|
}
|
|
|
|
|
2020-02-01 09:57:42 +01:00
|
|
|
/**
|
|
|
|
* @param string[] $classMethodNamesToSkip
|
|
|
|
*/
|
2020-04-29 13:42:11 +02:00
|
|
|
protected function removePropertyAndUsages(Property $property, array $classMethodNamesToSkip = []): void
|
|
|
|
{
|
2020-02-01 09:57:42 +01:00
|
|
|
$shouldKeepProperty = false;
|
|
|
|
|
2020-10-16 21:29:29 +02:00
|
|
|
$propertyFetches = $this->propertyManipulator->getPrivatePropertyFetches($property);
|
2019-11-05 16:33:38 +01:00
|
|
|
foreach ($propertyFetches as $propertyFetch) {
|
2020-02-01 09:57:42 +01:00
|
|
|
if ($this->shouldSkipPropertyForClassMethod($propertyFetch, $classMethodNamesToSkip)) {
|
|
|
|
$shouldKeepProperty = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-03-26 22:57:56 +01:00
|
|
|
// remove assigns
|
2020-02-09 12:31:31 +01:00
|
|
|
$assign = $this->resolveAssign($propertyFetch);
|
2020-11-16 17:50:38 +00:00
|
|
|
$this->assignRemover->removeAssignNode($assign);
|
2020-03-26 22:57:56 +01:00
|
|
|
|
|
|
|
$this->removeConstructorDependency($assign);
|
2019-11-05 16:33:38 +01:00
|
|
|
}
|
|
|
|
|
2020-02-01 09:57:42 +01:00
|
|
|
if ($shouldKeepProperty) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-31 17:20:30 +01:00
|
|
|
// remove __construct param
|
2020-03-26 22:57:56 +01:00
|
|
|
|
2019-11-05 16:33:38 +01:00
|
|
|
/** @var Property $property */
|
2020-04-29 13:42:11 +02:00
|
|
|
$this->removeNode($property);
|
2019-11-05 16:33:38 +01:00
|
|
|
|
|
|
|
foreach ($property->props as $prop) {
|
2020-03-31 18:39:08 +02:00
|
|
|
if (! $this->nodesToRemoveCollector->isNodeRemoved($prop)) {
|
2020-02-09 12:31:31 +01:00
|
|
|
// if the property has at least one node left -> return
|
2019-11-05 16:33:38 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->removeNode($property);
|
|
|
|
}
|
|
|
|
|
2020-02-01 09:57:42 +01:00
|
|
|
/**
|
2020-02-01 10:31:25 +01:00
|
|
|
* @param StaticPropertyFetch|PropertyFetch $expr
|
2020-02-01 09:57:42 +01:00
|
|
|
* @param string[] $classMethodNamesToSkip
|
|
|
|
*/
|
2020-02-01 10:31:25 +01:00
|
|
|
private function shouldSkipPropertyForClassMethod(Expr $expr, array $classMethodNamesToSkip): bool
|
2020-02-01 09:57:42 +01:00
|
|
|
{
|
2020-02-01 10:31:25 +01:00
|
|
|
$classMethodNode = $expr->getAttribute(AttributeKey::METHOD_NODE);
|
2021-01-19 18:24:48 +07:00
|
|
|
if (! $classMethodNode instanceof ClassMethod) {
|
2020-02-01 09:57:42 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$classMethodName = $this->getName($classMethodNode);
|
|
|
|
return in_array($classMethodName, $classMethodNamesToSkip, true);
|
|
|
|
}
|
2020-02-09 12:31:31 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param PropertyFetch|StaticPropertyFetch $expr
|
|
|
|
*/
|
|
|
|
private function resolveAssign(Expr $expr): Assign
|
|
|
|
{
|
|
|
|
$assign = $expr->getAttribute(AttributeKey::PARENT_NODE);
|
|
|
|
|
|
|
|
while ($assign !== null && ! $assign instanceof Assign) {
|
|
|
|
$assign = $assign->getAttribute(AttributeKey::PARENT_NODE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! $assign instanceof Assign) {
|
|
|
|
throw new ShouldNotHappenException("Can't handle this situation");
|
|
|
|
}
|
|
|
|
|
|
|
|
return $assign;
|
|
|
|
}
|
2020-03-26 22:57:56 +01:00
|
|
|
|
|
|
|
private function removeConstructorDependency(Assign $assign): void
|
|
|
|
{
|
|
|
|
$methodName = $assign->getAttribute(AttributeKey::METHOD_NAME);
|
2020-07-30 01:39:41 +02:00
|
|
|
if ($methodName !== MethodName::CONSTRUCT) {
|
2020-03-26 22:57:56 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$class = $assign->getAttribute(AttributeKey::CLASS_NODE);
|
|
|
|
if (! $class instanceof Class_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-30 01:39:41 +02:00
|
|
|
$constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
|
2021-01-14 23:44:07 +01:00
|
|
|
if (! $constructClassMethod instanceof ClassMethod) {
|
2020-03-26 22:57:56 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-11-09 01:22:24 +07:00
|
|
|
$constructClassMethodStmts = $constructClassMethod->stmts;
|
2020-12-20 22:05:48 +01:00
|
|
|
|
2020-03-26 22:57:56 +01:00
|
|
|
foreach ($constructClassMethod->getParams() as $param) {
|
2020-11-09 01:22:24 +07:00
|
|
|
$variable = $this->betterNodeFinder->findFirst($constructClassMethodStmts, function (Node $node) use (
|
|
|
|
$param
|
|
|
|
): bool {
|
|
|
|
return $this->betterStandardPrinter->areNodesEqual($param->var, $node);
|
|
|
|
});
|
|
|
|
|
2020-11-16 17:50:38 +00:00
|
|
|
if ($variable === null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-09 01:22:24 +07:00
|
|
|
if ($this->isExpressionVariableNotAssign($variable)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-03-28 16:27:06 +01:00
|
|
|
if (! $this->betterStandardPrinter->areNodesEqual($param->var, $assign->expr)) {
|
2020-03-26 22:57:56 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->removeNode($param);
|
|
|
|
}
|
|
|
|
}
|
2020-08-16 13:42:22 +02:00
|
|
|
|
2020-11-16 17:50:38 +00:00
|
|
|
private function isExpressionVariableNotAssign(Node $node): bool
|
2020-11-09 01:22:24 +07:00
|
|
|
{
|
|
|
|
if ($node !== null) {
|
|
|
|
$expressionVariable = $node->getAttribute(AttributeKey::PARENT_NODE);
|
|
|
|
|
|
|
|
if (! $expressionVariable instanceof Assign) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2019-11-05 16:33:38 +01:00
|
|
|
}
|