Skip to content

Commit 72349ee

Browse files
authored
perf: skip scope lookup for unsupported empty checks (#8795)
Co-authored-by: Alfred Bez <1001186+alfredbez@users.noreply.github.com>
1 parent b3763e7 commit 72349ee

2 files changed

Lines changed: 40 additions & 21 deletions

File tree

‎rules-tests/CodeQuality/Rector/Empty_/SimplifyEmptyCheckOnEmptyArrayRector/SimplifyEmptyCheckOnEmptyArrayRectorTest.php‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
namespace Rector\Tests\CodeQuality\Rector\Empty_\SimplifyEmptyCheckOnEmptyArrayRector;
66

77
use Iterator;
8+
use PhpParser\Node\Expr\Array_;
9+
use PhpParser\Node\Expr\BooleanNot;
10+
use PhpParser\Node\Expr\Empty_;
11+
use PhpParser\Node\Expr\FuncCall;
12+
use PhpParser\Node\Expr\Variable;
13+
use PhpParser\Node\Name;
814
use PHPUnit\Framework\Attributes\DataProvider;
15+
use Rector\CodeQuality\Rector\Empty_\SimplifyEmptyCheckOnEmptyArrayRector;
916
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
1017

1118
final class SimplifyEmptyCheckOnEmptyArrayRectorTest extends AbstractRectorTestCase
@@ -21,6 +28,26 @@ public static function provideData(): Iterator
2128
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
2229
}
2330

31+
#[DataProvider('provideUnsupportedNodes')]
32+
public function testSkipsUnsupportedNodesWithoutScope(BooleanNot|Empty_ $expr): void
33+
{
34+
$rector = self::getContainer()->make(SimplifyEmptyCheckOnEmptyArrayRector::class);
35+
36+
$this->assertNull($rector->refactor($expr));
37+
}
38+
39+
/**
40+
* @return Iterator<string, array{BooleanNot|Empty_}>
41+
*/
42+
public static function provideUnsupportedNodes(): Iterator
43+
{
44+
yield 'plain negation' => [new BooleanNot(new Variable('values'))];
45+
yield 'empty array literal' => [new Empty_(new Array_())];
46+
yield 'negated empty function call' => [new BooleanNot(new Empty_(new FuncCall(new Name('getValues'))))];
47+
yield 'superglobal get' => [new Empty_(new Variable('_GET'))];
48+
yield 'negated superglobal post' => [new BooleanNot(new Empty_(new Variable('_POST')))];
49+
}
50+
2451
public function provideConfigFilePath(): string
2552
{
2653
return __DIR__ . '/config/configured_rule.php';

‎rules/CodeQuality/Rector/Empty_/SimplifyEmptyCheckOnEmptyArrayRector.php‎

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Rector\CodeQuality\Rector\Empty_;
66

77
use PhpParser\Node;
8-
use PhpParser\Node\Expr;
98
use PhpParser\Node\Expr\Array_;
109
use PhpParser\Node\Expr\BinaryOp\Identical;
1110
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
@@ -79,43 +78,36 @@ public function getNodeTypes(): array
7978
*/
8079
public function refactor(Node $node): ?Node
8180
{
82-
$scope = ScopeFetcher::fetch($node);
83-
if ($node instanceof BooleanNot) {
84-
if ($node->expr instanceof Empty_ && $this->isAllowedExpr($node->expr->expr, $scope)) {
85-
return new NotIdentical($node->expr->expr, new Array_());
86-
}
87-
81+
$empty = $node instanceof BooleanNot ? $node->expr : $node;
82+
if (! $empty instanceof Empty_) {
8883
return null;
8984
}
9085

91-
if (! $this->isAllowedExpr($node->expr, $scope)) {
86+
$expr = $empty->expr;
87+
if (! $expr instanceof Variable && ! $expr instanceof PropertyFetch && ! $expr instanceof StaticPropertyFetch) {
9288
return null;
9389
}
9490

95-
return new Identical($node->expr, new Array_());
96-
}
91+
if ($expr instanceof Variable && is_string($expr->name) && $this->reservedKeywordAnalyzer->isNativeVariable($expr->name)) {
92+
return null;
93+
}
9794

98-
private function isAllowedVariable(Variable $variable): bool
99-
{
100-
if (is_string($variable->name) && $this->reservedKeywordAnalyzer->isNativeVariable($variable->name)) {
101-
return false;
95+
$scope = ScopeFetcher::fetch($node);
96+
if (! $this->isAllowedExpr($expr, $scope)) {
97+
return null;
10298
}
10399

104-
return ! $this->exprAnalyzer->isNonTypedFromParam($variable);
100+
return $node instanceof BooleanNot ? new NotIdentical($expr, new Array_()) : new Identical($expr, new Array_());
105101
}
106102

107-
private function isAllowedExpr(Expr $expr, Scope $scope): bool
103+
private function isAllowedExpr(Variable|PropertyFetch|StaticPropertyFetch $expr, Scope $scope): bool
108104
{
109-
if (! $expr instanceof Variable && ! $expr instanceof PropertyFetch && ! $expr instanceof StaticPropertyFetch) {
110-
return false;
111-
}
112-
113105
if (! $scope->getType($expr)->isArray()->yes()) {
114106
return false;
115107
}
116108

117109
if ($expr instanceof Variable) {
118-
return $this->isAllowedVariable($expr);
110+
return ! $this->exprAnalyzer->isNonTypedFromParam($expr);
119111
}
120112

121113
if (! $expr->name instanceof Identifier) {

0 commit comments

Comments
 (0)