[CodingStyle] Deprecate RemoveUnusedAliasRector, job rather for coding standard tool and opinonated (#1157)

This commit is contained in:
Tomas Votruba 2021-11-05 15:19:53 +01:00 committed by GitHub
parent 0c3527ebd8
commit 49aa15dbfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 22 additions and 1651 deletions

View File

@ -12,7 +12,7 @@
- [CodeQuality](#codequality) (69)
- [CodingStyle](#codingstyle) (39)
- [CodingStyle](#codingstyle) (38)
- [Composer](#composer) (6)
@ -76,7 +76,7 @@
- [Php80](#php80) (17)
- [Php81](#php81) (5)
- [Php81](#php81) (6)
- [PhpSpecToPHPUnit](#phpspectophpunit) (7)
@ -2352,24 +2352,6 @@ Non-magic PHP object methods cannot start with "__"
<br>
### RemoveUnusedAliasRector
Removes unused use aliases. Keep annotation aliases like "Doctrine\ORM\Mapping as ORM" to keep convention format
- class: [`Rector\CodingStyle\Rector\Use_\RemoveUnusedAliasRector`](../rules/CodingStyle/Rector/Use_/RemoveUnusedAliasRector.php)
```diff
-use Symfony\Kernel as BaseKernel;
+use Symfony\Kernel;
-class SomeClass extends BaseKernel
+class SomeClass extends Kernel
{
}
```
<br>
### ReturnArrayClassMethodToYieldRector
Turns array return to yield return in specific type and method
@ -8025,6 +8007,26 @@ Refactor MyCLabs enum fetch to Enum const
<br>
### Php81ResourceReturnToObjectRector
Change `is_resource()` to instanceof Object
- class: [`Rector\Php81\Rector\FuncCall\Php81ResourceReturnToObjectRector`](../rules/Php81/Rector/FuncCall/Php81ResourceReturnToObjectRector.php)
```diff
class SomeClass
{
public function run()
{
$f = finfo_open();
- is_resource($f);
+ $f instanceof \finfo;
}
}
```
<br>
### ReadOnlyPropertyRector
Decorate read-only property with `readonly` attribute

View File

@ -30,7 +30,6 @@ use Rector\CodingStyle\Rector\String_\SplitStringClassConstantToClassConstFetchR
use Rector\CodingStyle\Rector\String_\SymplifyQuoteEscapeRector;
use Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector;
use Rector\CodingStyle\Rector\Ternary\TernaryConditionVariableAssignmentRector;
use Rector\CodingStyle\Rector\Use_\RemoveUnusedAliasRector;
use Rector\CodingStyle\Rector\Use_\SeparateMultiUseImportsRector;
use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
use Rector\Transform\Rector\FuncCall\FuncCallToConstFetchRector;
@ -43,7 +42,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(BinarySwitchToIfElseRector::class);
$services->set(ConsistentImplodeRector::class);
$services->set(TernaryConditionVariableAssignmentRector::class);
$services->set(RemoveUnusedAliasRector::class);
$services->set(SymplifyQuoteEscapeRector::class);
$services->set(SplitGroupedConstantsAndPropertiesRector::class);
$services->set(SplitStringClassConstantToClassConstFetchRector::class);

View File

@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\NameImporting\NodeAnalyzer\UseAnalyzer\Fixture;
use Rector\Tests\NameImporting\NodeAnalyzer\UseAnalyzer\Source\FirstUsage;
final class SomeUses
{
public function run()
{
return new FirstUsage();
}
}

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\NameImporting\NodeAnalyzer\UseAnalyzer\Fixture;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\UnionType as PhpParserUnionType;
final class UnionAliasImports
{
public function param(String_ | PhpParserUnionType $node)
{
}
}

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\NameImporting\NodeAnalyzer\UseAnalyzer\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractInterface as BaseInterface;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel as BaseKernel;
class SomeClass extends BaseKernel implements BaseInterface
{
public function run(BaseKernel $baseKernel): BaseInterface
{
$anotherBaseKernel = new BaseKernel();
}
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\NameImporting\NodeAnalyzer\UseAnalyzer\Source;
final class FirstUsage
{
}

View File

@ -1,124 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\NameImporting\NodeAnalyzer\UseAnalyzer;
use Iterator;
use PhpParser\Node;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\UseUse;
use PhpParser\Node\UnionType;
use Rector\NameImporting\NodeAnalyzer\UseAnalyzer;
use Rector\NameImporting\ValueObject\NameAndParent;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Rector\Testing\TestingParser\TestingParser;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel;
use Rector\Tests\NameImporting\NodeAnalyzer\UseAnalyzer\Source\FirstUsage;
final class UseAnalyzerTest extends AbstractTestCase
{
private UseAnalyzer $useAnalyzer;
private TestingParser $testingParser;
protected function setUp(): void
{
$this->boot();
$this->useAnalyzer = $this->getService(UseAnalyzer::class);
$this->testingParser = $this->getService(TestingParser::class);
}
/**
* @dataProvider provideData()
*
* @param class-string<Node> $parentNodeType
* @param Identifier|FullyQualified $expectedNameNode
*/
public function test(
string $filePath,
string $expectedShortName,
int $position,
Name|Identifier $expectedNameNode,
string $parentNodeType
): void {
$file = $this->testingParser->parseFilePathToFile($filePath);
$firstStmt = $file->getOldStmts()[1];
$namesAndParents = $this->useAnalyzer->resolveUsedNameNodes($firstStmt);
$this->assertArrayHasKey($position, $namesAndParents);
$nameAndParent = $namesAndParents[$position];
$this->assertInstanceOf(NameAndParent::class, $nameAndParent);
$this->assertTrue($nameAndParent->matchShortName($expectedShortName));
// remove attributes for compare
$nameNode = $nameAndParent->getNameNode();
$nameNode->setAttributes([]);
$this->assertEquals($expectedNameNode, $nameNode);
$this->assertInstanceOf($parentNodeType, $nameAndParent->getParentNode());
}
public function provideData(): Iterator
{
yield [
__DIR__ . '/Fixture/some_uses.php.inc',
'FirstUsage',
0,
new FullyQualified(FirstUsage::class),
New_::class,
];
yield [__DIR__ . '/Fixture/some_uses.php.inc', 'SomeUses', 1, new Identifier('SomeUses'), Class_::class];
yield [
__DIR__ . '/Fixture/use_import.php.inc',
'BaseKernel',
4,
new FullyQualified(AbstractKernel::class),
New_::class,
];
yield [
__DIR__ . '/Fixture/use_import.php.inc',
'BaseInterface',
6,
new Identifier('BaseInterface'),
UseUse::class,
];
yield [
__DIR__ . '/Fixture/use_import.php.inc',
'BaseKernel',
7,
new Identifier('BaseKernel'),
UseUse::class,
];
yield [__DIR__ . '/Fixture/use_import.php.inc', 'SomeClass', 5, new Identifier('SomeClass'), Class_::class];
yield [
__DIR__ . '/Fixture/union_alias_imports.php.inc',
'String_',
0,
new FullyQualified(String_::class),
UnionType::class,
];
yield [
__DIR__ . '/Fixture/union_alias_imports.php.inc',
'PhpParserUnionType',
3,
new Identifier('PhpParserUnionType'),
UseUse::class,
];
}
}

View File

@ -1,119 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\NameImporting\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\UseUse;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NameImporting\ValueObject\NameAndParent;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @see \Rector\Tests\NameImporting\NodeAnalyzer\UseAnalyzer\UseAnalyzerTest
*/
final class UseAnalyzer
{
public function __construct(
private BetterNodeFinder $betterNodeFinder,
private NodeNameResolver $nodeNameResolver
) {
}
/**
* @return NameAndParent[]
*/
public function resolveUsedNameNodes(Node $node): array
{
$usedNames = $this->resolveUsedNames($node);
$usedClassNames = $this->resolveUsedClassNames($node);
$usedTraitNames = $this->resolveTraitUseNames($node);
return array_merge($usedNames, $usedClassNames, $usedTraitNames);
}
/**
* @return NameAndParent[]
*/
private function resolveUsedNames(Node $node): array
{
$namesAndParents = [];
/** @var Name[] $names */
$names = $this->betterNodeFinder->findInstanceOf($node, Name::class);
foreach ($names as $name) {
/** node name before becoming FQN - attribute from @see NameResolver */
$originalName = $name->getAttribute(AttributeKey::ORIGINAL_NAME);
if (! $originalName instanceof Name) {
continue;
}
$parentNode = $name->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentNode instanceof Node) {
throw new ShouldNotHappenException();
}
$shortName = $originalName->toString();
$namesAndParents[] = new NameAndParent($shortName, $name, $parentNode);
}
return $namesAndParents;
}
/**
* @return NameAndParent[]
*/
private function resolveUsedClassNames(Node $node): array
{
$namesAndParents = [];
/** @var ClassLike[] $classLikes */
$classLikes = $this->betterNodeFinder->findClassLikes($node);
foreach ($classLikes as $classLike) {
$classLikeName = $classLike->name;
if (! $classLikeName instanceof Identifier) {
continue;
}
$name = $this->nodeNameResolver->getName($classLikeName);
if (! is_string($name)) {
continue;
}
$namesAndParents[] = new NameAndParent($name, $classLikeName, $classLike);
}
return $namesAndParents;
}
/**
* @return NameAndParent[]
*/
private function resolveTraitUseNames(Node $node): array
{
$namesAndParents = [];
/** @var Identifier[] $identifiers */
$identifiers = $this->betterNodeFinder->findInstanceOf($node, Identifier::class);
foreach ($identifiers as $identifier) {
$parentNode = $identifier->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentNode instanceof UseUse) {
continue;
}
$shortName = $identifier->name;
$namesAndParents[] = new NameAndParent($shortName, $identifier, $parentNode);
}
return $namesAndParents;
}
}

View File

@ -1,37 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\NameImporting\ValueObject;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
final class NameAndParent
{
/**
* @param Name|Identifier $nameNode
*/
public function __construct(
private string $shortName,
private Node $nameNode,
private Node $parentNode
) {
}
public function getNameNode(): Identifier | Name
{
return $this->nameNode;
}
public function getParentNode(): Node
{
return $this->parentNode;
}
public function matchShortName(string $desiredShortName): bool
{
return strtolower($this->shortName) === strtolower($desiredShortName);
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractInterface as BaseInterface;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel as BaseKernel;
class SomeClass extends BaseKernel implements BaseInterface
{
public function run(BaseKernel $baseKernel): BaseInterface
{
$anotherBaseKernel = new BaseKernel();
}
}
?>
-----
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractInterface;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel;
class SomeClass extends AbstractKernel implements AbstractInterface
{
public function run(AbstractKernel $baseKernel): AbstractInterface
{
$anotherBaseKernel = new AbstractKernel();
}
}
?>

View File

@ -1,31 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AliasedStaticCall as CallOnMe;
class HandleStaticCall
{
public function run()
{
CallOnMe::someCall();
}
}
?>
-----
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AliasedStaticCall;
class HandleStaticCall
{
public function run()
{
AliasedStaticCall::someCall();
}
}
?>

View File

@ -1,23 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractInterface as NotNeededAliasInterface;
interface BasicInterface extends NotNeededAliasInterface
{
}
?>
-----
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractInterface;
interface BasicInterface extends AbstractInterface
{
}
?>

View File

@ -1,19 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Nette\Utils\Finder as NetteFinder;
use Symfony\Component\Finder\Finder as SymfonyFinder;
final class KeepNetteSymfonyFinder
{
public function nette()
{
return new NetteFinder();
}
public function symfony()
{
return new SymfonyFinder();
}
}

View File

@ -1,17 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use SplFileInfo as NativeSplFileInfo;
use Symfony\Component\Finder\SplFileInfo;
final class KeepUsedDocParam
{
/**
* @param SplFileInfo $type
*/
public function run($type): void
{
$splFileInfo = new NativeSplFileInfo('tests/Posts/Year2018/Exceptions/Source/some_file.txt');
}
}

View File

@ -1,17 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use SplFileInfo as NativeSplFileInfo;
use Symfony\Component\Finder\SplFileInfo;
final class KeepUsedSplFileInfo
{
public function testSplFileInfo(): void
{
$splFileInfo = new NativeSplFileInfo('tests/Posts/Year2018/Exceptions/Source/some_file.txt');
/** @var SplFileInfo $file */
$file = array_pop($files);
}
}

View File

@ -1,31 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel as BaseKernel;
class SomeClass
{
public function run(?BaseKernel $baseKernel)
{
$anotherBaseKernel = $baseKernel ?? new BaseKernel();
}
}
?>
-----
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel;
class SomeClass
{
public function run(?AbstractKernel $baseKernel)
{
$anotherBaseKernel = $baseKernel ?? new AbstractKernel();
}
}
?>

View File

@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\DifferentNamespace as Foo;
class SkipAliasAsUsedNamespace
{
public function run()
{
$foo = new Foo\StandaloneClass();
}
}
?>

View File

@ -1,9 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\StandaloneClass as BaseKernel;
class StandaloneClass extends BaseKernel
{
}

View File

@ -1,15 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use \Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\StandaloneClass as FirstStandalone;
use \Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\DifferentNamespace\StandaloneClass as SecondStandalone;
class DifferentNamespacesSameClass
{
public function run()
{
$firstStandalone = new FirstStandalone;
$secondStandalone = new SecondStandalone;
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use PhpParser\Node\Const_;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Const_ as ConstStmt;
$consts = [new Const_('CONSTANT_IN_CLASS', new String_('default value'))];
return new ConstStmt($consts);

View File

@ -1,9 +0,0 @@
<?php
use PhpParser\Node\Const_;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Const_ as ConstStmt;
$consts = [new Const_('CONSTANT_IN_CLASS', new String_('default value'))];
return new ConstStmt($consts);

View File

@ -1,13 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\Mapping as ORM;
class SkipDocBlock
{
/**
* @ORM\Id
*/
protected $id;
}

View File

@ -1,19 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use DateTime as PhpDateTime;
use DateTimeImmutable as PhpDateTimeImmutable;
class SkipDocBlockUniontype
{
/**
* @var PhpDateTime|bool
*/
protected $b;
/**
* @var PhpDateTimeImmutable
*/
protected $a;
}

View File

@ -1,23 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use App\Bar as BarAlias;
use App\Foo\Bar;
use App\NoAlias;
class SkipHasConflictClassConstant
{
private $classMap = [
BarAlias::class => 'bar',
NoAlias::class => 'noalias',
];
public function run()
{
Bar::execute();
Bar::DATA;
}
}
?>

View File

@ -1,26 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Nette\Utils\FileSystem as NetteFileSystem;
use Symfony\Component\Filesystem\Filesystem;
use Symplify\ConsoleColorDiff\Console\Output\ConsoleDiffer;
final class SkipNetteSymfonyFilesystemAlias
{
/**
* @var Filesystem
*/
private $filesystem;
public function __construct(Filesystem $filesystem, ConsoleDiffer $consoleDiffer)
{
$this->filesystem = $filesystem;
}
public function fixComposerJson(string $composerJsonFile): void
{
$fileContent = NetteFileSystem::read($composerJsonFile);
$this->filesystem->dumpFile($composerJsonFile, '...');
}
}

View File

@ -1,7 +0,0 @@
<?php
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\StandaloneClass as BaseKernel;
class StandaloneClass extends BaseKernel
{
}

View File

@ -1,14 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\StandaloneClass;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\DifferentNamespace\StandaloneClass as StandaloneClassDifferentNamespace;
class SkipSameClassInUseStatementNotUsed
{
public function run()
{
return new StandaloneClassDifferentNamespace();
}
}

View File

@ -1,10 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\StandaloneTrait as DuplicatedStandaloneTrait;
trait StandaloneTrait
{
use DuplicatedStandaloneTrait;
}

View File

@ -1,15 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel as BaseKernel;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\Another\AbstractKernel;
class SkipUsed extends BaseKernel
{
public function run(BaseKernel $baseKernel, AbstractKernel $abstractKernel)
{
$anotherBaseKernel = new BaseKernel();
$anotherAbstractKernel = new AbstractKernel();
}
}

View File

@ -1,26 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @ORM\Table()
* @ORM\Entity()
* @UniqueEntity("slug")
* @Vich\Uploadable
*/
class Entity
{
/**
* @var string
*
* @ORM\Column(name="slug", type="string", length=50, unique=true)
* @Assert\NotBlank()
* @Assert\Length(max="50")
*/
private $slug;
}

View File

@ -1,33 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel as BaseKernel;
class UnderInstanceOf
{
public function run(?BaseKernel $baseKernel)
{
if ($baseKernel instanceof BaseKernel) {
}
}
}
?>
-----
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\AbstractKernel;
class UnderInstanceOf
{
public function run(?AbstractKernel $baseKernel)
{
if ($baseKernel instanceof AbstractKernel) {
}
}
}
?>

View File

@ -1,27 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\ClassicTrait;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\StandaloneTrait as DuplicatedStandaloneTrait;
trait UnneededStandaloneTrait
{
use ClassicTrait, DuplicatedStandaloneTrait;
}
?>
-----
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\ClassicTrait;
use Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\StandaloneTrait;
trait UnneededStandaloneTrait
{
use ClassicTrait, StandaloneTrait;
}
?>

View File

@ -1,45 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use App\Bar as BarAlias;
use App\NoAlias;
class UsedInClassConstant
{
private $classMap = [
BarAlias::class => 'bar',
NoAlias::class => 'noalias',
];
public function run()
{
BarAlias::execute();
BarAlias::DATA;
}
}
?>
-----
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use App\Bar;
use App\NoAlias;
class UsedInClassConstant
{
private $classMap = [
Bar::class => 'bar',
NoAlias::class => 'noalias',
];
public function run()
{
Bar::execute();
Bar::DATA;
}
}
?>

View File

@ -1,31 +0,0 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\UnionType as PhpParserUnionType;
final class UsedUnionType
{
public function param(String_ | PhpParserUnionType $node)
{
}
}
?>
-----
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\UnionType;
final class UsedUnionType
{
public function param(String_ | UnionType $node)
{
}
}
?>

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class RemoveUnusedAliasRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source;
interface AbstractInterface
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source;
class AbstractKernel
{
}

View File

@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source;
class AliasedStaticCall
{
public static function someCall()
{
}
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\Another;
class AbstractKernel
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source;
trait ClassicTrait
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source\DifferentNamespace;
class StandaloneClass
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source;
final class Mapping
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source;
class StandaloneClass
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Source;
trait StandaloneTrait
{
}

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
use Rector\CodingStyle\Rector\Use_\RemoveUnusedAliasRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(RemoveUnusedAliasRector::class);
};

View File

@ -1,215 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\CodingStyle\Naming;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\Instanceof_;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\TraitUse;
use PhpParser\Node\UnionType;
use Rector\NameImporting\ValueObject\NameAndParent;
use Rector\NodeNameResolver\NodeNameResolver;
final class NameRenamer
{
public function __construct(
private NodeNameResolver $nodeNameResolver
) {
}
/**
* @param NameAndParent[] $namesAndParent
*/
public function renameNameNode(array $namesAndParent, string $lastName): void
{
foreach ($namesAndParent as $nameAndParent) {
$parentNode = $nameAndParent->getParentNode();
$usedName = $nameAndParent->getNameNode();
if ($parentNode instanceof TraitUse) {
$this->renameTraitUse($lastName, $parentNode, $usedName);
}
if ($parentNode instanceof Class_) {
$this->renameClass($lastName, $parentNode, $usedName);
}
if ($parentNode instanceof Param) {
$this->renameParam($lastName, $parentNode, $usedName);
}
if ($parentNode instanceof New_) {
$this->renameNew($lastName, $parentNode, $usedName);
}
if ($parentNode instanceof ClassMethod) {
$this->renameClassMethod($lastName, $parentNode, $usedName);
}
if ($parentNode instanceof Interface_) {
$this->renameInterface($lastName, $parentNode, $usedName);
}
if ($parentNode instanceof StaticCall) {
$this->renameStaticCall($lastName, $parentNode);
}
if ($parentNode instanceof UnionType) {
$this->renameUnionType($lastName, $parentNode, $usedName);
}
if ($parentNode instanceof NullableType) {
$this->renameNullableType($lastName, $parentNode, $usedName);
}
if ($parentNode instanceof Instanceof_) {
$this->renameInInstanceOf($lastName, $parentNode, $usedName);
}
if ($parentNode instanceof ClassConstFetch) {
$this->renameClassConstFetch($lastName, $parentNode, $usedName);
}
}
}
private function renameClassConstFetch(
string $lastName,
ClassConstFetch $classConstFetch,
Name | Identifier $usedNameNode
): void {
if (! $this->nodeNameResolver->areNamesEqual($classConstFetch->class, $usedNameNode)) {
return;
}
$classConstFetch->class = new Name($lastName);
}
private function renameInInstanceOf(
string $lastName,
Instanceof_ $instanceof,
Name | Identifier $usedNameNode
): void {
if (! $this->nodeNameResolver->areNamesEqual($instanceof->class, $usedNameNode)) {
return;
}
$instanceof->class = new Name($lastName);
}
private function renameNullableType(
string $lastName,
NullableType $nullableType,
Name | Identifier $usedNameNode
): void {
if (! $this->nodeNameResolver->areNamesEqual($nullableType->type, $usedNameNode)) {
return;
}
$nullableType->type = new Name($lastName);
}
private function renameTraitUse(string $lastName, TraitUse $traitUse, Name | Identifier $usedNameNode): void
{
foreach ($traitUse->traits as $key => $traitName) {
if (! $this->nodeNameResolver->areNamesEqual($traitName, $usedNameNode)) {
continue;
}
$traitUse->traits[$key] = new Name($lastName);
}
}
private function renameClass(string $lastName, Class_ $class, Name | Identifier $usedNameNode): void
{
if ($class->name !== null && $this->nodeNameResolver->areNamesEqual($class->name, $usedNameNode)) {
$class->name = new Identifier($lastName);
}
if ($class->extends !== null && $this->nodeNameResolver->areNamesEqual($class->extends, $usedNameNode)) {
$class->extends = new Name($lastName);
}
foreach ($class->implements as $key => $implementNode) {
if ($this->nodeNameResolver->areNamesEqual($implementNode, $usedNameNode)) {
$class->implements[$key] = new Name($lastName);
}
}
}
private function renameParam(string $lastName, Param $param, Name | Identifier $usedNameNode): void
{
if ($param->type === null) {
return;
}
if (! $this->nodeNameResolver->areNamesEqual($param->type, $usedNameNode)) {
return;
}
$param->type = new Name($lastName);
}
private function renameUnionType(string $lastName, UnionType $unionType, Identifier|Name $usedNameNode): void
{
foreach ($unionType->types as $key => $unionedType) {
if (! $this->nodeNameResolver->areNamesEqual($unionedType, $usedNameNode)) {
continue;
}
if (! $unionedType instanceof Name) {
continue;
}
$unionType->types[$key] = new Name($lastName);
}
}
private function renameNew(string $lastName, New_ $new, Name | Identifier $usedNameNode): void
{
if ($this->nodeNameResolver->areNamesEqual($new->class, $usedNameNode)) {
$new->class = new Name($lastName);
}
}
private function renameClassMethod(
string $lastName,
ClassMethod $classMethod,
Name | Identifier $usedNameNode
): void {
if ($classMethod->returnType === null) {
return;
}
if (! $this->nodeNameResolver->areNamesEqual($classMethod->returnType, $usedNameNode)) {
return;
}
$classMethod->returnType = new Name($lastName);
}
private function renameInterface(string $lastName, Interface_ $interface, Name | Identifier $usedNameNode): void
{
foreach ($interface->extends as $key => $extendInterfaceName) {
if (! $this->nodeNameResolver->areNamesEqual($extendInterfaceName, $usedNameNode)) {
continue;
}
$interface->extends[$key] = new Name($lastName);
}
}
private function renameStaticCall(string $lastName, StaticCall $staticCall): void
{
$staticCall->class = new Name($lastName);
}
}

View File

@ -1,93 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\CodingStyle\Node;
use Nette\Utils\Strings;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class DocAliasResolver
{
/**
* @var string
* @see https://regex101.com/r/cWpliJ/1
*/
private const DOC_ALIAS_REGEX = '#\@(?<possible_alias>\w+)(\\\\)?#s';
public function __construct(
private SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
private PhpDocInfoFactory $phpDocInfoFactory
) {
}
/**
* @return string[]
*/
public function resolve(Node $node): array
{
$possibleDocAliases = [];
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($node, function (Node $node) use (
&$possibleDocAliases
): void {
$docComment = $node->getDocComment();
if (! $docComment instanceof Doc) {
return;
}
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
$possibleDocAliases = $this->collectVarType($phpDocInfo, $possibleDocAliases);
// e.g. "use Dotrine\ORM\Mapping as ORM" etc.
$matches = Strings::matchAll($docComment->getText(), self::DOC_ALIAS_REGEX);
foreach ($matches as $match) {
$possibleDocAliases[] = $match['possible_alias'];
}
});
return array_unique($possibleDocAliases);
}
/**
* @param string[] $possibleDocAliases
* @return string[]
*/
private function collectVarType(PhpDocInfo $phpDocInfo, array $possibleDocAliases): array
{
$possibleDocAliases = $this->appendPossibleAliases($phpDocInfo->getVarType(), $possibleDocAliases);
$possibleDocAliases = $this->appendPossibleAliases($phpDocInfo->getReturnType(), $possibleDocAliases);
foreach ($phpDocInfo->getParamTypesByName() as $paramType) {
$possibleDocAliases = $this->appendPossibleAliases($paramType, $possibleDocAliases);
}
return $possibleDocAliases;
}
/**
* @param string[] $possibleDocAliases
* @return string[]
*/
private function appendPossibleAliases(Type $varType, array $possibleDocAliases): array
{
if ($varType instanceof AliasedObjectType) {
$possibleDocAliases[] = $varType->getClassName();
}
if ($varType instanceof UnionType) {
foreach ($varType->getTypes() as $type) {
$possibleDocAliases = $this->appendPossibleAliases($type, $possibleDocAliases);
}
}
return $possibleDocAliases;
}
}

View File

@ -1,42 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\CodingStyle\Node;
use Rector\CodingStyle\ClassNameImport\ShortNameResolver;
use Rector\CodingStyle\Naming\ClassNaming;
use Rector\Core\ValueObject\Application\File;
final class UseNameAliasToNameResolver
{
public function __construct(
private ClassNaming $classNaming,
private ShortNameResolver $shortNameResolver
) {
}
/**
* @return array<string, string[]>
*/
public function resolve(File $file): array
{
$useNamesAliasToName = [];
$shortNames = $this->shortNameResolver->resolveFromFile($file);
foreach ($shortNames as $alias => $useImport) {
if (! is_string($alias)) {
continue;
}
$shortName = $this->classNaming->getShortName($useImport);
if ($shortName === $alias) {
continue;
}
$useNamesAliasToName[$shortName][] = $alias;
}
return $useNamesAliasToName;
}
}

View File

@ -1,244 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\CodingStyle\Rector\Use_;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper;
use Rector\CodingStyle\Naming\NameRenamer;
use Rector\CodingStyle\Node\DocAliasResolver;
use Rector\CodingStyle\Node\UseNameAliasToNameResolver;
use Rector\Core\PhpParser\NodeFinder\FullyQualifiedFromUseFinder;
use Rector\Core\Rector\AbstractRector;
use Rector\NameImporting\NodeAnalyzer\UseAnalyzer;
use Rector\NameImporting\ValueObject\NameAndParent;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\RemoveUnusedAliasRectorTest
*/
final class RemoveUnusedAliasRector extends AbstractRector
{
/**
* @var NameAndParent[]
*/
private array $namesAndParents = [];
/**
* @var array<string, string[]>
*/
private array $useNamesAliasToName = [];
/**
* @var string[]
*/
private array $resolvedDocPossibleAliases = [];
public function __construct(
private DocAliasResolver $docAliasResolver,
private UseAnalyzer $useAnalyzer,
private UseNameAliasToNameResolver $useNameAliasToNameResolver,
private NameRenamer $nameRenamer,
private ClassNameImportSkipper $classNameImportSkipper,
private FullyQualifiedFromUseFinder $fullyQualifiedFromUseFinder
) {
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Removes unused use aliases. Keep annotation aliases like "Doctrine\ORM\Mapping as ORM" to keep convention format',
[
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 array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Use_::class];
}
/**
* @param Use_ $node
*/
public function refactor(Node $node): ?Node
{
if ($this->shouldSkipUse($node)) {
return null;
}
$searchNode = $this->resolveSearchNode($node);
if (! $searchNode instanceof Node) {
return null;
}
$this->namesAndParents = $this->useAnalyzer->resolveUsedNameNodes($searchNode);
$this->resolvedDocPossibleAliases = $this->docAliasResolver->resolve($searchNode);
$this->useNamesAliasToName = $this->useNameAliasToNameResolver->resolve($this->file);
// lowercase
$this->resolvedDocPossibleAliases = $this->lowercaseArray($this->resolvedDocPossibleAliases);
$this->useNamesAliasToName = array_change_key_case($this->useNamesAliasToName, CASE_LOWER);
foreach ($node->uses as $use) {
if ($use->alias === null) {
continue;
}
$lastName = $use->name->getLast();
/** @var string $aliasName */
$aliasName = $this->getName($use->alias);
if ($this->shouldSkip($node, $lastName, $aliasName)) {
continue;
}
// only last name is used → no need for alias
$matchedNamesAndParents = $this->matchNamesAndParentsByShort($lastName);
if ($matchedNamesAndParents !== []) {
$use->alias = null;
continue;
}
$this->refactorAliasName($node, $use->name->toString(), $lastName, $use);
}
return $node;
}
private function shouldSkipUse(Use_ $use): bool
{
// skip cases without namespace, problematic to analyse
$namespace = $this->betterNodeFinder->findParentType($use, Namespace_::class);
if (! $namespace instanceof Node) {
return true;
}
return ! $this->hasUseAlias($use);
}
/**
* @param string[] $values
* @return string[]
*/
private function lowercaseArray(array $values): array
{
return array_map('strtolower', $values);
}
private function shouldSkip(Use_ $use, string $lastName, string $aliasName): bool
{
// PHP is case insensitive
$loweredLastName = strtolower($lastName);
$loweredAliasName = strtolower($aliasName);
// both are used → nothing to remove
if ($this->areBothShortNamesUsed($loweredLastName, $loweredLastName)) {
return true;
}
// part of some @Doc annotation
if (in_array($loweredAliasName, $this->resolvedDocPossibleAliases, true)) {
return true;
}
return (bool) $this->fullyQualifiedFromUseFinder->matchAliasNamespace($use, $loweredAliasName);
}
private function refactorAliasName(Use_ $use, string $fullUseUseName, string $lastName, UseUse $useUse): void
{
$parentUse = $use->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentUse instanceof Node) {
return;
}
/** @var Use_[] $uses */
$uses = $this->betterNodeFinder->find($parentUse, function (Node $node) use ($use): bool {
if ($node === $use) {
return false;
}
return $node instanceof Use_;
});
if ($this->classNameImportSkipper->isShortNameInUseStatement(new Name($lastName), $uses)) {
return;
}
$parentsAndNames = $this->matchNamesAndParentsByShort($fullUseUseName);
if ($parentsAndNames === []) {
return;
}
$this->nameRenamer->renameNameNode($parentsAndNames, $lastName);
$useUse->alias = null;
}
private function hasUseAlias(Use_ $use): bool
{
foreach ($use->uses as $useUse) {
if ($useUse->alias !== null) {
return true;
}
}
return false;
}
private function resolveSearchNode(Use_ $use): ?Node
{
$searchNode = $use->getAttribute(AttributeKey::PARENT_NODE);
if ($searchNode !== null) {
return $searchNode;
}
return $use->getAttribute(AttributeKey::NEXT_NODE);
}
private function areBothShortNamesUsed(string $firstName, string $secondName): bool
{
$firstNamesAndParents = $this->matchNamesAndParentsByShort($firstName);
$secondNamesAndParents = $this->matchNamesAndParentsByShort($secondName);
return $firstNamesAndParents !== [] && $secondNamesAndParents !== [];
}
/**
* @return NameAndParent[]
*/
private function matchNamesAndParentsByShort(string $shortName): array
{
return array_filter(
$this->namesAndParents,
fn (NameAndParent $nameAndParent): bool => $nameAndParent->matchShortName($shortName)
);
}
}

View File

@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\PhpParser\NodeFinder;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Use_;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class FullyQualifiedFromUseFinder
{
public function __construct(
private BetterNodeFinder $betterNodeFinder
) {
}
public function matchAliasNamespace(Use_ $use, string $loweredAliasName): ?Node
{
return $this->betterNodeFinder->findFirstNext($use, function (Node $node) use ($loweredAliasName): bool {
if (! $node instanceof FullyQualified) {
return false;
}
$originalName = $node->getAttribute(AttributeKey::ORIGINAL_NAME);
if (! $originalName instanceof Name) {
return false;
}
$loweredOriginalName = strtolower($originalName->toString());
$loweredOriginalNameNamespace = Strings::before($loweredOriginalName, '\\');
return $loweredAliasName === $loweredOriginalNameNamespace;
});
}
}