decouple FuncCallManipulator

This commit is contained in:
TomasVotruba 2020-03-01 10:13:41 +01:00
parent b611c4aeda
commit 0f8cdacd26
4 changed files with 136 additions and 37 deletions

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\NodeManipulator;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\FunctionLike;
use PhpParser\NodeTraverser;
use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\NodeNameResolver\NodeNameResolver;
final class VariadicFunctionLikeDetector
{
/**
* @var string[]
*/
private const VARIADIC_FUNCTION_NAMES = ['func_get_arg', 'func_get_args', 'func_num_args'];
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
/**
* @var CallableNodeTraverser
*/
private $callableNodeTraverser;
public function __construct(NodeNameResolver $nodeNameResolver, CallableNodeTraverser $callableNodeTraverser)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->callableNodeTraverser = $callableNodeTraverser;
}
public function isVariadic(FunctionLike $functionLike): bool
{
$isVariadic = false;
$this->callableNodeTraverser->traverseNodesWithCallable(
(array) $functionLike->getStmts(),
function (Node $node) use (&$isVariadic) {
if (! $node instanceof FuncCall) {
return null;
}
if (! $this->nodeNameResolver->isNames($node, self::VARIADIC_FUNCTION_NAMES)) {
return null;
}
$isVariadic = true;
return NodeTraverser::STOP_TRAVERSAL;
}
);
return $isVariadic;
}
}

View File

@ -14,6 +14,7 @@ use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\DeadCode\NodeManipulator\MagicMethodDetector;
use Rector\DeadCode\NodeManipulator\VariadicFunctionLikeDetector;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
@ -39,14 +40,21 @@ final class RemoveUnusedParameterRector extends AbstractRector
*/
private $magicMethodDetector;
/**
* @var VariadicFunctionLikeDetector
*/
private $variadicFunctionLikeDetector;
public function __construct(
ClassManipulator $classManipulator,
ClassMethodManipulator $classMethodManipulator,
MagicMethodDetector $magicMethodDetector
MagicMethodDetector $magicMethodDetector,
VariadicFunctionLikeDetector $variadicFunctionLikeDetector
) {
$this->classManipulator = $classManipulator;
$this->classMethodManipulator = $classMethodManipulator;
$this->magicMethodDetector = $magicMethodDetector;
$this->variadicFunctionLikeDetector = $variadicFunctionLikeDetector;
}
public function getDefinition(): RectorDefinition
@ -113,9 +121,12 @@ PHP
foreach ($childrenOfClass as $childClassNode) {
$methodOfChild = $childClassNode->getMethod($methodName);
if ($methodOfChild !== null) {
$this->removeNodes($this->getParameterOverlap($methodOfChild->params, $unusedParameters));
if ($methodOfChild === null) {
continue;
}
$overlappingParameters = $this->getParameterOverlap($methodOfChild->params, $unusedParameters);
$this->removeNodes($overlappingParameters);
}
$this->removeNodes($unusedParameters);
@ -124,7 +135,7 @@ PHP
}
/**
* @param Class_[] $childrenOfClass
* @param Class_[] $childrenOfClass
* @return Param[]
*/
private function getUnusedParameters(ClassMethod $classMethod, string $methodName, array $childrenOfClass): array
@ -136,13 +147,16 @@ PHP
foreach ($childrenOfClass as $childClassNode) {
$methodOfChild = $childClassNode->getMethod($methodName);
if ($methodOfChild !== null) {
$unusedParameters = $this->getParameterOverlap(
$unusedParameters,
$this->resolveUnusedParameters($methodOfChild)
);
if ($methodOfChild === null) {
continue;
}
$unusedParameters = $this->getParameterOverlap(
$unusedParameters,
$this->resolveUnusedParameters($methodOfChild)
);
}
return $unusedParameters;
}
@ -156,8 +170,8 @@ PHP
return array_uintersect(
$parameters1,
$parameters2,
function (Param $a, Param $b): int {
return $this->areNodesEqual($a, $b) ? 0 : 1;
function (Param $firstParam, Param $secondParam): int {
return $this->areNodesWithoutCommentsEqual($firstParam, $secondParam) ? 0 : 1;
}
);
}
@ -195,6 +209,10 @@ PHP
return true;
}
if ($this->variadicFunctionLikeDetector->isVariadic($classMethod)) {
return true;
}
$class = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
// skip interfaces and traits
if (! $class instanceof Class_) {

View File

@ -13,7 +13,6 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
@ -42,22 +41,22 @@ final class ClassMethodManipulator
private $nodeNameResolver;
/**
* @var ValueResolver
* @var FuncCallManipulator
*/
private $valueResolver;
private $funcCallManipulator;
public function __construct(
BetterNodeFinder $betterNodeFinder,
BetterStandardPrinter $betterStandardPrinter,
NodeTypeResolver $nodeTypeResolver,
NodeNameResolver $nodeNameResolver,
ValueResolver $valueResolver
FuncCallManipulator $funcCallManipulator
) {
$this->betterNodeFinder = $betterNodeFinder;
$this->betterStandardPrinter = $betterStandardPrinter;
$this->nodeTypeResolver = $nodeTypeResolver;
$this->nodeNameResolver = $nodeNameResolver;
$this->valueResolver = $valueResolver;
$this->funcCallManipulator = $funcCallManipulator;
}
public function isParameterUsedMethod(Param $param, ClassMethod $classMethod): bool
@ -81,7 +80,7 @@ final class ClassMethodManipulator
return $this->nodeNameResolver->isName($node, 'compact');
});
$arguments = $this->extractArgumentsFromCompactFuncCalls($compactFuncCalls);
$arguments = $this->funcCallManipulator->extractArgumentsFromCompactFuncCalls($compactFuncCalls);
return $this->nodeNameResolver->isNames($param, $arguments);
}
@ -208,26 +207,6 @@ final class ClassMethodManipulator
return null;
}
/**
* @param FuncCall[] $compactFuncCalls
* @return string[]
*/
private function extractArgumentsFromCompactFuncCalls(array $compactFuncCalls): array
{
$arguments = [];
foreach ($compactFuncCalls as $compactFuncCall) {
foreach ($compactFuncCall->args as $arg) {
$value = $this->valueResolver->getValue($arg->value);
if ($value) {
$arguments[] = $value;
}
}
}
return $arguments;
}
private function isMethodInParent(string $class, string $method): bool
{
foreach (class_parents($class) as $parentClass) {

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Rector\Core\PhpParser\Node\Manipulator;
use PhpParser\Node\Expr\FuncCall;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
final class FuncCallManipulator
{
/**
* @var ValueResolver
*/
private $valueResolver;
public function __construct(ValueResolver $valueResolver)
{
$this->valueResolver = $valueResolver;
}
/**
* @param FuncCall[] $compactFuncCalls
* @return string[]
*/
public function extractArgumentsFromCompactFuncCalls(array $compactFuncCalls): array
{
$arguments = [];
foreach ($compactFuncCalls as $compactFuncCall) {
foreach ($compactFuncCall->args as $arg) {
$value = $this->valueResolver->getValue($arg->value);
if ($value === null) {
continue;
}
$arguments[] = $value;
}
}
return $arguments;
}
}