From 5f00ac7b129d5c641bc9b32cb8c79cacd58143c3 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 6 Apr 2026 12:32:39 +0700 Subject: [PATCH 1/8] [DeadCode] Add RemoveUselessTernaryRector --- .../Fixture/fixture.php.inc | 27 ++++++ .../Fixture/skip_different_type.php.inc | 11 +++ .../Fixture/skip_union.php.inc | 11 +++ .../Fixture/with_array_empty.php.inc | 27 ++++++ .../Fixture/with_if_equal.php.inc | 27 ++++++ .../Fixture/with_if_not_equal.php.inc | 11 +++ .../Fixture/with_integer_zero.php.inc | 27 ++++++ .../RemoveUselessTernaryRectorTest.php | 28 +++++++ .../config/configured_rule.php | 9 ++ .../Ternary/RemoveUselessTernaryRector.php | 83 +++++++++++++++++++ src/Config/Level/DeadCodeLevel.php | 2 + 11 files changed, 263 insertions(+) create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/fixture.php.inc create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_different_type.php.inc create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_union.php.inc create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_array_empty.php.inc create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_equal.php.inc create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_not_equal.php.inc create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_integer_zero.php.inc create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/RemoveUselessTernaryRectorTest.php create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/config/configured_rule.php create mode 100644 rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/fixture.php.inc b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..eb25989d9ed --- /dev/null +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/fixture.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_different_type.php.inc b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_different_type.php.inc new file mode 100644 index 00000000000..823854898ab --- /dev/null +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_different_type.php.inc @@ -0,0 +1,11 @@ + +----- + diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_equal.php.inc b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_equal.php.inc new file mode 100644 index 00000000000..f313c151152 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_equal.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_not_equal.php.inc b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_not_equal.php.inc new file mode 100644 index 00000000000..e16ed8bba45 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_not_equal.php.inc @@ -0,0 +1,11 @@ + +----- + diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/RemoveUselessTernaryRectorTest.php b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/RemoveUselessTernaryRectorTest.php new file mode 100644 index 00000000000..c0d2f7b0d16 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/RemoveUselessTernaryRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/config/configured_rule.php b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/config/configured_rule.php new file mode 100644 index 00000000000..abc80c166c5 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/config/configured_rule.php @@ -0,0 +1,9 @@ +withRules([RemoveUselessTernaryRector::class]); diff --git a/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php b/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php new file mode 100644 index 00000000000..7c6df1bdfa7 --- /dev/null +++ b/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php @@ -0,0 +1,83 @@ +> + */ + public function getNodeTypes(): array + { + return [Ternary::class]; + } + + /** + * @param Ternary $node + */ + public function refactor(Node $node): ?Node + { + if ($node->if instanceof Expr && ! $this->nodeComparator->areNodesEqual($node->if, $node->cond)) { + return null; + } + + $nativeType = $this->nodeTypeResolver->getNativeType($node->cond); + if ($nativeType instanceof BooleanType && $this->valueResolver->isFalse($node->else)) { + return $node->cond; + } + + if ($nativeType instanceof ArrayType && $node->else instanceof Array_ && $node->else->items === []) { + return $node->cond; + } + + if ($nativeType instanceof IntegerType && $node->else instanceof Int_ && $node->else->value === 0) { + return $node->cond; + } + + return null; + } +} diff --git a/src/Config/Level/DeadCodeLevel.php b/src/Config/Level/DeadCodeLevel.php index 2beee307b47..3bb5770ca97 100644 --- a/src/Config/Level/DeadCodeLevel.php +++ b/src/Config/Level/DeadCodeLevel.php @@ -61,6 +61,7 @@ use Rector\DeadCode\Rector\Stmt\RemoveNextSameValueConditionRector; use Rector\DeadCode\Rector\Stmt\RemoveUnreachableStatementRector; use Rector\DeadCode\Rector\Switch_\RemoveDuplicatedCaseInSwitchRector; +use Rector\DeadCode\Rector\Ternary\RemoveUselessTernaryRector; use Rector\DeadCode\Rector\Ternary\TernaryToBooleanOrFalseToBooleanAndRector; use Rector\DeadCode\Rector\TryCatch\RemoveDeadCatchRector; use Rector\DeadCode\Rector\TryCatch\RemoveDeadTryCatchRector; @@ -100,6 +101,7 @@ final class DeadCodeLevel RemoveTypedPropertyDeadInstanceOfRector::class, TernaryToBooleanOrFalseToBooleanAndRector::class, + RemoveUselessTernaryRector::class, RemoveDoubleAssignRector::class, RemoveUselessAssignFromPropertyPromotionRector::class, RemoveConcatAutocastRector::class, From 96b55a79b40e2e8f341bb7aa4f982176357a024d Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 6 Apr 2026 12:40:18 +0700 Subject: [PATCH 2/8] skip negated --- .../Fixture/skip_negated_cond.php.inc | 11 +++++++++++ .../Rector/Ternary/RemoveUselessTernaryRector.php | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_negated_cond.php.inc diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_negated_cond.php.inc b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_negated_cond.php.inc new file mode 100644 index 00000000000..6012bfb3415 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_negated_cond.php.inc @@ -0,0 +1,11 @@ +cond instanceof BooleanNot) { + return null; + } + $nativeType = $this->nodeTypeResolver->getNativeType($node->cond); if ($nativeType instanceof BooleanType && $this->valueResolver->isFalse($node->else)) { return $node->cond; From 642d85a5dab6db45aec1b97682a521dd1a273f45 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 6 Apr 2026 12:41:36 +0700 Subject: [PATCH 3/8] rename fixture --- ...with_if_not_equal.php.inc => skip_with_if_not_equal.php.inc} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/{with_if_not_equal.php.inc => skip_with_if_not_equal.php.inc} (87%) diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_not_equal.php.inc b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_with_if_not_equal.php.inc similarity index 87% rename from rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_not_equal.php.inc rename to rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_with_if_not_equal.php.inc index e16ed8bba45..87432a7259b 100644 --- a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/with_if_not_equal.php.inc +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_with_if_not_equal.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\DeadCode\Rector\Ternary\RemoveUselessTernaryRector\Fixture; -class WithIfNotEqual +class SkipWithIfNotEqual { public function go(bool $value) { From 3891e2dde9153e2362a361a5ff01251fda5ab473 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 6 Apr 2026 12:43:04 +0700 Subject: [PATCH 4/8] comment --- .../DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php b/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php index 4da618bb859..cdeadcccb78 100644 --- a/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php +++ b/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php @@ -66,8 +66,11 @@ public function refactor(Node $node): ?Node return null; } - // if condition is negated - // switch negated ternary condition via SwitchNegatedTernaryRector for that + /** + * if condition is negated, skip + * switch negated ternary condition early via SwitchNegatedTernaryRector for that + * if needed + */ if ($node->cond instanceof BooleanNot) { return null; } From 6576459184e147b92d78cb17fa1af46f1e43061b Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 6 Apr 2026 12:43:32 +0700 Subject: [PATCH 5/8] early check --- .../Rector/Ternary/RemoveUselessTernaryRector.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php b/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php index cdeadcccb78..c2f9e868c71 100644 --- a/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php +++ b/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php @@ -62,10 +62,6 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - if ($node->if instanceof Expr && ! $this->nodeComparator->areNodesEqual($node->if, $node->cond)) { - return null; - } - /** * if condition is negated, skip * switch negated ternary condition early via SwitchNegatedTernaryRector for that @@ -75,6 +71,10 @@ public function refactor(Node $node): ?Node return null; } + if ($node->if instanceof Expr && ! $this->nodeComparator->areNodesEqual($node->if, $node->cond)) { + return null; + } + $nativeType = $this->nodeTypeResolver->getNativeType($node->cond); if ($nativeType instanceof BooleanType && $this->valueResolver->isFalse($node->else)) { return $node->cond; From 9b08c58637ce3aab00ab0855afc6957bd520456d Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 6 Apr 2026 12:44:46 +0700 Subject: [PATCH 6/8] final touch: more fixture --- .../Fixture/skip_docblock_type.php.inc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_docblock_type.php.inc diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_docblock_type.php.inc b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_docblock_type.php.inc new file mode 100644 index 00000000000..05247f96482 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/skip_docblock_type.php.inc @@ -0,0 +1,14 @@ + Date: Mon, 6 Apr 2026 13:15:38 +0700 Subject: [PATCH 7/8] final touch: handle true false on bool --- .../Rector/Ternary/RemoveUselessTernaryRector.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php b/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php index c2f9e868c71..7d30ee12c63 100644 --- a/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php +++ b/rules/DeadCode/Rector/Ternary/RemoveUselessTernaryRector.php @@ -71,11 +71,18 @@ public function refactor(Node $node): ?Node return null; } + $nativeType = $this->nodeTypeResolver->getNativeType($node->cond); + if ($nativeType instanceof BooleanType + && $node->if instanceof Expr + && $this->valueResolver->isTrue($node->if) + && $this->valueResolver->isFalse($node->else)) { + return $node->cond; + } + if ($node->if instanceof Expr && ! $this->nodeComparator->areNodesEqual($node->if, $node->cond)) { return null; } - $nativeType = $this->nodeTypeResolver->getNativeType($node->cond); if ($nativeType instanceof BooleanType && $this->valueResolver->isFalse($node->else)) { return $node->cond; } From 4f2a50015f6ecb438b7f0761e44ac3443b4531bf Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 6 Apr 2026 13:15:43 +0700 Subject: [PATCH 8/8] final touch: handle true false on bool --- .../Fixture/true_false_on_bool.php.inc | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/true_false_on_bool.php.inc diff --git a/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/true_false_on_bool.php.inc b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/true_false_on_bool.php.inc new file mode 100644 index 00000000000..43e4821b604 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Ternary/RemoveUselessTernaryRector/Fixture/true_false_on_bool.php.inc @@ -0,0 +1,27 @@ + +----- +