Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Renaming] Skip docblock rename different namespace on RenameClassRector #2419

Merged
merged 18 commits into from
Jun 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,23 @@

namespace Rector\NodeTypeResolver\PhpDocNodeVisitor;

use PhpParser\Node as PhpParserNode;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Use_;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\ObjectType;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\Core\Configuration\CurrentNodeProvider;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Naming\Naming\UseImportsResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\ValueObject\OldToNewType;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\StaticTypeMapper\StaticTypeMapper;
Expand All @@ -26,7 +36,11 @@ final class ClassRenamePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor

public function __construct(
private readonly StaticTypeMapper $staticTypeMapper,
private readonly CurrentNodeProvider $currentNodeProvider
private readonly CurrentNodeProvider $currentNodeProvider,
private readonly UseImportsResolver $useImportsResolver,
private readonly BetterNodeFinder $betterNodeFinder,
private readonly NodeNameResolver $nodeNameResolver,
private readonly NodeComparator $nodeComparator
) {
}

Expand All @@ -48,7 +62,11 @@ public function enterNode(Node $node): ?Node
throw new ShouldNotHappenException();
}

$staticType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType($node, $phpParserNode);
$identifier = clone $node;

$namespacedName = $this->resolveNamespacedName($phpParserNode, $identifier->name);
$identifier->name = $namespacedName;
$staticType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType($identifier, $phpParserNode);

// make sure to compare FQNs
if ($staticType instanceof ShortenedObjectType) {
Expand Down Expand Up @@ -84,4 +102,59 @@ public function setOldToNewTypes(array $oldToNewTypes): void
{
$this->oldToNewTypes = $oldToNewTypes;
}

private function resolveNamespacedName(PhpParserNode $phpParserNode, string $name): string
{
if (str_starts_with($name, '\\')) {
return $name;
}

if (str_contains($name, '\\')) {
return $name;
}

$namespace = $this->betterNodeFinder->findParentType($phpParserNode, Namespace_::class);
$uses = $this->useImportsResolver->resolveForNode($phpParserNode);

if (! $namespace instanceof Namespace_) {
return $this->resolveNamefromUse($uses, $name);
}

$originalNode = $namespace->getAttribute(AttributeKey::ORIGINAL_NODE);
if (! $this->nodeComparator->areNodesEqual($originalNode, $namespace)) {
return $name;
}

if ($uses === []) {
$namespaceName = $this->nodeNameResolver->getName($namespace);
return $namespaceName . '\\' . $name;
}

return $this->resolveNamefromUse($uses, $name);
}

/**
* @param Use_[]|GroupUse[] $uses
*/
private function resolveNamefromUse(array $uses, string $name): string
{
foreach ($uses as $use) {
$prefix = $use instanceof GroupUse
? $use->prefix . '\\'
: '';

foreach ($use->uses as $useUse) {
if ($useUse->alias instanceof Identifier) {
continue;
}

$lastName = $useUse->name->getLast();
if ($lastName === $name) {
return $prefix . $useUse->name->toString();
}
}
}

return $name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

/**
* Future note: Not inside namespace on purpose to check last name Use_ used
*/
use \Company2\Bar;

final class SkipDocblockRenameDifferentNamespace
{
/**
* @param Bar $foo
*/
public function importedClassesReferencedViaAlias($foo)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\Fixture;

final class SkipDocblockRenameDifferentNamespace2
{
/**
* @param Bar $foo
*/
public function importedClassViaSameNamespace($foo)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\Fixture;

use \Company2\{ Bar };

final class SkipDocblockRenameDifferentNamespace3
{
/**
* @param Bar $foo
*/
public function importedClassViaSameNamespace($foo)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

/**
* Future note: Not inside namespace on purpose to check last name GroupUse_ used
*/

use \Company2\{ Bar };

final class SkipDocblockRenameDifferentNamespace4
{
/**
* @param Bar $foo
*/
public function importedClassViaSameNamespace($foo)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@
SomeNonFinalClass::class => SomeFinalClass::class,
'Foo\Bar' => 'Foo\Bar\BarInterface',
'Doctrine\DBAL\DBALException' => 'Doctrine\DBAL\Exception',
'Bar' => 'BarInterface',
]);
};