Skip to content

Commit

Permalink
[AutoImport] Add GroupUse support on auto import (#2939)
Browse files Browse the repository at this point in the history
* [AutoImport] Add GroupUse support on auto import

* fixture rename

* [ci-review] Rector Rectify

* clean up

* phpstan

* phpstan

Co-authored-by: GitHub Action <action@github.com>
  • Loading branch information
samsonasik and actions-user committed Sep 19, 2022
1 parent 75b1261 commit cd1dca7
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 44 deletions.
54 changes: 22 additions & 32 deletions packages/PostRector/Rector/NameImportingPostRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
namespace Rector\PostRector\Rector;

use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use PHPStan\Reflection\ReflectionProvider;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper;
use Rector\CodingStyle\Node\NameImporter;
use Rector\Core\Configuration\Option;
use Rector\Core\Configuration\Parameter\ParameterProvider;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\Provider\CurrentFileProvider;
use Rector\Core\ValueObject\Application\File;
use Rector\Naming\Naming\AliasNameResolver;
use Rector\Naming\Naming\UseImportsResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockNameImporter;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
Expand All @@ -34,7 +34,7 @@ public function __construct(
private readonly PhpDocInfoFactory $phpDocInfoFactory,
private readonly ReflectionProvider $reflectionProvider,
private readonly CurrentFileProvider $currentFileProvider,
private readonly BetterNodeFinder $betterNodeFinder,
private readonly UseImportsResolver $useImportsResolver,
private readonly AliasNameResolver $aliasNameResolver
) {
}
Expand Down Expand Up @@ -105,19 +105,14 @@ private function processNodeName(Name $name, File $file): ?Node
return $name;
}

// @todo test if old stmts or new stmts! or both? :)
/** @var Use_[] $currentUses */
$currentUses = $this->betterNodeFinder->findInstanceOf($file->getNewStmts(), Use_::class);
/** @var Use_[]|GroupUse[] $currentUses */
$currentUses = $this->useImportsResolver->resolveForNode($name);

