mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-07 03:40:50 +00:00
[Renaming] Skip renaming method call on RenameMethodRector when both 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>
This commit is contained in:
parent
1dd739aab6
commit
ebd4c3fee6
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Renaming\Rector\MethodCall\RenameMethodRector\Source;
|
||||
|
||||
interface NewInterface
|
||||
{
|
||||
public function some_new();
|
||||
}
|
|
@ -9,6 +9,7 @@ use Rector\Renaming\ValueObject\MethodCallRenameWithArrayKey;
|
|||
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 {
|
||||
|
@ -19,6 +20,7 @@ return static function (RectorConfig $rectorConfig): void {
|
|||
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'),
|
||||
]);
|
||||
|
|
|
@ -12,9 +12,12 @@ use PhpParser\Node\Expr\StaticCall;
|
|||
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;
|
||||
|
@ -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
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -124,7 +129,28 @@ CODE_SAMPLE
|
|||
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);
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\Core\Reflection;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
|
@ -26,15 +27,19 @@ use PHPStan\Reflection\ReflectionProvider;
|
|||
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,
|
||||
|
@ -45,6 +50,12 @@ final class ReflectionResolver
|
|||
) {
|
||||
}
|
||||
|
||||
#[Required]
|
||||
public function autowire(AstResolver $astResolver): void
|
||||
{
|
||||
$this->astResolver = $astResolver;
|
||||
}
|
||||
|
||||
public function resolveClassAndAnonymousClass(ClassLike $classLike): ClassReflection
|
||||
{
|
||||
if ($classLike instanceof Class_ && $this->classAnalyzer->isAnonymousClass($classLike)) {
|
||||
|
@ -59,9 +70,18 @@ final class ReflectionResolver
|
|||
}
|
||||
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user