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\Array_;
|
|
|
|
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;
|
|
|
|
use PhpParser\Node\Stmt\PropertyProperty;
|
2020-02-06 22:48:18 +01:00
|
|
|
use Rector\Core\Exception\ShouldNotHappenException;
|
|
|
|
use Rector\Core\PhpParser\Node\Commander\NodeRemovingCommander;
|
|
|
|
use Rector\Core\PhpParser\Node\Manipulator\PropertyManipulator;
|
2020-03-26 22:57:56 +01:00
|
|
|
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
|
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;
|
2019-11-05 16:33:38 +01:00
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
|
|
|
|
|
|
|
/**
|
2020-02-09 12:31:31 +01:00
|
|
|
* Located in another trait ↓
|
2019-11-05 16:33:38 +01:00
|
|
|
* @property NodeRemovingCommander $nodeRemovingCommander
|
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,
|
|
|
|
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-02-09 11:05:37 +01:00
|
|
|
$classMethodCalls = $this->functionLikeParsedNodesFinder->findClassMethodCalls($classMethod);
|
2019-11-05 16:33:38 +01:00
|
|
|
foreach ($classMethodCalls as $classMethodCall) {
|
2019-11-09 00:12:44 +01:00
|
|
|
if ($classMethodCall instanceof Array_) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-11-05 16:33:38 +01:00
|
|
|
$this->removeMethodCall($classMethodCall);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-01 09:57:42 +01:00
|
|
|
/**
|
|
|
|
* @param string[] $classMethodNamesToSkip
|
|
|
|
*/
|
|
|
|
protected function removePropertyAndUsages(
|
|
|
|
PropertyProperty $propertyProperty,
|
|
|
|
array $classMethodNamesToSkip = []
|
|
|
|
): void {
|
|
|
|
$shouldKeepProperty = false;
|
|
|
|
|
2019-11-05 16:33:38 +01:00
|
|
|
$propertyFetches = $this->propertyManipulator->getAllPropertyFetch($propertyProperty);
|
|
|
|
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 */
|
|
|
|
$property = $propertyProperty->getAttribute(AttributeKey::PARENT_NODE);
|
|
|
|
$this->removeNode($propertyProperty);
|
|
|
|
|
|
|
|
foreach ($property->props as $prop) {
|
|
|
|
if (! $this->nodeRemovingCommander->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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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->replaceNode($assign, $assign->expr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private function addLivingCodeBeforeNode(Expr $expr, Node $addBeforeThisNode): void
|
|
|
|
{
|
2020-02-09 12:31:31 +01:00
|
|
|
foreach ($this->livingCodeManipulator->keepLivingCodeFromExpr($expr) as $expr) {
|
2019-11-05 16:33:38 +01:00
|
|
|
$this->addNodeBeforeNode(new Expression($expr), $addBeforeThisNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
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
|
|
|
|
|
|
|
private function removeConstructorDependency(Assign $assign): void
|
|
|
|
{
|
|
|
|
$methodName = $assign->getAttribute(AttributeKey::METHOD_NAME);
|
|
|
|
if ($methodName !== '__construct') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$class = $assign->getAttribute(AttributeKey::CLASS_NODE);
|
|
|
|
if (! $class instanceof Class_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var Class_|null $class */
|
|
|
|
$constructClassMethod = $class->getMethod('__construct');
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2019-11-05 16:33:38 +01:00
|
|
|
}
|