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\MethodCall;
|
|
|
|
use PhpParser\Node\Expr\PropertyFetch;
|
2019-11-09 00:12:44 +01:00
|
|
|
use PhpParser\Node\Expr\StaticCall;
|
2019-11-05 16:33:38 +01:00
|
|
|
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\Expression;
|
|
|
|
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;
|
|
|
|
use Rector\NodeCollector\NodeFinder\FunctionLikeParsedNodesFinder;
|
2020-03-29 00:06:05 +01:00
|
|
|
use Rector\NodeCollector\ValueObject\ArrayCallable;
|
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
|
2020-02-09 12:31:31 +01:00
|
|
|
* @property FunctionLikeParsedNodesFinder $functionLikeParsedNodesFinder
|
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
|
|
|
|
|
|
|
/**
|
|
|
|
* @required
|
|
|
|
*/
|
2019-11-09 00:12:44 +01:00
|
|
|
public function autowireComplextRemovalTrait(
|
|
|
|
PropertyManipulator $propertyManipulator,
|
2020-02-09 11:05:37 +01:00
|
|
|
ParsedNodeCollector $parsedNodeCollector,
|
2020-03-26 22:57:56 +01:00
|
|
|
LivingCodeManipulator $livingCodeManipulator,
|
2020-09-10 12:24:43 +02:00
|
|
|
BetterStandardPrinter $betterStandardPrinter
|
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;
|
2019-11-05 16:33:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
abstract protected function removeNode(Node $node): void;
|
|
|
|
|
|
|
|
protected function removeClassMethodAndUsages(ClassMethod $classMethod): void
|
|
|
|
{
|
|
|
|
$this->removeNode($classMethod);
|
|
|
|
|
2020-09-10 12:24:43 +02:00
|
|
|
$calls = $this->nodeRepository->findCallsByClassMethod($classMethod);
|
|
|
|
foreach ($calls as $classMethodCall) {
|
2020-03-29 00:06:05 +01:00
|
|
|
if ($classMethodCall instanceof ArrayCallable) {
|
2019-11-09 00:12:44 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-11-05 16:33:38 +01:00
|
|
|
$this->removeMethodCall($classMethodCall);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-04-29 13:42:11 +02:00
|
|
|
$propertyFetches = $this->propertyManipulator->getAllPropertyFetch($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);
|
2019-11-05 16:33:38 +01:00
|
|
|
$this->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-03-26 22:57:56 +01:00
|
|
|
// remove __contruct param
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-11-09 00:12:44 +01:00
|
|
|
* @param MethodCall|StaticCall $node
|
2019-11-05 16:33:38 +01:00
|
|
|
*/
|
|
|
|
private function removeMethodCall(Node $node): void
|
|
|
|
{
|
|
|
|
$currentStatement = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
|
|
|
foreach ($node->args as $arg) {
|
|
|
|
$this->addLivingCodeBeforeNode($arg->value, $currentStatement);
|
|
|
|
}
|
|
|
|
$this->removeNode($node);
|
|
|
|
}
|
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
|
|
|
/** @var ClassMethod|null $classMethodNode */
|
|
|
|
$classMethodNode = $expr->getAttribute(AttributeKey::METHOD_NODE);
|
2020-02-01 09:57:42 +01:00
|
|
|
if ($classMethodNode === null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$classMethodName = $this->getName($classMethodNode);
|
|
|
|
if ($classMethodName === null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2020-08-16 13:42:22 +02:00
|
|
|
private function removeAssignNode(Assign $assign): void
|
|
|
|
{
|
|
|
|
$currentStatement = $assign->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
|
|
|
$this->addLivingCodeBeforeNode($assign->var, $currentStatement);
|
|
|
|
|
|
|
|
/** @var Assign $assign */
|
|
|
|
$parent = $assign->getAttribute(AttributeKey::PARENT_NODE);
|
|
|
|
if ($parent instanceof Expression) {
|
|
|
|
$this->addLivingCodeBeforeNode($assign->expr, $currentStatement);
|
|
|
|
$this->removeNode($assign);
|
|
|
|
} else {
|
|
|
|
$this->nodesToReplaceCollector->addReplaceNodeWithAnotherNode($assign, $assign->expr);
|
|
|
|
$this->rectorChangeCollector->notifyNodeFileInfo($assign->expr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var Class_|null $class */
|
2020-07-30 01:39:41 +02:00
|
|
|
$constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
|
2020-03-26 22:57:56 +01:00
|
|
|
if ($constructClassMethod === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($constructClassMethod->getParams() as $param) {
|
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
|
|
|
|
|
|
|
private function addLivingCodeBeforeNode(Expr $expr, Node $addBeforeThisNode): void
|
|
|
|
{
|
|
|
|
foreach ($this->livingCodeManipulator->keepLivingCodeFromExpr($expr) as $expr) {
|
|
|
|
$this->addNodeBeforeNode(new Expression($expr), $addBeforeThisNode);
|
|
|
|
}
|
|
|
|
}
|
2019-11-05 16:33:38 +01:00
|
|
|
}
|