Skip to content

Commit 92752b0

Browse files
committed
Add a rector to replace negated boolean literals
Replaces `! true` with `false` and replaces `! false` with `true`. This lets other rectors like dead code elimination work better.
1 parent a44d574 commit 92752b0

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

rector.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require_once __DIR__ . '/util/rector/RemoveAlwaysFalseIfStatementRector.php';
44
require_once __DIR__ . '/util/rector/RemoveAlwaysTrueIfConditionRector2.php';
55
require_once __DIR__ . '/util/rector/ReplaceKnownDefinedWithBooleanRector.php';
6+
require_once __DIR__ . '/util/rector/ReplaceNegatedBooleanRector.php';
67

78
use Rector\Config\RectorConfig;
89
use Rector\Constants\Rector\FuncCall\ReplaceKnownDefinedWithBooleanRector;
@@ -11,6 +12,7 @@
1112
use Rector\DeadCode\Rector\If_\RemoveAlwaysTrueIfConditionRector2;
1213
use Rector\Php53\Rector\Ternary\TernaryToElvisRector;
1314
use Rector\Set\ValueObject\SetList;
15+
use Rector\Transform\Rector\BooleanNot\ReplaceNegatedBooleanRector;
1416

1517
// Search rules at https://getrector.com/find-rule
1618

@@ -34,6 +36,7 @@
3436
RemoveAlwaysFalseIfStatementRector::class,
3537
RemoveAlwaysTrueIfConditionRector2::class,
3638
ReplaceKnownDefinedWithBooleanRector::class,
39+
ReplaceNegatedBooleanRector::class,
3740
]
3841
)
3942
->withSets(
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Transform\Rector\BooleanNot;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr;
9+
use PhpParser\Node\Expr\BooleanNot;
10+
use PhpParser\Node\Expr\ConstFetch;
11+
use PhpParser\Node\Name;
12+
use Rector\Rector\AbstractRector;
13+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
14+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
15+
16+
/**
17+
* Replace negated boolean literals with their simplified equivalents
18+
*
19+
* @see \Rector\Tests\DeadCode\Rector\BooleanNot\ReplaceNegatedBooleanRector\ReplaceNegatedBooleanRectorTest
20+
*/
21+
final class ReplaceNegatedBooleanRector extends AbstractRector
22+
{
23+
public function getRuleDefinition(): RuleDefinition
24+
{
25+
return new RuleDefinition('Replace negated boolean literals (!false, !true) with their simplified equivalents (true, false)', [
26+
new CodeSample(
27+
<<<'CODE_SAMPLE'
28+
if (!false) {
29+
return 'always true';
30+
}
31+
32+
if (!true) {
33+
return 'never reached';
34+
}
35+
CODE_SAMPLE
36+
,
37+
<<<'CODE_SAMPLE'
38+
if (true) {
39+
return 'always true';
40+
}
41+
42+
if (false) {
43+
return 'never reached';
44+
}
45+
CODE_SAMPLE
46+
)
47+
]);
48+
}
49+
50+
/**
51+
* @return array<class-string<Node>>
52+
*/
53+
public function getNodeTypes(): array
54+
{
55+
return [BooleanNot::class];
56+
}
57+
58+
/**
59+
* @param BooleanNot $node
60+
*/
61+
public function refactor(Node $node): ?Node
62+
{
63+
if (!$node instanceof BooleanNot) {
64+
return null;
65+
}
66+
67+
if (!$node->expr instanceof ConstFetch) {
68+
return null;
69+
}
70+
71+
$constantName = $this->getName($node->expr);
72+
73+
/** @var ConstFetch $constFetch */
74+
$constFetch = $node->expr;
75+
$constantName = $this->getName($constFetch);
76+
77+
if ($constantName === 'false') {
78+
return new ConstFetch(new Name('true'));
79+
}
80+
81+
if ($constantName === 'true') {
82+
return new ConstFetch(new Name('false'));
83+
}
84+
85+
return null;
86+
}
87+
}

0 commit comments

Comments
 (0)