From 7c6c6aaa45fe64223cd20147a2a176811b24cadb Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 23 May 2019 08:02:49 +0200 Subject: [PATCH] [Psr4] Add supprot for namespace less MultipleClassFileToPsr4ClassesRector --- phpstan.neon | 1 + rector.yaml | 2 +- .../MultipleClassFileToPsr4ClassesRector.php | 105 ++++++++++++------ .../JustOneExceptionWithoutNamespace.php | 5 + .../JustTwoExceptionWithoutNamespace.php | 5 + ...ltipleClassFileToPsr4ClassesRectorTest.php | 15 ++- .../Source/exceptions-without-namespace.php | 9 ++ 7 files changed, 106 insertions(+), 36 deletions(-) create mode 100644 tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Expected/JustOneExceptionWithoutNamespace.php create mode 100644 tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Expected/JustTwoExceptionWithoutNamespace.php create mode 100644 tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Source/exceptions-without-namespace.php diff --git a/phpstan.neon b/phpstan.neon index 67650d255afd..580ceacb98d2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -29,6 +29,7 @@ parameters: - '*/packages/ContributorTools/templates/*' # part of composer - 'tests/Composer/AutoloadWrongCasesEventSubscriber.php' + - '*/tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Expected/Just*ExceptionWithoutNamespace.php' ignoreErrors: # false positive diff --git a/rector.yaml b/rector.yaml index ac4cb8d11d41..f9c93639aaab 100644 --- a/rector.yaml +++ b/rector.yaml @@ -15,4 +15,4 @@ parameters: php_version_features: '7.1' services: - Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: ~ +# Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: ~ diff --git a/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php b/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php index 5e30330b23df..f1e48b093821 100644 --- a/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php +++ b/src/Rector/Psr4/MultipleClassFileToPsr4ClassesRector.php @@ -6,6 +6,7 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassLike; +use PhpParser\Node\Stmt\Declare_; use PhpParser\Node\Stmt\Namespace_; use Rector\FileSystemRector\Rector\AbstractFileSystemRector; use Rector\RectorDefinition\CodeSample; @@ -66,44 +67,43 @@ public function refactor(SmartFileInfo $smartFileInfo): void { $nodes = $this->parseFileInfoToNodes($smartFileInfo); - /** @var Namespace_[] $namespaceNodes */ - $namespaceNodes = $this->betterNodeFinder->findInstanceOf($nodes, Namespace_::class); - - if ($this->shouldSkip($smartFileInfo, $nodes, $namespaceNodes)) { + if ($this->shouldSkip($smartFileInfo, $nodes)) { return; } $shouldDelete = true; - foreach ($namespaceNodes as $namespaceNode) { - $newStmtsSet = $this->removeAllOtherNamespaces($nodes, $namespaceNode); - - foreach ($newStmtsSet as $newStmt) { - if (! $newStmt instanceof Namespace_) { - continue; - } - - /** @var ClassLike[] $namespacedClassLikeNodes */ - $namespacedClassLikeNodes = $this->betterNodeFinder->findInstanceOf($newStmt->stmts, ClassLike::class); + /** @var Namespace_[] $namespaceNodes */ + $namespaceNodes = $this->betterNodeFinder->findInstanceOf($nodes, Namespace_::class); - foreach ($namespacedClassLikeNodes as $classLikeNode) { - if ($classLikeNode instanceof Class_ && $classLikeNode->isAnonymous()) { - continue; - } + if (count($namespaceNodes)) { + $shouldDelete = $this->processNamespaceNodes($smartFileInfo, $namespaceNodes, $nodes); + } else { + $declareNode = null; - $this->removeAllClassLikesFromNamespaceNode($newStmt); - $newStmt->stmts[] = $classLikeNode; + foreach ($nodes as $node) { + if ($node instanceof Declare_) { + $declareNode = $node; + } - $fileDestination = $this->createClassLikeFileDestination($classLikeNode, $smartFileInfo); + if (! $node instanceof Class_ || $node->isAnonymous()) { + continue; + } - if ($smartFileInfo->getRealPath() === $fileDestination) { - $shouldDelete = false; - } + $fileDestination = $this->createClassLikeFileDestination($node, $smartFileInfo); + if ($smartFileInfo->getRealPath() === $fileDestination) { + $shouldDelete = false; + } - // has file changed? + // has file changed? - $this->printNodesToFilePath($newStmtsSet, $fileDestination); + if ($declareNode) { + $nodes = array_merge([$declareNode], [$node]); + } else { + $nodes = [$node]; } + + $this->printNodesToFilePath($nodes, $fileDestination); } } @@ -114,15 +114,9 @@ public function refactor(SmartFileInfo $smartFileInfo): void /** * @param Node[] $nodes - * @param Namespace_[] $namespaceNodes */ - private function shouldSkip(SmartFileInfo $smartFileInfo, array $nodes, array $namespaceNodes): bool + private function shouldSkip(SmartFileInfo $smartFileInfo, array $nodes): bool { - // process only namespaced file - if ($namespaceNodes === []) { - return true; - } - /** @var ClassLike[] $classLikeNodes */ $classLikeNodes = $this->betterNodeFinder->findInstanceOf($nodes, ClassLike::class); @@ -173,6 +167,49 @@ private function createClassLikeFileDestination(ClassLike $classLike, SmartFileI { $currentDirectory = dirname($smartFileInfo->getRealPath()); - return $currentDirectory . DIRECTORY_SEPARATOR . (string) $classLike->name . '.php'; + return $currentDirectory . DIRECTORY_SEPARATOR . $classLike->name . '.php'; + } + + /** + * @param Namespace_[] $namespaceNodes + * @param Node\Stmt[] $nodes + */ + private function processNamespaceNodes(SmartFileInfo $smartFileInfo, array $namespaceNodes, array $nodes): bool + { + $shouldDelete = true; + + foreach ($namespaceNodes as $namespaceNode) { + $newStmtsSet = $this->removeAllOtherNamespaces($nodes, $namespaceNode); + + foreach ($newStmtsSet as $newStmt) { + if (! $newStmt instanceof Namespace_) { + continue; + } + + /** @var ClassLike[] $namespacedClassLikeNodes */ + $namespacedClassLikeNodes = $this->betterNodeFinder->findInstanceOf($newStmt->stmts, ClassLike::class); + + foreach ($namespacedClassLikeNodes as $classLikeNode) { + if ($classLikeNode instanceof Class_ && $classLikeNode->isAnonymous()) { + continue; + } + + $this->removeAllClassLikesFromNamespaceNode($newStmt); + $newStmt->stmts[] = $classLikeNode; + + $fileDestination = $this->createClassLikeFileDestination($classLikeNode, $smartFileInfo); + + if ($smartFileInfo->getRealPath() === $fileDestination) { + $shouldDelete = false; + } + + // has file changed? + + $this->printNodesToFilePath($newStmtsSet, $fileDestination); + } + } + } + + return $shouldDelete; } } diff --git a/tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Expected/JustOneExceptionWithoutNamespace.php b/tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Expected/JustOneExceptionWithoutNamespace.php new file mode 100644 index 000000000000..e03c2d56c26a --- /dev/null +++ b/tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Expected/JustOneExceptionWithoutNamespace.php @@ -0,0 +1,5 @@ + __DIR__ . '/Expected/JustOneExceptionWithoutNamespace.php', + __DIR__ . '/Fixture/JustTwoExceptionWithoutNamespace.php' => __DIR__ . '/Expected/JustTwoExceptionWithoutNamespace.php', + ], + ]; + } + public function provideMissNamed(): Iterator { yield [ diff --git a/tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Source/exceptions-without-namespace.php b/tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Source/exceptions-without-namespace.php new file mode 100644 index 000000000000..6789ba4d0416 --- /dev/null +++ b/tests/Rector/Psr4/MultipleClassFileToPsr4ClassesRector/Source/exceptions-without-namespace.php @@ -0,0 +1,9 @@ +