if ($this->shouldImportName($name, $currentUses)) {
$aliasName = $this->aliasNameResolver->resolveByName($name);
$node = $name->getAttribute(AttributeKey::PARENT_NODE);

if (is_string($aliasName) && ! $node instanceof UseUse && ! $this->hasOtherSameUseStatementWithoutAlias(
$name,
$currentUses
)) {
return new Name($aliasName);
$alias = $this->resolveAlias($name);

if ($alias instanceof Name) {
return $alias;
}

return $this->nameImporter->importName($name, $file, $currentUses);
Expand All @@ -126,29 +121,24 @@ private function processNodeName(Name $name, File $file): ?Node
return null;
}

/**
* @param Use_[] $currentUses
*/
private function hasOtherSameUseStatementWithoutAlias(Name $name, array $currentUses): bool
private function resolveAlias(Name $name): ?Name
{
$currentName = $name->toString();
foreach ($currentUses as $currentUse) {
foreach ($currentUse->uses as $useUse) {
if ($useUse->alias instanceof Identifier) {
continue;
}

if ($useUse->name->toString() === $currentName) {
return true;
}
}
$originalName = $name->getAttribute(AttributeKey::ORIGINAL_NAME);

if (! $originalName instanceof FullyQualified) {
return null;
}

$aliasName = $this->aliasNameResolver->resolveByName($name);
if (! is_string($aliasName)) {
return null;
}

return false;
return new Name($aliasName);
}

/**
* @param Use_[] $currentUses
* @param Use_[]|GroupUse[] $currentUses
*/
private function shouldImportName(Name $name, array $currentUses): bool
{
Expand Down
23 changes: 15 additions & 8 deletions rules/CodingStyle/ClassNameImport/ClassNameImportSkipper.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\Core\ValueObject\Application\File;
use Rector\Naming\Naming\UseImportsResolver;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;

final class ClassNameImportSkipper
Expand All @@ -20,7 +22,8 @@ final class ClassNameImportSkipper
*/
public function __construct(
private readonly array $classNameImportSkipVoters,
private readonly RenamedClassesDataCollector $renamedClassesDataCollector
private readonly RenamedClassesDataCollector $renamedClassesDataCollector,
private readonly UseImportsResolver $useImportsResolver
) {
}

Expand All @@ -39,7 +42,7 @@ public function shouldSkipNameForFullyQualifiedObjectType(
}

/**
* @param Use_[] $existingUses
* @param Use_[]|GroupUse[] $existingUses
*/
public function isShortNameInUseStatement(Name $name, array $existingUses): bool
{
Expand All @@ -52,15 +55,17 @@ public function isShortNameInUseStatement(Name $name, array $existingUses): bool
}

/**
* @param Use_[] $uses
* @param Use_[]|GroupUse[] $uses
*/
public function isAlreadyImported(Name $name, array $uses): bool
{
$stringName = $name->toString();

foreach ($uses as $use) {
$prefix = $this->useImportsResolver->resolvePrefix($use);

foreach ($use->uses as $useUse) {
if ($useUse->name->toString() === $stringName) {
if ($prefix . $useUse->name->toString() === $stringName) {
return true;
}
}
Expand All @@ -70,22 +75,24 @@ public function isAlreadyImported(Name $name, array $uses): bool
}

/**
* @param Use_[] $uses
* @param Use_[]|GroupUse[] $uses
*/
public function isFoundInUse(Name $name, array $uses): bool
{
$stringName = $name->toString();
$nameLastName = strtolower($name->getLast());

foreach ($uses as $use) {
$prefix = $this->useImportsResolver->resolvePrefix($use);

foreach ($use->uses as $useUse) {
$useUseLastName = strtolower($useUse->name->getLast());

if ($useUseLastName !== $nameLastName) {
continue;
}

if ($this->isJustRenamedClass($stringName, $useUse)) {
if ($this->isJustRenamedClass($stringName, $prefix, $useUse)) {
continue;
}

Expand All @@ -96,9 +103,9 @@ public function isFoundInUse(Name $name, array $uses): bool
return false;
}

private function isJustRenamedClass(string $stringName, UseUse $useUse): bool
private function isJustRenamedClass(string $stringName, string $prefix, UseUse $useUse): bool
{
$useUseNameString = $useUse->name->toString();
$useUseNameString = $prefix . $useUse->name->toString();

// is in renamed classes? skip it
foreach ($this->renamedClassesDataCollector->getOldToNewClasses() as $oldClass => $newClass) {
Expand Down
3 changes: 2 additions & 1 deletion rules/CodingStyle/Node/NameImporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
Expand Down Expand Up @@ -40,7 +41,7 @@ public function __construct(
}

/**
* @param Use_[] $uses
* @param Use_[]|GroupUse[] $uses
*/
public function importName(Name $name, File $file, array $uses): ?Name
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PhpParser\Node;
use PhpParser\Node\ComplexType;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
Expand Down Expand Up @@ -79,7 +80,7 @@ public function refactor(Node $node): ?Node
$onlyProperty = $node->props[0];

//Skip properties with default values
if ($onlyProperty->default instanceof Node\Expr) {
if ($onlyProperty->default instanceof Expr) {
return null;
}

Expand Down
32 changes: 32 additions & 0 deletions tests/Issues/AutoImportGroupUse/AutoImportGroupUseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Rector\Core\Tests\Issues\AutoImportGroupUse;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class AutoImportGroupUseTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

/**
* @return Iterator<array<string>>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Rector\Core\Tests\Issues\AutoImportGroupUse\Fixture;

use Rector\Core\Tests\Issues\AutoImportGroupUse\Source\{ SomeClass };

final class AutoImportInGroupUse extends \Rector\Core\Tests\Issues\AutoImportGroupUse\Source\SomeClass
{
}

?>
-----
<?php

namespace Rector\Core\Tests\Issues\AutoImportGroupUse\Fixture;

use Rector\Core\Tests\Issues\AutoImportGroupUse\Source\{ SomeClass };

final class AutoImportInGroupUse extends SomeClass
{
}

?>
9 changes: 9 additions & 0 deletions tests/Issues/AutoImportGroupUse/Source/SomeClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Rector\Core\Tests\Issues\AutoImportGroupUse\Source;

class SomeClass
{
}
9 changes: 9 additions & 0 deletions tests/Issues/AutoImportGroupUse/config/configured_rule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->importNames();
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Rector\Core\Tests\Issues\AutoImportDocInUse\Fixture;
namespace Rector\Core\Tests\Issues\AutoImportInAlias\Fixture;

use stdClass as SomeObject;

Expand All @@ -12,7 +12,7 @@ final class AutoImportInAlias extends \stdClass
-----
<?php

namespace Rector\Core\Tests\Issues\AutoImportDocInUse\Fixture;
namespace Rector\Core\Tests\Issues\AutoImportInAlias\Fixture;

use stdClass as SomeObject;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Rector\Core\Tests\Issues\AutoImportInAlias\Fixture;

use Rector\Core\Tests\Issues\AutoImportInAlias\Source\{ SomeClass as SomeObject };

final class AutoImportInAlias extends \Rector\Core\Tests\Issues\AutoImportInAlias\Source\SomeClass
{
}

?>
-----
<?php

namespace Rector\Core\Tests\Issues\AutoImportInAlias\Fixture;

use Rector\Core\Tests\Issues\AutoImportInAlias\Source\{ SomeClass as SomeObject };

final class AutoImportInAlias extends SomeObject
{
}

?>
9 changes: 9 additions & 0 deletions tests/Issues/AutoImportInAlias/Source/SomeClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Rector\Core\Tests\Issues\AutoImportInAlias\Source;

class SomeClass
{
}

0 comments on commit cd1dca7

Please sign in to comment.