Skip to content

Commit

Permalink
[Renaming] Handle Rename no namespace to namespaced class with existi…
Browse files Browse the repository at this point in the history
…ng use statements (#5264)

* [Renaming] Rename no namespace to namespaced class with existing use statements

* Fixed 🎉

* Fixed 🎉
  • Loading branch information
samsonasik committed Nov 19, 2023
1 parent 7fca71b commit e43a1ce
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 14 deletions.
14 changes: 0 additions & 14 deletions packages/PostRector/Rector/UseAddingPostRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,6 @@ private function resolveNodesWithImportedUses(
return $nodes;
}

// just renamed no-namepaced class to namespaced class
$namespaces = array_filter($nodes, static fn (Stmt $stmt): bool => $stmt instanceof Namespace_);
if ($namespaces !== []) {
// then add, to prevent adding + removing false positive of same short use
$this->useImportsAdder->addImportsToNamespace(
current($namespaces),
$useImportTypes,
$constantUseImportTypes,
$functionUseImportTypes
);

return $nodes;
}

// B. no namespace? add in the top
$useImportTypes = $this->filterOutNonNamespacedNames($useImportTypes);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

use A\B;

class FqnizeNamespacedWithUse
{
}

?>
-----
<?php

namespace Abc;

use A\B;
class FqnizeNamespacedWithUse
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

use A\B;

class FqnizeNamespacedWithUseWithDeclareStrictTypes
{
}

?>
-----
<?php

declare(strict_types=1);
namespace Abc;

use A\B;
class FqnizeNamespacedWithUseWithDeclareStrictTypes
{
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

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

use Iterator;
use PHPUnit\Framework\Attributes\DataProvider;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class RenameToNamespacedClassTest extends AbstractRectorTestCase
{
#[DataProvider('provideData')]
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public static function provideData(): Iterator
{
return self::yieldFilesFromDirectory(__DIR__ . '/FixtureRenameToNamespacedClass');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/rename_to_namespaced_class.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Renaming\Rector\Name\RenameClassRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->ruleWithConfiguration(RenameClassRector::class, [
'FqnizeNamespacedWithUse' => 'Abc\FqnizeNamespacedWithUse',
'FqnizeNamespacedWithUseWithDeclareStrictTypes' => 'Abc\FqnizeNamespacedWithUseWithDeclareStrictTypes',
]);
};
56 changes: 56 additions & 0 deletions rules/Renaming/Rector/Name/RenameClassRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Declare_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Property;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Renaming\NodeManipulator\ClassRenamer;
Expand Down Expand Up @@ -109,4 +111,58 @@ public function configure(array $configuration): void

$this->renamedClassesDataCollector->addOldToNewClasses($configuration);
}

/**
* @param Node[] $nodes
* @return null|Node[]
*/
public function afterTraverse(array $nodes): ?array
{
foreach ($nodes as $node) {
if ($node instanceof Namespace_) {
return parent::afterTraverse($nodes);
}

if ($node instanceof FileWithoutNamespace) {
foreach ($node->stmts as $stmt) {
if ($stmt instanceof Namespace_) {
$this->restructureUnderNamespace($node);
return $node->stmts;
}
}

return parent::afterTraverse($nodes);
}
}

return parent::afterTraverse($nodes);
}

private function restructureUnderNamespace(FileWithoutNamespace $fileWithoutNamespace): void
{
$stmts = array_reverse($fileWithoutNamespace->stmts, true);
$isBeforeNamespace = false;
$stmtsBeforeNamespace = [];
$namepace = null;

foreach ($stmts as $key => $stmt) {
if ($stmt instanceof Namespace_) {
$isBeforeNamespace = true;
$namepace = $stmt;
continue;
}

if ($isBeforeNamespace && ! $stmt instanceof Declare_) {
$stmtsBeforeNamespace[] = $stmt;
unset($stmts[$key]);
}
}

if ($stmtsBeforeNamespace === [] || ! $namepace instanceof Namespace_) {
return;
}

$namepace->stmts = array_values([...$stmtsBeforeNamespace, ...$namepace->stmts]);
$fileWithoutNamespace->stmts = array_values(array_reverse($stmts, true));
}
}

0 comments on commit e43a1ce

Please sign in to comment.