fix renaming class to existing one [closes #1438]

This commit is contained in:
Tomas Votruba 2019-09-23 18:18:59 +02:00
parent 9832e8a883
commit 7b1595a931
5 changed files with 57 additions and 0 deletions

View File

@ -0,0 +1,9 @@
<?php declare(strict_types=1);
namespace Rector\Renaming\Exception;
use Exception;
final class InvalidPhpCodeException extends Exception
{
}

View File

@ -17,12 +17,15 @@ use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use PHPStan\Type\ObjectType;
use Rector\CodingStyle\Naming\ClassNaming;
use Rector\NodeTypeResolver\ClassExistenceStaticHelper;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpDoc\PhpDocClassRenamer;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\ConfiguredCodeSample;
use Rector\RectorDefinition\RectorDefinition;
use Rector\Renaming\Exception\InvalidPhpCodeException;
use ReflectionClass;
/**
* @see \Rector\Renaming\Tests\Rector\Class_\RenameClassRector\RenameClassRectorTest
@ -262,6 +265,8 @@ PHP
$newClassNamePart = $this->classNaming->getShortName($newName);
$newNamespacePart = $this->classNaming->getNamespace($newName);
$this->ensureClassWillNotBeDuplicate($newName, $name);
$classLike->name = new Identifier($newClassNamePart);
// Old class did not have any namespace, we need to wrap class with Namespace_ node
@ -323,4 +328,20 @@ PHP
$this->phpDocClassRenamer->changeTypeInAnnotationTypes($node, $this->oldToNewClasses);
}
private function ensureClassWillNotBeDuplicate(string $newName, string $oldName): void
{
if (! ClassExistenceStaticHelper::doesClassLikeExist($newName)) {
return;
}
$classReflection = new ReflectionClass($newName);
throw new InvalidPhpCodeException(sprintf(
'Renaming class "%s" to "%s" would create a duplicated class/interface/trait (already existing in "%s") and cause PHP code to be invalid.',
$oldName,
$newName,
$classReflection->getFileName()
));
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Fixture;
class DuplicatedClass
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Fixture;
class SingularClass
{
}

View File

@ -5,7 +5,9 @@ namespace Rector\Renaming\Tests\Rector\Class_\RenameClassRector;
use Iterator;
use Manual\Twig\TwigFilter;
use Manual_Twig_Filter;
use Rector\Renaming\Exception\InvalidPhpCodeException;
use Rector\Renaming\Rector\Class_\RenameClassRector;
use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Fixture\DuplicatedClass;
use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\AbstractManualExtension;
use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\NewClass;
use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\NewClassWithoutTypo;
@ -51,6 +53,15 @@ final class RenameClassRectorTest extends AbstractRectorTestCase
yield [__DIR__ . '/Fixture/rename_class_to_class_without_namespace.php.inc'];
}
/**
* @see https://github.com/rectorphp/rector/issues/1438
*/
public function testClassNameDuplication(): void
{
$this->expectException(InvalidPhpCodeException::class);
$this->doTestFile(__DIR__ . '/Fixture/skip_duplicated_class.php.inc');
}
/**
* @return mixed[]
*/
@ -73,6 +84,8 @@ final class RenameClassRectorTest extends AbstractRectorTestCase
'MyOldClass' => 'MyNamespace\MyNewClass',
'AnotherMyOldClass' => 'AnotherMyNewClass',
'MyNamespace\AnotherMyClass' => 'MyNewClassWithoutNamespace',
// test duplicated class - @see https://github.com/rectorphp/rector/issues/1438
'Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Fixture\SingularClass' => DuplicatedClass::class,
],
],
];