Failing test: Node type is not updated after executing rector (#6255)

Co-authored-by: Michal Lulco <lulco@efabrica.sk>
This commit is contained in:
Tomas Votruba 2021-04-28 02:11:40 +02:00 committed by GitHub
parent a5a99317b7
commit cf9d8c202d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 161 additions and 37 deletions

View File

@ -38,6 +38,7 @@ use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
@ -91,6 +92,11 @@ final class NodeTypeResolver
*/
private $identifierTypeResolver;
/**
* @var RenamedClassesDataCollector
*/
private $renamedClassesDataCollector;
/**
* @param NodeTypeResolverInterface[] $nodeTypeResolvers
*/
@ -101,6 +107,7 @@ final class NodeTypeResolver
ReflectionProvider $reflectionProvider,
HasOffsetTypeCorrector $hasOffsetTypeCorrector,
IdentifierTypeResolver $identifierTypeResolver,
RenamedClassesDataCollector $renamedClassesDataCollector,
array $nodeTypeResolvers
) {
foreach ($nodeTypeResolvers as $nodeTypeResolver) {
@ -113,6 +120,7 @@ final class NodeTypeResolver
$this->reflectionProvider = $reflectionProvider;
$this->hasOffsetTypeCorrector = $hasOffsetTypeCorrector;
$this->identifierTypeResolver = $identifierTypeResolver;
$this->renamedClassesDataCollector = $renamedClassesDataCollector;
}
/**
@ -146,7 +154,6 @@ final class NodeTypeResolver
}
$resolvedType = $this->resolve($node);
if ($resolvedType instanceof MixedType) {
return false;
}
@ -156,7 +163,7 @@ final class NodeTypeResolver
}
if ($resolvedType instanceof ObjectType) {
return $this->isObjectTypeOfObjectType($resolvedType, $requiredObjectType);
return $this->resolveObjectType($resolvedType, $requiredObjectType);
}
return $this->isMatchingUnionType($resolvedType, $requiredObjectType);
@ -438,7 +445,7 @@ final class NodeTypeResolver
private function resolveByNodeTypeResolvers(Node $node): ?Type
{
foreach ($this->nodeTypeResolvers as $nodeClass => $nodeTypeResolver) {
if (! is_a($node, $nodeClass)) {
if (! is_a($node, $nodeClass, true)) {
continue;
}
@ -502,4 +509,16 @@ final class NodeTypeResolver
return $classReflection->isSubclassOf($requiredObjectType->getClassName());
}
private function resolveObjectType(ObjectType $resolvedObjectType, ObjectType $requiredObjectType): bool
{
$renamedObjectType = $this->renamedClassesDataCollector->matchClassName($resolvedObjectType);
if (! $renamedObjectType instanceof ObjectType) {
return $this->isObjectTypeOfObjectType($resolvedObjectType, $requiredObjectType);
}
if (! $this->isObjectTypeOfObjectType($renamedObjectType, $requiredObjectType)) {
return $this->isObjectTypeOfObjectType($resolvedObjectType, $requiredObjectType);
}
return true;
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\ComplexFixture;
use Rector\Tests\Renaming\Rector\Name\RenameClassRector\Source\OldClassWithMethod;
$class = new OldClassWithMethod();
$class->someMethod();
?>
-----
<?php
namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\ComplexFixture;
use Rector\Tests\Renaming\Rector\Name\RenameClassRector\Source\NewClassWithNewMethod;
use Rector\Tests\Renaming\Rector\Name\RenameClassRector\Source\OldClassWithMethod;
$class = new NewClassWithNewMethod();
$class->someNewMethod();
?>

View File

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

View File

@ -0,0 +1,11 @@
<?php
namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\Source;
class NewClassWithNewMethod
{
public function someNewMethod()
{
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace Rector\Tests\Renaming\Rector\Name\RenameClassRector\Source;
class OldClassWithMethod
{
public function someMethod()
{
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
use Rector\Renaming\Rector\Name\RenameClassRector;
use Rector\Renaming\ValueObject\MethodCallRename;
use Rector\Tests\Renaming\Rector\Name\RenameClassRector\Source\NewClassWithNewMethod;
use Rector\Tests\Renaming\Rector\Name\RenameClassRector\Source\OldClassWithMethod;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
$services = $containerConfigurator->services();
$services->set(RenameClassRector::class)
->call('configure', [[
RenameClassRector::OLD_TO_NEW_CLASSES => [
OldClassWithMethod::class => NewClassWithNewMethod::class,
],
]]);
$services->set(RenameMethodRector::class)
->call('configure', [[
RenameMethodRector::METHOD_CALL_RENAMES => ValueObjectInliner::inline([
new MethodCallRename(NewClassWithNewMethod::class, 'someMethod', 'someNewMethod'),
]),
]]);
};

View File

@ -6,6 +6,9 @@ namespace Rector\PSR4\Collector;
use Rector\Core\Configuration\RenamedClassesDataCollector;
/**
* @deprecated Merge with RenamedClassesDataCollector
*/
final class RenamedClassesCollector
{
/**

View File

@ -11,9 +11,12 @@ final class MethodCallRenameCollector
*/
private $methodCallRenames = [];
public function addMethodCallRename(MethodCallRenameInterface $methodCallRename): void
/**
* @param MethodCallRenameInterface[] $methodCallRenames
*/
public function addMethodCallRenames(array $methodCallRenames): void
{
$this->methodCallRenames[] = $methodCallRename;
$this->methodCallRenames = array_merge($this->methodCallRenames, $methodCallRenames);
}
/**

View File

@ -139,10 +139,7 @@ CODE_SAMPLE
Assert::allIsInstanceOf($methodCallRenames, MethodCallRenameInterface::class);
$this->methodCallRenames = $methodCallRenames;
foreach ($methodCallRenames as $methodCallRename) {
$this->methodCallRenameCollector->addMethodCallRename($methodCallRename);
}
$this->methodCallRenameCollector->addMethodCallRenames($methodCallRenames);
}
/**

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Rector\Core\Configuration;
use PHPStan\Type\ObjectType;
final class RenamedClassesDataCollector
{
/**
@ -26,4 +28,16 @@ final class RenamedClassesDataCollector
{
return $this->oldToNewClasses;
}
public function matchClassName(ObjectType $objectType): ?ObjectType
{
$className = $objectType->getClassName();
$renamedClassName = $this->oldToNewClasses[$className] ?? null;
if ($renamedClassName === null) {
return null;
}
return new ObjectType($renamedClassName);
}
}

View File

@ -11,7 +11,6 @@ use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Trait_;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ObjectType;
use Rector\NodeNameResolver\NodeNameResolver;
@ -36,8 +35,8 @@ final class ClassManipulator
public function __construct(
NodeNameResolver $nodeNameResolver,
ReflectionProvider $reflectionProvider,
NodesToRemoveCollector $nodesToRemoveCollector
NodesToRemoveCollector $nodesToRemoveCollector,
ReflectionProvider $reflectionProvider
) {
$this->nodeNameResolver = $nodeNameResolver;
$this->nodesToRemoveCollector = $nodesToRemoveCollector;
@ -70,11 +69,12 @@ final class ClassManipulator
}
$classReflection = $this->reflectionProvider->getClass($objectType->getClassName());
foreach ($classReflection->getAncestors() as $ancestorClassReflection) {
if ($classReflection === $ancestorClassReflection) {
continue;
}
/** @var ClassReflection[] $parentClassReflections */
$parentClassReflections = array_merge($classReflection->getParents(), $classReflection->getInterfaces());
foreach ($parentClassReflections as $parentClassReflection) {
if ($parentClassReflection->hasMethod($methodName)) {
if ($ancestorClassReflection->hasMethod($methodName)) {
return true;
}
}
@ -94,27 +94,6 @@ final class ClassManipulator
return $this->nodeNameResolver->getNames($privateProperties);
}
/**
* @return string[]
*/
public function getPublicMethodNames(Class_ $class): array
{
$publicMethodNames = [];
foreach ($class->getMethods() as $classMethod) {
if ($classMethod->isAbstract()) {
continue;
}
if ($classMethod->isAbstract()) {
continue;
}
$publicMethodNames[] = $this->nodeNameResolver->getName($classMethod);
}
return $publicMethodNames;
}
/**
* @return string[]
*/