Skip to content

Commit dd99e41

Browse files
authored
perf: reject non-callable arrays before scope lookup (#8796)
1 parent d7a7306 commit dd99e41

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

‎rules-tests/Php81/Rector/Array_/ArrayToFirstClassCallableRector/ArrayToFirstClassCallableRectorTest.php‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@
55
namespace Rector\Tests\Php81\Rector\Array_\ArrayToFirstClassCallableRector;
66

77
use Iterator;
8+
use PhpParser\Node\ArrayItem;
9+
use PhpParser\Node\Expr\Array_;
10+
use PhpParser\Node\Expr\Variable;
11+
use PhpParser\Node\Scalar\String_;
812
use PHPUnit\Framework\Attributes\DataProvider;
13+
use Rector\NodeTypeResolver\Node\AttributeKey;
14+
use Rector\Php81\Rector\Array_\ArrayToFirstClassCallableRector;
915
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
1016

1117
final class ArrayToFirstClassCallableRectorTest extends AbstractRectorTestCase
@@ -21,6 +27,39 @@ public static function provideData(): Iterator
2127
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
2228
}
2329

30+
#[DataProvider('provideSkippedArrays')]
31+
public function testSkipWithoutScope(Array_ $array): void
32+
{
33+
$rector = $this->make(ArrayToFirstClassCallableRector::class);
34+
35+
$this->assertNull($rector->refactor($array));
36+
}
37+
38+
/**
39+
* @return Iterator<string, array{Array_}>
40+
*/
41+
public static function provideSkippedArrays(): Iterator
42+
{
43+
$caller = new ArrayItem(new Variable('this'));
44+
$method = new ArrayItem(new String_('run'));
45+
46+
yield 'empty array' => [new Array_()];
47+
yield 'one item' => [new Array_([$caller])];
48+
yield 'three items' => [new Array_([$caller, $method, $method])];
49+
50+
foreach ([
51+
AttributeKey::IS_CLASS_CONST_VALUE,
52+
AttributeKey::IS_DEFAULT_PROPERTY_VALUE,
53+
AttributeKey::IS_PARAM_DEFAULT,
54+
AttributeKey::IS_UNPACKED_ARG_VALUE,
55+
] as $attribute) {
56+
yield $attribute => [
57+
new Array_([$caller, $method], [
58+
$attribute => true,
59+
])];
60+
}
61+
}
62+
2463
public function provideConfigFilePath(): string
2564
{
2665
return __DIR__ . '/config/configured_rule.php';

‎rules/Php81/Rector/Array_/ArrayToFirstClassCallableRector.php‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Rector\Php81\Rector\Array_;
66

77
use PhpParser\Node;
8+
use PhpParser\Node\ArrayItem;
89
use PhpParser\Node\Expr\Array_;
910
use PhpParser\Node\Expr\ClassConstFetch;
1011
use PhpParser\Node\Expr\MethodCall;
@@ -90,6 +91,14 @@ public function getNodeTypes(): array
9091
*/
9192
public function refactor(Node $node): StaticCall|MethodCall|null
9293
{
94+
if (count($node->items) !== 2) {
95+
return null;
96+
}
97+
98+
if (! $node->items[0] instanceof ArrayItem || ! $node->items[1] instanceof ArrayItem) {
99+
return null;
100+
}
101+
93102
if ($node->getAttribute(AttributeKey::IS_ARG_NOT_ACCEPTING_CLOSURE)) {
94103
return null;
95104
}

0 commit comments

Comments
 (0)