mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-18 14:03:41 +01:00
[CodingStyle] Add RemoveUnusedAliasRector
This commit is contained in:
parent
392d444862
commit
3414bd925e
@ -6,3 +6,4 @@ services:
|
|||||||
Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector: ~
|
Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector: ~
|
||||||
Rector\CodingStyle\Rector\FuncCall\ConsistentImplodeRector: ~
|
Rector\CodingStyle\Rector\FuncCall\ConsistentImplodeRector: ~
|
||||||
Rector\CodingStyle\Rector\FuncCall\SetTypeToCastRector: ~
|
Rector\CodingStyle\Rector\FuncCall\SetTypeToCastRector: ~
|
||||||
|
Rector\CodingStyle\Rector\Use_\RemoveUnusedAliasRector: ~
|
||||||
|
159
packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php
Normal file
159
packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\CodingStyle\Rector\Use_;
|
||||||
|
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PhpParser\Node\Param;
|
||||||
|
use PhpParser\Node\Stmt\Namespace_;
|
||||||
|
use PhpParser\Node\Stmt\Use_;
|
||||||
|
use PhpParser\NodeVisitor\NameResolver;
|
||||||
|
use Rector\NodeTypeResolver\Node\Attribute;
|
||||||
|
use Rector\PhpParser\Node\BetterNodeFinder;
|
||||||
|
use Rector\Rector\AbstractRector;
|
||||||
|
use Rector\RectorDefinition\CodeSample;
|
||||||
|
use Rector\RectorDefinition\RectorDefinition;
|
||||||
|
|
||||||
|
final class RemoveUnusedAliasRector extends AbstractRector
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var BetterNodeFinder
|
||||||
|
*/
|
||||||
|
private $betterNodeFinder;
|
||||||
|
|
||||||
|
public function __construct(BetterNodeFinder $betterNodeFinder)
|
||||||
|
{
|
||||||
|
$this->betterNodeFinder = $betterNodeFinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefinition(): RectorDefinition
|
||||||
|
{
|
||||||
|
return new RectorDefinition('Removes unused use aliases', [
|
||||||
|
new CodeSample(
|
||||||
|
<<<'CODE_SAMPLE'
|
||||||
|
use Symfony\Kernel as BaseKernel;
|
||||||
|
|
||||||
|
class SomeClass extends BaseKernel
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CODE_SAMPLE
|
||||||
|
,
|
||||||
|
<<<'CODE_SAMPLE'
|
||||||
|
use Symfony\Kernel;
|
||||||
|
|
||||||
|
class SomeClass extends Kernel
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CODE_SAMPLE
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getNodeTypes(): array
|
||||||
|
{
|
||||||
|
return [Use_::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Use_ $node
|
||||||
|
*/
|
||||||
|
public function refactor(Node $node): ?Node
|
||||||
|
{
|
||||||
|
$parentNode = $node->getAttribute(Attribute::PARENT_NODE);
|
||||||
|
$usedNameNodes = $this->resolveUsedNameNodes($parentNode);
|
||||||
|
if ($usedNameNodes === []) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($node->uses as $use) {
|
||||||
|
if ($use->alias === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastName = $use->name->getLast();
|
||||||
|
$aliasName = $this->getName($use->alias);
|
||||||
|
|
||||||
|
// both are used → nothing to remove
|
||||||
|
if (isset($usedNameNodes[$lastName]) && isset($usedNameNodes[$aliasName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only last name is used → no need for alias
|
||||||
|
if (isset($usedNameNodes[$lastName])) {
|
||||||
|
$use->alias = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only alis name is used → use last name directly
|
||||||
|
if (isset($usedNameNodes[$aliasName])) {
|
||||||
|
$this->renameNameNode($usedNameNodes, $aliasName, $lastName);
|
||||||
|
$use->alias = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Name[][]|Node[][]
|
||||||
|
*/
|
||||||
|
private function resolveUsedNameNodes(Node $parentNode): array
|
||||||
|
{
|
||||||
|
$usedNameNodes = [];
|
||||||
|
|
||||||
|
// assumption for namespaced content
|
||||||
|
if ($parentNode instanceof Namespace_) {
|
||||||
|
/** @var Name[] $namedNodes */
|
||||||
|
$namedNodes = $this->betterNodeFinder->find($parentNode, function (Node $node) {
|
||||||
|
if ($node instanceof Name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach ($namedNodes as $nameNode) {
|
||||||
|
/** node name before becoming FQN - attribute from @see NameResolver */
|
||||||
|
$originalName = $nameNode->getAttribute('originalName');
|
||||||
|
if (! $originalName instanceof Name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$usedNameNodes[$originalName->toString()][] = [
|
||||||
|
$nameNode,
|
||||||
|
$nameNode->getAttribute(Attribute::PARENT_NODE),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $usedNameNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Name[][]|Node[][] $usedNameNodes
|
||||||
|
*/
|
||||||
|
private function renameNameNode(array $usedNameNodes, string $aliasName, string $lastName): void
|
||||||
|
{
|
||||||
|
foreach ($usedNameNodes[$aliasName] as [$usedName, $parentNode]) {
|
||||||
|
foreach ($this->getObjectPublicPropertyNames($parentNode) as $parentNodePropertyName) {
|
||||||
|
if ($parentNode->{$parentNodePropertyName} !== $usedName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parentNode->{$parentNodePropertyName} = new Name($lastName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $node
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
private function getObjectPublicPropertyNames($node): array
|
||||||
|
{
|
||||||
|
return array_keys(get_object_vars($node));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector\Fixture;
|
||||||
|
|
||||||
|
use Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel as BaseKernel;
|
||||||
|
|
||||||
|
class SomeClass extends BaseKernel
|
||||||
|
{
|
||||||
|
public function run(BaseKernel $baseKernel)
|
||||||
|
{
|
||||||
|
$anotherBaseKernel = new BaseKernel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector\Fixture;
|
||||||
|
|
||||||
|
use Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel;
|
||||||
|
|
||||||
|
class SomeClass extends AbstractKernel
|
||||||
|
{
|
||||||
|
public function run(AbstractKernel $baseKernel)
|
||||||
|
{
|
||||||
|
$anotherBaseKernel = new AbstractKernel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector\Fixture;
|
||||||
|
|
||||||
|
use Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel as BaseKernel;
|
||||||
|
use Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector\Source\Another\AbstractKernel;
|
||||||
|
|
||||||
|
class Used extends BaseKernel
|
||||||
|
{
|
||||||
|
public function run(BaseKernel $baseKernel, AbstractKernel $abstractKernel)
|
||||||
|
{
|
||||||
|
$anotherBaseKernel = new BaseKernel();
|
||||||
|
$anotherAbstractKernel = new AbstractKernel();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector;
|
||||||
|
|
||||||
|
use Rector\CodingStyle\Rector\Use_\RemoveUnusedAliasRector;
|
||||||
|
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||||
|
|
||||||
|
final class RemoveUnusedAliasRectorTest extends AbstractRectorTestCase
|
||||||
|
{
|
||||||
|
public function test(): void
|
||||||
|
{
|
||||||
|
$this->doTestFiles([
|
||||||
|
__DIR__ . '/Fixture/fixture.php.inc',
|
||||||
|
__DIR__ . '/Fixture/used.php.inc',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRectorClass(): string
|
||||||
|
{
|
||||||
|
return RemoveUnusedAliasRector::class;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector\Source;
|
||||||
|
|
||||||
|
class AbstractKernel
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\CodingStyle\Tests\Rector\Use_\RemoveUnusedAliasRector\Source\Another;
|
||||||
|
|
||||||
|
class AbstractKernel
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -83,14 +83,17 @@ final class NodeScopeAndMetadataDecorator
|
|||||||
public function decorateNodesFromFile(array $nodes, string $filePath): array
|
public function decorateNodesFromFile(array $nodes, string $filePath): array
|
||||||
{
|
{
|
||||||
$nodeTraverser = new NodeTraverser();
|
$nodeTraverser = new NodeTraverser();
|
||||||
// specially rewrite nodes for PHPStan
|
$nodeTraverser->addVisitor(new NameResolver(null, [
|
||||||
$nodeTraverser->addVisitor(new NameResolver());
|
'preserveOriginalNames' => true,
|
||||||
|
'replaceNodes' => true, // required by PHPStan
|
||||||
|
]));
|
||||||
$nodes = $nodeTraverser->traverse($nodes);
|
$nodes = $nodeTraverser->traverse($nodes);
|
||||||
|
|
||||||
$nodes = $this->nodeScopeResolver->processNodes($nodes, $filePath);
|
$nodes = $this->nodeScopeResolver->processNodes($nodes, $filePath);
|
||||||
|
|
||||||
$nodeTraverser = new NodeTraverser();
|
$nodeTraverser = new NodeTraverser();
|
||||||
$nodeTraverser->addVisitor(new NameResolver(null, [
|
$nodeTraverser->addVisitor(new NameResolver(null, [
|
||||||
|
'preserveOriginalNames' => true,
|
||||||
// this option would override old non-fqn-namespaced nodes otherwise, so it needs to be disabled
|
// this option would override old non-fqn-namespaced nodes otherwise, so it needs to be disabled
|
||||||
'replaceNodes' => false,
|
'replaceNodes' => false,
|
||||||
]));
|
]));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user