Skip to content

Commit

Permalink
[Renaming] Skip renaming method call on RenameMethodRector when both …
Browse files Browse the repository at this point in the history
…old and new exists, which implements interface as config (#2276)

* [Renaming] Skip renaming method call on RenameMethodRector when both old and new exists

* rollback fixture

* verify if caller is a class that implements interface, which both old and new method exists

* [ci-review] Rector Rectify

* clean up

* allow directly get ClassReflection from StaticCall/MethodCall from ReflectionResolver

* clean up

* [ci-review] Rector Rectify

* [ci-review] Rector Rectify

* [ci-review] Rector Rectify

* verify that classlike is different, it means it is a child

* final touch: comment

Co-authored-by: GitHub Action <action@github.com>
  • Loading branch information
samsonasik and actions-user committed May 11, 2022
1 parent 1dd739a commit ebd4c3f
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Fixture;

use Nette\Utils\Html;
use Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Source\AClass;

class SkipOldNewExistsImplementsInterface
{
public function run(AClass $aClass)
{
$aClass->some_old();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Source;

final class AClass implements NewInterface
{
public function some_old()
{
}

public function some_new()
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Source;

interface NewInterface
{
public function some_new();
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Source\AbstractType;
use Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Source\CustomType;
use Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Source\Foo;
use Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Source\NewInterface;
use Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Source\SomeSubscriber;

return static function (RectorConfig $rectorConfig): void {
Expand All @@ -19,6 +20,7 @@
new MethodCallRename(CustomType::class, 'notify', '__invoke'),
new MethodCallRename(SomeSubscriber::class, 'old', 'new'),
new MethodCallRename(Foo::class, 'old', 'new'),
new MethodCallRename(NewInterface::class, 'some_old', 'some_new'),
// with array key
new MethodCallRenameWithArrayKey('Nette\Utils\Html', 'addToArray', 'addToHtmlArray', 'hey'),
]);
Expand Down
30 changes: 28 additions & 2 deletions rules/Renaming/Rector/MethodCall/RenameMethodRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\NodeManipulator\ClassManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\Renaming\Collector\MethodCallRenameCollector;
use Rector\Renaming\Contract\MethodCallRenameInterface;
use Rector\Renaming\ValueObject\MethodCallRename;
Expand All @@ -35,7 +38,9 @@ final class RenameMethodRector extends AbstractRector implements ConfigurableRec

public function __construct(
private readonly ClassManipulator $classManipulator,
private readonly MethodCallRenameCollector $methodCallRenameCollector
private readonly MethodCallRenameCollector $methodCallRenameCollector,
private readonly ReflectionResolver $reflectionResolver,
private readonly ReflectionProvider $reflectionProvider
) {
}

Expand Down Expand Up @@ -124,7 +129,28 @@ private function shouldSkipClassMethod(
MethodCallRenameInterface $methodCallRename
): bool {
if (! $node instanceof ClassMethod) {
return false;
$classReflection = $this->reflectionResolver->resolveClassReflection($node);

if (! $classReflection instanceof ClassReflection) {
return false;
}

$targetClass = $methodCallRename->getClass();
if (! $this->reflectionProvider->hasClass($targetClass)) {
return false;
}

$targetClassReflection = $this->reflectionProvider->getClass($targetClass);
if ($classReflection->getName() === $targetClassReflection->getName()) {
return false;
}

// different with configured ClassLike source? it is a child, which may has old and new exists
if (! $classReflection->hasMethod($methodCallRename->getOldMethod())) {
return false;
}

return $classReflection->hasMethod($methodCallRename->getNewMethod());
}

return $this->shouldSkipForAlreadyExistingClassMethod($node, $methodCallRename);
Expand Down
24 changes: 22 additions & 2 deletions src/Reflection/ReflectionResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Rector\Core\Reflection;

use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
Expand All @@ -26,15 +27,19 @@
use PHPStan\Type\TypeUtils;
use PHPStan\Type\TypeWithClassName;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
use Rector\Core\PhpParser\AstResolver;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PHPStan\Reflection\TypeToCallReflectionResolver\TypeToCallReflectionResolverRegistry;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Symfony\Contracts\Service\Attribute\Required;

final class ReflectionResolver
{
private AstResolver $astResolver;

public function __construct(
private readonly ReflectionProvider $reflectionProvider,
private readonly BetterNodeFinder $betterNodeFinder,
Expand All @@ -45,6 +50,12 @@ public function __construct(
) {
}

#[Required]
public function autowire(AstResolver $astResolver): void
{
$this->astResolver = $astResolver;
}

public function resolveClassAndAnonymousClass(ClassLike $classLike): ClassReflection
{
if ($classLike instanceof Class_ && $this->classAnalyzer->isAnonymousClass($classLike)) {
Expand All @@ -59,9 +70,18 @@ public function resolveClassAndAnonymousClass(ClassLike $classLike): ClassReflec
}

public function resolveClassReflection(
ClassMethod|Property|ClassLike|New_|Function_|ClassConst $classMethod
ClassMethod|Property|ClassLike|New_|Function_|ClassConst|MethodCall|StaticCall|null $node
): ?ClassReflection {
$scope = $classMethod->getAttribute(AttributeKey::SCOPE);
if (! $node instanceof Node) {
return null;
}

if ($node instanceof MethodCall || $node instanceof StaticCall) {
$classMethod = $this->astResolver->resolveClassMethodFromCall($node);
return $this->resolveClassReflection($classMethod);
}

$scope = $node->getAttribute(AttributeKey::SCOPE);

if (! $scope instanceof Scope) {
return null;
Expand Down

0 comments on commit ebd4c3f

Please sign in to comment.