Skip to content

Commit a97477b

Browse files
committed
Fix literal array with empty item outside of left-side assign
1 parent fb8d3ef commit a97477b

8 files changed

+88
-5
lines changed

conf/config.level0.neon

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ parametersSchema:
1717

1818
rules:
1919
- PHPStan\Rules\Arrays\DuplicateKeysInLiteralArraysRule
20+
- PHPStan\Rules\Arrays\EmptyArrayItemRule
2021
- PHPStan\Rules\Arrays\OffsetAccessWithoutDimForReadingRule
2122
- PHPStan\Rules\Classes\ClassConstantRule
2223
- PHPStan\Rules\Classes\DuplicateDeclarationRule

src/Analyser/NodeScopeResolver.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -1755,10 +1755,10 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression
17551755
$itemNodes = [];
17561756
$hasYield = false;
17571757
foreach ($expr->items as $arrayItem) {
1758+
$itemNodes[] = new LiteralArrayItem($scope, $arrayItem);
17581759
if ($arrayItem === null) {
1759-
throw new \PHPStan\ShouldNotHappenException();
1760+
continue;
17601761
}
1761-
$itemNodes[] = new LiteralArrayItem($scope, $arrayItem);
17621762
$result = $this->processExprNode($arrayItem, $scope, $nodeCallback, $context->enterDeep());
17631763
$hasYield = $hasYield || $result->hasYield();
17641764
$scope = $result->getScope();

src/Node/LiteralArrayItem.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ class LiteralArrayItem
1010

1111
private Scope $scope;
1212

13-
private ArrayItem $arrayItem;
13+
private ?ArrayItem $arrayItem;
1414

15-
public function __construct(Scope $scope, ArrayItem $arrayItem)
15+
public function __construct(Scope $scope, ?ArrayItem $arrayItem)
1616
{
1717
$this->scope = $scope;
1818
$this->arrayItem = $arrayItem;
@@ -23,7 +23,7 @@ public function getScope(): Scope
2323
return $this->scope;
2424
}
2525

26-
public function getArrayItem(): ArrayItem
26+
public function getArrayItem(): ?ArrayItem
2727
{
2828
return $this->arrayItem;
2929
}

src/Rules/Arrays/DuplicateKeysInLiteralArraysRule.php

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ public function processNode(\PhpParser\Node $node, Scope $scope): array
3535
$valueLines = [];
3636
foreach ($node->getItemNodes() as $itemNode) {
3737
$item = $itemNode->getArrayItem();
38+
if ($item === null) {
39+
continue;
40+
}
3841
if ($item->key === null) {
3942
continue;
4043
}
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Arrays;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Node\LiteralArrayNode;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Rules\RuleErrorBuilder;
10+
11+
/**
12+
* @implements \PHPStan\Rules\Rule<\PHPStan\Node\LiteralArrayNode>
13+
*/
14+
class EmptyArrayItemRule implements Rule
15+
{
16+
17+
public function getNodeType(): string
18+
{
19+
return LiteralArrayNode::class;
20+
}
21+
22+
public function processNode(Node $node, Scope $scope): array
23+
{
24+
foreach ($node->getItemNodes() as $itemNode) {
25+
$item = $itemNode->getArrayItem();
26+
if ($item !== null) {
27+
continue;
28+
}
29+
30+
return [
31+
RuleErrorBuilder::message('Literal array contains empty item.')
32+
->nonIgnorable()
33+
->build(),
34+
];
35+
}
36+
37+
return [];
38+
}
39+
40+
}

src/Rules/Arrays/UnpackIterableInArrayRule.php

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public function processNode(Node $node, Scope $scope): array
3737
$errors = [];
3838
foreach ($node->getItemNodes() as $itemNode) {
3939
$item = $itemNode->getArrayItem();
40+
if ($item === null) {
41+
continue;
42+
}
4043
if (!$item->unpack) {
4144
continue;
4245
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Arrays;
4+
5+
use PHPStan\Rules\Rule;
6+
use PHPStan\Testing\RuleTestCase;
7+
8+
/**
9+
* @extends RuleTestCase<EmptyArrayItemRule>
10+
*/
11+
class EmptyArrayItemRuleTest extends RuleTestCase
12+
{
13+
14+
protected function getRule(): Rule
15+
{
16+
return new EmptyArrayItemRule();
17+
}
18+
19+
public function testRule(): void
20+
{
21+
$this->analyse([__DIR__ . '/data/empty-array-item.php'], [
22+
[
23+
'Literal array contains empty item.',
24+
5,
25+
],
26+
]);
27+
}
28+
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace EmptyArrayItem;
4+
5+
doFoo([, 'foo']);
6+
7+
[, $a] = doFoo();

0 commit comments

Comments
 (0)