From e43a1cec56310b6762eb0b56d18f60402d5fd652 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 19 Nov 2023 09:53:05 +0700 Subject: [PATCH] [Renaming] Handle Rename no namespace to namespaced class with existing use statements (#5264) * [Renaming] Rename no namespace to namespaced class with existing use statements * Fixed :tada: * Fixed :tada: --- .../PostRector/Rector/UseAddingPostRector.php | 14 ----- ...namespaced_class_with_existing_use.php.inc | 18 ++++++ ...amespaced_class_with_existing_use2.php.inc | 23 ++++++++ .../RenameToNamespacedClassTest.php | 28 ++++++++++ .../config/rename_to_namespaced_class.php | 13 +++++ .../Rector/Name/RenameClassRector.php | 56 +++++++++++++++++++ 6 files changed, 138 insertions(+), 14 deletions(-) create mode 100644 rules-tests/Renaming/Rector/Name/RenameClassRector/FixtureRenameToNamespacedClass/no_namespaced_to_namespaced_class_with_existing_use.php.inc create mode 100644 rules-tests/Renaming/Rector/Name/RenameClassRector/FixtureRenameToNamespacedClass/no_namespaced_to_namespaced_class_with_existing_use2.php.inc create mode 100644 rules-tests/Renaming/Rector/Name/RenameClassRector/RenameToNamespacedClassTest.php create mode 100644 rules-tests/Renaming/Rector/Name/RenameClassRector/config/rename_to_namespaced_class.php diff --git a/packages/PostRector/Rector/UseAddingPostRector.php b/packages/PostRector/Rector/UseAddingPostRector.php index 1fd847eee9c..d68c9933c2c 100644 --- a/packages/PostRector/Rector/UseAddingPostRector.php +++ b/packages/PostRector/Rector/UseAddingPostRector.php @@ -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); diff --git a/rules-tests/Renaming/Rector/Name/RenameClassRector/FixtureRenameToNamespacedClass/no_namespaced_to_namespaced_class_with_existing_use.php.inc b/rules-tests/Renaming/Rector/Name/RenameClassRector/FixtureRenameToNamespacedClass/no_namespaced_to_namespaced_class_with_existing_use.php.inc new file mode 100644 index 00000000000..50bb28cb0f7 --- /dev/null +++ b/rules-tests/Renaming/Rector/Name/RenameClassRector/FixtureRenameToNamespacedClass/no_namespaced_to_namespaced_class_with_existing_use.php.inc @@ -0,0 +1,18 @@ + +----- + +----- + diff --git a/rules-tests/Renaming/Rector/Name/RenameClassRector/RenameToNamespacedClassTest.php b/rules-tests/Renaming/Rector/Name/RenameClassRector/RenameToNamespacedClassTest.php new file mode 100644 index 00000000000..baa6df022d0 --- /dev/null +++ b/rules-tests/Renaming/Rector/Name/RenameClassRector/RenameToNamespacedClassTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/FixtureRenameToNamespacedClass'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/rename_to_namespaced_class.php'; + } +} diff --git a/rules-tests/Renaming/Rector/Name/RenameClassRector/config/rename_to_namespaced_class.php b/rules-tests/Renaming/Rector/Name/RenameClassRector/config/rename_to_namespaced_class.php new file mode 100644 index 00000000000..a36f2da5dc8 --- /dev/null +++ b/rules-tests/Renaming/Rector/Name/RenameClassRector/config/rename_to_namespaced_class.php @@ -0,0 +1,13 @@ +ruleWithConfiguration(RenameClassRector::class, [ + 'FqnizeNamespacedWithUse' => 'Abc\FqnizeNamespacedWithUse', + 'FqnizeNamespacedWithUseWithDeclareStrictTypes' => 'Abc\FqnizeNamespacedWithUseWithDeclareStrictTypes', + ]); +}; diff --git a/rules/Renaming/Rector/Name/RenameClassRector.php b/rules/Renaming/Rector/Name/RenameClassRector.php index a32e4ad5356..589c6bac706 100644 --- a/rules/Renaming/Rector/Name/RenameClassRector.php +++ b/rules/Renaming/Rector/Name/RenameClassRector.php @@ -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; @@ -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)); + } }