[DeadCode] Fix RemoveUnusedPrivateMethodRector for self call

This commit is contained in:
Tomas Votruba 2019-04-26 09:57:36 +02:00
parent e2134fedb4
commit 860853dc93
5 changed files with 76 additions and 37 deletions

View File

@ -4,7 +4,7 @@ namespace Rector\DeadCode\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\PhpParser\Node\Manipulator\ClassMethodManipulator;
use Rector\NodeContainer\ParsedNodesByType;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
@ -12,13 +12,13 @@ use Rector\RectorDefinition\RectorDefinition;
final class RemoveUnusedPrivateMethodRector extends AbstractRector
{
/**
* @var ClassMethodManipulator
* @var ParsedNodesByType
*/
private $classMethodManipulator;
private $parsedNodesByType;
public function __construct(ClassMethodManipulator $classMethodManipulator)
public function __construct(ParsedNodesByType $parsedNodesByType)
{
$this->classMethodManipulator = $classMethodManipulator;
$this->parsedNodesByType = $parsedNodesByType;
}
public function getDefinition(): RectorDefinition
@ -74,7 +74,7 @@ CODE_SAMPLE
return null;
}
$classMethodCalls = $this->classMethodManipulator->getAllClassMethodCall($node);
$classMethodCalls = $this->parsedNodesByType->findClassMethodCalls($node);
if ($classMethodCalls === []) {
$this->removeNode($node);
}

View File

@ -0,0 +1,19 @@
<?php
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveUnusedPrivateMethodRector\Fixture;
/**
* @see https://3v4l.org/IsSHq
*/
class Customer
{
private $id;
public static function create($id){
$customer = new self();
$customer->setId($id);
return $customer;
}
private function setId($id){
$this->id=$id;
}
}

View File

@ -12,8 +12,10 @@ final class RemoveUnusedPrivateMethodRectorTest extends AbstractRectorTestCase
$this->doTestFiles([
__DIR__ . '/Fixture/fixture.php.inc',
__DIR__ . '/Fixture/static_method.php.inc',
__DIR__ . '/Fixture/keep_anonymous.php.inc',
__DIR__ . '/Fixture/private_constructor.php.inc',
// skip
__DIR__ . '/Fixture/keep_anonymous.php.inc',
__DIR__ . '/Fixture/skip_local_called.php.inc',
]);
}

View File

@ -5,6 +5,7 @@ namespace Rector\NodeContainer;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Class_;
@ -40,6 +41,7 @@ final class ParsedNodesByType
// simply collected
New_::class,
StaticCall::class,
MethodCall::class,
];
/**
@ -77,6 +79,11 @@ final class ParsedNodesByType
*/
private $simpleParsedNodesByType = [];
/**
* @var mixed[]
*/
private $methodsCallsByTypeAndMethod = [];
public function __construct(NameResolver $nameResolver)
{
$this->nameResolver = $nameResolver;
@ -377,11 +384,34 @@ final class ParsedNodesByType
return;
}
if ($node instanceof MethodCall || $node instanceof StaticCall) {
$this->addCall($node);
return;
}
// simple collect
$type = get_class($node);
$this->simpleParsedNodesByType[$type][] = $node;
}
/**
* @return MethodCall[]
*/
public function findClassMethodCalls(ClassMethod $classMethod): array
{
$className = $classMethod->getAttribute(AttributeKey::CLASS_NAME);
if ($className === null) { // anonymous
return [];
}
$methodName = $this->nameResolver->resolve($classMethod);
if ($methodName === null) {
return [];
}
return $this->methodsCallsByTypeAndMethod[$className][$methodName] ?? [];
}
private function addClass(Class_ $classNode): void
{
if ($this->isClassAnonymous($classNode)) {
@ -489,4 +519,22 @@ final class ParsedNodesByType
// PHPStan polution
return Strings::startsWith($classNode->name->toString(), 'AnonymousClass');
}
/**
* @param MethodCall|StaticCall $node
*/
private function addCall(Node $node): void
{
$className = $this->nodeTypeResolver->resolve($node)[0] ?? null;
if ($className === null) { // anonymous
return;
}
$methodName = $this->nameResolver->resolve($node);
if ($methodName === null) {
return;
}
$this->methodsCallsByTypeAndMethod[$className][$methodName][] = $node;
}
}

View File

@ -4,8 +4,6 @@ namespace Rector\PhpParser\Node\Manipulator;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
@ -163,34 +161,6 @@ final class ClassMethodManipulator
});
}
/**
* @return MethodCall[]
*/
public function getAllClassMethodCall(ClassMethod $classMethod): array
{
$classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
if ($classNode === null) {
return [];
}
return $this->betterNodeFinder->find($classNode, function (Node $node) use ($classMethod) {
// itself
if ($this->betterStandardPrinter->areNodesEqual($node, $classMethod)) {
return false;
}
// is it the name match?
if ($this->nameResolver->resolve($node) !== $this->nameResolver->resolve($classMethod)) {
return false;
}
if ($node instanceof MethodCall && $this->nameResolver->isName($node->var, 'this')) {
return true;
}
return $node instanceof StaticCall && $this->nameResolver->isNames($node->class, ['self', 'static']);
});
}
/**
* @param string[] $possibleNames
*/