diff --git a/rules/DeadCode/Rector/Stmt/RemoveUnreachableStatementRector.php b/rules/DeadCode/Rector/Stmt/RemoveUnreachableStatementRector.php index f6d85829ec1..ac06c4c7092 100644 --- a/rules/DeadCode/Rector/Stmt/RemoveUnreachableStatementRector.php +++ b/rules/DeadCode/Rector/Stmt/RemoveUnreachableStatementRector.php @@ -4,19 +4,7 @@ declare (strict_types=1); namespace Rector\DeadCode\Rector\Stmt; use PhpParser\Node; -use PhpParser\Node\Expr\Exit_; use PhpParser\Node\Stmt; -use PhpParser\Node\Stmt\Break_; -use PhpParser\Node\Stmt\Continue_; -use PhpParser\Node\Stmt\Expression; -use PhpParser\Node\Stmt\Goto_; -use PhpParser\Node\Stmt\If_; -use PhpParser\Node\Stmt\InlineHTML; -use PhpParser\Node\Stmt\Label; -use PhpParser\Node\Stmt\Nop; -use PhpParser\Node\Stmt\Return_; -use PhpParser\Node\Stmt\Throw_; -use PhpParser\Node\Stmt\TryCatch; use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface; use Rector\Core\NodeAnalyzer\TerminatedNodeAnalyzer; use Rector\Core\Rector\AbstractRector; @@ -93,41 +81,13 @@ CODE_SAMPLE if (!isset($stmts[$key - 1])) { continue; } - if ($stmt instanceof Nop) { - continue; - } $previousStmt = $stmts[$key - 1]; // unset... - if ($this->shouldRemove($previousStmt, $stmt)) { + if ($this->terminatedNodeAnalyzer->isAlwaysTerminated($previousStmt, $stmt)) { \array_splice($stmts, $key); return $stmts; } } return $stmts; } - private function shouldRemove(Stmt $previousStmt, Stmt $currentStmt) : bool - { - if ($currentStmt instanceof InlineHTML) { - return \false; - } - if ($previousStmt instanceof Throw_) { - return \true; - } - if ($previousStmt instanceof Expression && $previousStmt->expr instanceof Exit_) { - return \true; - } - if ($previousStmt instanceof Goto_ && $currentStmt instanceof Label) { - return \false; - } - if (\in_array(\get_class($previousStmt), [Return_::class, Break_::class, Continue_::class, Goto_::class], \true)) { - return \true; - } - if ($previousStmt instanceof TryCatch) { - return $this->terminatedNodeAnalyzer->isAlwaysTerminated($previousStmt); - } - if ($previousStmt instanceof If_) { - return $this->terminatedNodeAnalyzer->isAlwaysTerminated($previousStmt); - } - return \false; - } } diff --git a/src/Application/ChangedNodeScopeRefresher.php b/src/Application/ChangedNodeScopeRefresher.php index 8f95039b69a..f68a4587bfa 100644 --- a/src/Application/ChangedNodeScopeRefresher.php +++ b/src/Application/ChangedNodeScopeRefresher.php @@ -23,6 +23,7 @@ use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\If_; use PhpParser\Node\Stmt\Namespace_; use PhpParser\Node\Stmt\Property; +use PhpParser\Node\Stmt\Switch_; use PhpParser\Node\Stmt\TryCatch; use PHPStan\Analyser\MutatingScope; use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface; @@ -142,6 +143,9 @@ final class ChangedNodeScopeRefresher if ($node instanceof TryCatch) { $node->catches = \array_values($node->catches); } + if ($node instanceof Switch_) { + $node->cases = \array_values($node->cases); + } } /** * @return Stmt[] diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index 923902f417e..aba8898597e 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -16,11 +16,11 @@ final class VersionResolver /** * @var string */ - public const PACKAGE_VERSION = '7c8b23b02d49c397deb2cf194f0e0bfeef6ea90c'; + public const PACKAGE_VERSION = '945fcc81ba3030f276e0a2d0cc8dd554e5e3171e'; /** * @var string */ - public const RELEASE_DATE = '2022-06-29 15:50:24'; + public const RELEASE_DATE = '2022-06-30 09:57:15'; /** * @var int */ diff --git a/src/NodeAnalyzer/TerminatedNodeAnalyzer.php b/src/NodeAnalyzer/TerminatedNodeAnalyzer.php index 4d1bc6a682f..d1714514ee7 100644 --- a/src/NodeAnalyzer/TerminatedNodeAnalyzer.php +++ b/src/NodeAnalyzer/TerminatedNodeAnalyzer.php @@ -4,13 +4,21 @@ declare (strict_types=1); namespace Rector\Core\NodeAnalyzer; use PhpParser\Node; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\Exit_; use PhpParser\Node\Stmt; +use PhpParser\Node\Stmt\Break_; +use PhpParser\Node\Stmt\Continue_; use PhpParser\Node\Stmt\Else_; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Finally_; +use PhpParser\Node\Stmt\Goto_; use PhpParser\Node\Stmt\If_; +use PhpParser\Node\Stmt\InlineHTML; +use PhpParser\Node\Stmt\Label; +use PhpParser\Node\Stmt\Nop; use PhpParser\Node\Stmt\Return_; +use PhpParser\Node\Stmt\Switch_; use PhpParser\Node\Stmt\Throw_; use PhpParser\Node\Stmt\TryCatch; final class TerminatedNodeAnalyzer @@ -20,46 +28,101 @@ final class TerminatedNodeAnalyzer */ private const TERMINATED_NODES = [Return_::class, Throw_::class]; /** - * @param \PhpParser\Node\Stmt\TryCatch|\PhpParser\Node\Stmt\If_ $node + * @var array> */ - public function isAlwaysTerminated($node) : bool + private const TERMINABLE_NODES = [Throw_::class, Return_::class, Break_::class, Continue_::class]; + /** + * @var array> + */ + private const TERMINABLE_NODES_BY_ITS_STMTS = [TryCatch::class, If_::class, Switch_::class]; + /** + * @var array> + */ + private const ALLOWED_CONTINUE_CURRENT_STMTS = [InlineHTML::class, Nop::class]; + /** + * @param \PhpParser\Node\Stmt\TryCatch|\PhpParser\Node\Stmt\If_|\PhpParser\Node\Stmt\Switch_|\PhpParser\Node $node + */ + public function isAlwaysTerminated($node, Node $currentStmt) : bool { - if ($node instanceof TryCatch) { - if ($node->finally instanceof Finally_ && $this->isTerminated($node->finally->stmts)) { - return \true; - } - foreach ($node->catches as $catch) { - if (!$this->isTerminated($catch->stmts)) { - return \false; - } - } - return $this->isTerminated($node->stmts); + if (\in_array(\get_class($currentStmt), self::ALLOWED_CONTINUE_CURRENT_STMTS, \true)) { + return \false; } - return $this->isTerminatedIf($node); + if (!\in_array(\get_class($node), self::TERMINABLE_NODES_BY_ITS_STMTS, \true)) { + return $this->isTerminatedNode($node, $currentStmt); + } + if ($node instanceof TryCatch) { + return $this->isTerminatedInLastStmtsTryCatch($node, $currentStmt); + } + if ($node instanceof If_) { + return $this->isTerminatedInLastStmtsIf($node, $currentStmt); + } + /** @var Switch_ $node */ + return $this->isTerminatedInLastStmtsSwitch($node, $currentStmt); } - private function isTerminatedIf(If_ $if) : bool + private function isTerminatedNode(Node $previousNode, Node $currentStmt) : bool + { + if (\in_array(\get_class($previousNode), self::TERMINABLE_NODES, \true)) { + return \true; + } + if ($previousNode instanceof Expression && $previousNode->expr instanceof Exit_) { + return \true; + } + if ($previousNode instanceof Goto_) { + return !$currentStmt instanceof Label; + } + return \false; + } + private function isTerminatedInLastStmtsSwitch(Switch_ $switch, Node $node) : bool + { + if ($switch->cases === []) { + return \false; + } + $hasDefault = \false; + foreach ($switch->cases as $case) { + if (!$case->cond instanceof Expr) { + $hasDefault = \true; + } + if (!$this->isTerminatedInLastStmts($case->stmts, $node)) { + return \false; + } + } + return $hasDefault; + } + private function isTerminatedInLastStmtsTryCatch(TryCatch $tryCatch, Node $node) : bool + { + if ($tryCatch->finally instanceof Finally_ && $this->isTerminatedInLastStmts($tryCatch->finally->stmts, $node)) { + return \true; + } + foreach ($tryCatch->catches as $catch) { + if (!$this->isTerminatedInLastStmts($catch->stmts, $node)) { + return \false; + } + } + return $this->isTerminatedInLastStmts($tryCatch->stmts, $node); + } + private function isTerminatedInLastStmtsIf(If_ $if, Node $node) : bool { // Without ElseIf_[] and Else_, after If_ is possibly executable if ($if->elseifs === [] && !$if->else instanceof Else_) { return \false; } foreach ($if->elseifs as $elseIf) { - if (!$this->isTerminated($elseIf->stmts)) { + if (!$this->isTerminatedInLastStmts($elseIf->stmts, $node)) { return \false; } } - if (!$this->isTerminated($if->stmts)) { + if (!$this->isTerminatedInLastStmts($if->stmts, $node)) { return \false; } if (!$if->else instanceof Else_) { return \false; } - return $this->isTerminated($if->else->stmts); + return $this->isTerminatedInLastStmts($if->else->stmts, $node); } /** * @param Stmt[] $stmts */ - private function isTerminated(array $stmts) : bool + private function isTerminatedInLastStmts(array $stmts, Node $node) : bool { if ($stmts === []) { return \false; @@ -67,6 +130,9 @@ final class TerminatedNodeAnalyzer \end($stmts); $lastKey = \key($stmts); $lastNode = $stmts[$lastKey]; + if (isset($stmts[$lastKey - 1]) && $this->isTerminatedNode($stmts[$lastKey - 1], $node)) { + return \false; + } if ($lastNode instanceof Expression) { return $lastNode->expr instanceof Exit_; } diff --git a/vendor/autoload.php b/vendor/autoload.php index c05103210a4..cb3e828edcd 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) { require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit6836f15434ca6d9a0271618d614b8b14::getLoader(); +return ComposerAutoloaderInit4ec8ad4ac2544855c7228b7fe4f7592b::getLoader(); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index e0100c8c313..3d9ae8aa96a 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit6836f15434ca6d9a0271618d614b8b14 +class ComposerAutoloaderInit4ec8ad4ac2544855c7228b7fe4f7592b { private static $loader; @@ -22,19 +22,19 @@ class ComposerAutoloaderInit6836f15434ca6d9a0271618d614b8b14 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit6836f15434ca6d9a0271618d614b8b14', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit4ec8ad4ac2544855c7228b7fe4f7592b', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit6836f15434ca6d9a0271618d614b8b14', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit4ec8ad4ac2544855c7228b7fe4f7592b', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit6836f15434ca6d9a0271618d614b8b14::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit4ec8ad4ac2544855c7228b7fe4f7592b::getInitializer($loader)); $loader->setClassMapAuthoritative(true); $loader->register(true); - $includeFiles = \Composer\Autoload\ComposerStaticInit6836f15434ca6d9a0271618d614b8b14::$files; + $includeFiles = \Composer\Autoload\ComposerStaticInit4ec8ad4ac2544855c7228b7fe4f7592b::$files; foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire6836f15434ca6d9a0271618d614b8b14($fileIdentifier, $file); + composerRequire4ec8ad4ac2544855c7228b7fe4f7592b($fileIdentifier, $file); } return $loader; @@ -46,7 +46,7 @@ class ComposerAutoloaderInit6836f15434ca6d9a0271618d614b8b14 * @param string $file * @return void */ -function composerRequire6836f15434ca6d9a0271618d614b8b14($fileIdentifier, $file) +function composerRequire4ec8ad4ac2544855c7228b7fe4f7592b($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 6f30e211819..8a82105bd61 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit6836f15434ca6d9a0271618d614b8b14 +class ComposerStaticInit4ec8ad4ac2544855c7228b7fe4f7592b { public static $files = array ( '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', @@ -3417,9 +3417,9 @@ class ComposerStaticInit6836f15434ca6d9a0271618d614b8b14 public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit6836f15434ca6d9a0271618d614b8b14::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit6836f15434ca6d9a0271618d614b8b14::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit6836f15434ca6d9a0271618d614b8b14::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit4ec8ad4ac2544855c7228b7fe4f7592b::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit4ec8ad4ac2544855c7228b7fe4f7592b::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit4ec8ad4ac2544855c7228b7fe4f7592b::$classMap; }, null, ClassLoader::class); }