From 3f2fb29fe87904d779fb2f8d3e59492aaa9249f4 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 10 Nov 2023 05:04:21 +0700 Subject: [PATCH] [DeadCode] Allow indirect duplicated grouping on RemoveDuplicatedCaseInSwitchRector (#5234) * [DeadCode] Allow indirect duplicated grouping on RemoveDuplicatedCaseInSwitchRector * implemented :tada: * [ci-review] Rector Rectify --------- Co-authored-by: GitHub Action --- .../Fixture/indirect_duplicated.php.inc | 44 ++++++++++ .../Fixture/multi_indirect_duplicated.php.inc | 47 ++++++++++ .../RemoveDuplicatedCaseInSwitchRector.php | 86 ++++++++++++++++--- ...efaultNullToNullableTypePropertyRector.php | 3 +- 4 files changed, 168 insertions(+), 12 deletions(-) create mode 100644 rules-tests/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector/Fixture/indirect_duplicated.php.inc create mode 100644 rules-tests/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector/Fixture/multi_indirect_duplicated.php.inc diff --git a/rules-tests/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector/Fixture/indirect_duplicated.php.inc b/rules-tests/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector/Fixture/indirect_duplicated.php.inc new file mode 100644 index 00000000000..37cc0dbfd07 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector/Fixture/indirect_duplicated.php.inc @@ -0,0 +1,44 @@ +modifyHeader($node, 'replace'); + case 'clearHeader': + return $this->modifyHeader($node, 'remove'); + case 'clearRawHeaders': + return $this->modifyHeader($node, 'replace'); + case '...': + return 5; + } + } +} + +?> +----- +modifyHeader($node, 'replace'); + case 'clearHeader': + return $this->modifyHeader($node, 'remove'); + case '...': + return 5; + } + } +} + +?> diff --git a/rules-tests/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector/Fixture/multi_indirect_duplicated.php.inc b/rules-tests/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector/Fixture/multi_indirect_duplicated.php.inc new file mode 100644 index 00000000000..6c72922a51c --- /dev/null +++ b/rules-tests/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector/Fixture/multi_indirect_duplicated.php.inc @@ -0,0 +1,47 @@ +modifyHeader($node, 'replace'); + case 'clearHeader': + return $this->modifyHeader($node, 'remove'); + case 'clearRawHeaders': + return $this->modifyHeader($node, 'replace'); + case 'clearRawHeaders2': + return $this->modifyHeader($node, 'replace'); + case '...': + return 5; + } + } +} + +?> +----- +modifyHeader($node, 'replace'); + case 'clearHeader': + return $this->modifyHeader($node, 'remove'); + case '...': + return 5; + } + } +} + +?> diff --git a/rules/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector.php b/rules/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector.php index 0a71a15bf4d..1282213ee30 100644 --- a/rules/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector.php +++ b/rules/DeadCode/Rector/Switch_/RemoveDuplicatedCaseInSwitchRector.php @@ -18,6 +18,8 @@ */ final class RemoveDuplicatedCaseInSwitchRector extends AbstractRector { + private bool $hasChanged = false; + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -82,28 +84,90 @@ public function refactor(Node $node): ?Node return null; } + $this->hasChanged = false; + + $insertByKeys = $this->resolveInsertedByKeys($node); + $this->insertCaseByKeys($node, $insertByKeys); + $this->cleanUpEqualCaseStmts($node); + + if (! $this->hasChanged) { + return null; + } + + return $node; + } + + /** + * @return array> + */ + private function resolveInsertedByKeys(Switch_ $switch): array + { + $totalKeys = count($switch->cases); + $insertByKeys = []; + + foreach ($switch->cases as $key => $case) { + if ($case->stmts === []) { + continue; + } + + $nextKey = $key + 1; + for ($jumpToKey = $key + 1; $jumpToKey < $totalKeys; ++$jumpToKey) { + if (! isset($switch->cases[$jumpToKey])) { + continue; + } + + if (! $this->areSwitchStmtsEqualsAndWithBreak($case, $switch->cases[$jumpToKey])) { + continue; + } + + if ($nextKey === $jumpToKey) { + continue 2; + } + + $nextCase = $switch->cases[$jumpToKey]; + + unset($switch->cases[$jumpToKey]); + + $insertByKeys[$key][] = $nextCase; + + $this->hasChanged = true; + } + } + + return $insertByKeys; + } + + /** + * @param array> $insertByKeys + */ + private function insertCaseByKeys(Switch_ $switch, array $insertByKeys): void + { + foreach ($insertByKeys as $key => $insertByKey) { + $switch->cases[$key]->stmts = []; + $nextKey = $key + 1; + + array_splice($switch->cases, $nextKey, 0, $insertByKey); + } + } + + private function cleanUpEqualCaseStmts(Switch_ $switch): void + { /** @var Case_|null $previousCase */ $previousCase = null; - $hasChanged = false; - foreach ($node->cases as $case) { + foreach ($switch->cases as $case) { if ($previousCase instanceof Case_ && $this->areSwitchStmtsEqualsAndWithBreak($case, $previousCase)) { $previousCase->stmts = []; - $hasChanged = true; + + $this->hasChanged = true; } $previousCase = $case; } - - if (! $hasChanged) { - return null; - } - - return $node; } - private function areSwitchStmtsEqualsAndWithBreak(Case_ $currentCase, Case_ $previousCase): bool + private function areSwitchStmtsEqualsAndWithBreak(Case_ $currentCase, Case_ $nextCase): bool { - if (! $this->nodeComparator->areNodesEqual($currentCase->stmts, $previousCase->stmts)) { + if (! $this->nodeComparator->areNodesEqual($currentCase->stmts, $nextCase->stmts)) { return false; } diff --git a/rules/Php74/Rector/Property/RestoreDefaultNullToNullableTypePropertyRector.php b/rules/Php74/Rector/Property/RestoreDefaultNullToNullableTypePropertyRector.php index 14f20697b8c..5cc3251beb8 100644 --- a/rules/Php74/Rector/Property/RestoreDefaultNullToNullableTypePropertyRector.php +++ b/rules/Php74/Rector/Property/RestoreDefaultNullToNullableTypePropertyRector.php @@ -4,6 +4,7 @@ namespace Rector\Php74\Rector\Property; +use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Stmt\Class_; @@ -21,7 +22,7 @@ final class RestoreDefaultNullToNullableTypePropertyRector extends AbstractRector implements MinPhpVersionInterface { public function __construct( - private readonly ConstructorAssignDetector $constructorAssignDetector + private readonly ConstructorAssignDetector $constructorAssignDetector, private readonly PhpDocInfoFactory $phpDocInfoFactory ) { }