Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4476b7a

Browse files
Introduce reportCastedArrayKey parameter
1 parent 0d410e6 commit 4476b7a

File tree

9 files changed

+144
-7
lines changed

9 files changed

+144
-7
lines changed

‎conf/config.neon‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ parameters:
7171
reportStaticMethodSignatures: false
7272
reportWrongPhpDocTypeInVarTag: false
7373
reportAnyTypeWideningInVarTag: false
74+
reportArrayKeyCast: false
7475
reportPossiblyNonexistentGeneralArrayOffset: false
7576
reportPossiblyNonexistentConstantArrayOffset: false
7677
checkMissingOverrideMethodAttribute: false

‎conf/parametersSchema.neon‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ parametersSchema:
8080
reportStaticMethodSignatures: bool()
8181
reportWrongPhpDocTypeInVarTag: bool()
8282
reportAnyTypeWideningInVarTag: bool()
83+
reportArrayKeyCast: bool()
8384
reportPossiblyNonexistentGeneralArrayOffset: bool()
8485
reportPossiblyNonexistentConstantArrayOffset: bool()
8586
checkMissingOverrideMethodAttribute: bool()

‎src/Rules/Arrays/AllowedArrayKeysTypes.php‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,15 @@
2121
final class AllowedArrayKeysTypes
2222
{
2323

24-
public static function getType(): Type
24+
public static function getType(bool$strict = false): Type
2525
{
26+
if ($strict) {
27+
return new UnionType([
28+
new IntegerType(),
29+
new StringType(),
30+
]);
31+
}
32+
2633
return new UnionType([
2734
new IntegerType(),
2835
new StringType(),

‎src/Rules/Arrays/InvalidKeyInArrayDimFetchRule.php‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public function __construct(
2525
private RuleLevelHelper $ruleLevelHelper,
2626
#[AutowiredParameter]
2727
private bool $reportMaybes,
28+
#[AutowiredParameter]
29+
private bool $reportArrayKeyCast,
2830
)
2931
{
3032
}
@@ -56,17 +58,18 @@ public function processNode(Node $node, Scope $scope): array
5658
return [];
5759
}
5860

61+
$reportArrayKeyCast = $this->reportArrayKeyCast;
5962
$dimensionType = $this->ruleLevelHelper->findTypeToCheck(
6063
$scope,
6164
$node->dim,
6265
'',
63-
static fn (Type $dimType): bool => AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimType)->yes(),
66+
static fn (Type $dimType): bool => AllowedArrayKeysTypes::getType($reportArrayKeyCast)->isSuperTypeOf($dimType)->yes(),
6467
)->getType();
6568
if ($dimensionType instanceof ErrorType) {
6669
return [];
6770
}
6871

69-
$isSuperType = AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimensionType);
72+
$isSuperType = AllowedArrayKeysTypes::getType($this->reportArrayKeyCast)->isSuperTypeOf($dimensionType);
7073
if ($isSuperType->yes() || ($isSuperType->maybe() && !$this->reportMaybes)) {
7174
return [];
7275
}

‎src/Rules/Arrays/InvalidKeyInArrayItemRule.php‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
use PHPStan\DependencyInjection\RegisteredRule;
99
use PHPStan\Rules\Rule;
1010
use PHPStan\Rules\RuleErrorBuilder;
11+
use PHPStan\Rules\RuleLevelHelper;
1112
use PHPStan\Type\MixedType;
13+
use PHPStan\Type\Type;
1214
use PHPStan\Type\VerbosityLevel;
1315
use function sprintf;
1416

@@ -20,8 +22,11 @@ final class InvalidKeyInArrayItemRule implements Rule
2022
{
2123

2224
public function __construct(
25+
private RuleLevelHelper $ruleLevelHelper,
2326
#[AutowiredParameter]
2427
private bool $reportMaybes,
28+
#[AutowiredParameter]
29+
private bool $reportArrayKeyCast,
2530
)
2631
{
2732
}
@@ -37,8 +42,15 @@ public function processNode(Node $node, Scope $scope): array
3742
return [];
3843
}
3944

40-
$dimensionType = $scope->getType($node->key);
41-
$isSuperType = AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimensionType);
45+
$reportArrayKeyCast = $this->reportArrayKeyCast;
46+
$dimensionType = $this->ruleLevelHelper->findTypeToCheck(
47+
$scope,
48+
$node->key,
49+
'',
50+
static fn (Type $dimType): bool => AllowedArrayKeysTypes::getType($reportArrayKeyCast)->isSuperTypeOf($dimType)->yes(),
51+
)->getType();
52+
53+
$isSuperType = AllowedArrayKeysTypes::getType($reportArrayKeyCast)->isSuperTypeOf($dimensionType);
4254
if ($isSuperType->no()) {
4355
return [
4456
RuleErrorBuilder::message(

‎tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleTest.php‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
class InvalidKeyInArrayDimFetchRuleTest extends RuleTestCase
1414
{
1515

16+
private bool $reportCastedArrayKey = false;
17+
1618
protected function getRule(): Rule
1719
{
1820
$ruleLevelHelper = new RuleLevelHelper(self::createReflectionProvider(), true, false, true, true, true, false, true);
19-
return new InvalidKeyInArrayDimFetchRule($ruleLevelHelper, true);
21+
return new InvalidKeyInArrayDimFetchRule($ruleLevelHelper, true, $this->reportCastedArrayKey);
2022
}
2123

2224
public function testInvalidKey(): void
@@ -116,4 +118,20 @@ public function testBug12273(): void
116118
]);
117119
}
118120

121+
public function testUnsetFalseKey(): void
122+
{
123+
$this->reportCastedArrayKey = true;
124+
125+
$this->analyse([__DIR__ . '/data/unset-false-key.php'], [
126+
[
127+
'Invalid array key type false.',
128+
6,
129+
],
130+
[
131+
'Invalid array key type false.',
132+
13,
133+
],
134+
]);
135+
}
136+
119137
}

‎tests/PHPStan/Rules/Arrays/InvalidKeyInArrayItemRuleTest.php‎

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Rules\Arrays;
44

55
use PHPStan\Rules\Rule;
6+
use PHPStan\Rules\RuleLevelHelper;
67
use PHPStan\Testing\RuleTestCase;
78
use PHPUnit\Framework\Attributes\RequiresPhp;
89

@@ -12,9 +13,16 @@
1213
class InvalidKeyInArrayItemRuleTest extends RuleTestCase
1314
{
1415

16+
private bool $reportCastedArrayKey = false;
17+
18+
private bool $checkUnionType = true;
19+
20+
private bool $checkNullable = true;
21+
1522
protected function getRule(): Rule
1623
{
17-
return new InvalidKeyInArrayItemRule(true);
24+
$ruleLevelHelper = new RuleLevelHelper(self::createReflectionProvider(), $this->checkNullable, false, $this->checkUnionType, false, false, false, true);
25+
return new InvalidKeyInArrayItemRule($ruleLevelHelper, true, $this->reportCastedArrayKey);
1826
}
1927

2028
public function testInvalidKey(): void
@@ -35,6 +43,70 @@ public function testInvalidKey(): void
3543
]);
3644
}
3745

46+
public function testInvalidKeyOnLevel6(): void
47+
{
48+
$this->checkNullable = false;
49+
$this->checkUnionType = false;
50+
$this->analyse([__DIR__ . '/data/invalid-key-array-item.php'], [
51+
[
52+
'Invalid array key type DateTimeImmutable.',
53+
13,
54+
],
55+
[
56+
'Invalid array key type array.',
57+
14,
58+
],
59+
]);
60+
}
61+
62+
public function testInvalidKeyReportingCastedArrayKey(): void
63+
{
64+
$this->reportCastedArrayKey = true;
65+
$this->analyse([__DIR__ . '/data/invalid-key-array-item.php'], [
66+
[
67+
'Invalid array key type null.',
68+
12,
69+
],
70+
[
71+
'Invalid array key type DateTimeImmutable.',
72+
13,
73+
],
74+
[
75+
'Invalid array key type array.',
76+
14,
77+
],
78+
[
79+
'Possibly invalid array key type stdClass|string.',
80+
15,
81+
],
82+
[
83+
'Possibly invalid array key type string|null.',
84+
22,
85+
],
86+
]);
87+
}
88+
89+
public function testInvalidKeyReportingCastedArrayKeyOnLevel6(): void
90+
{
91+
$this->checkNullable = false;
92+
$this->checkUnionType = false;
93+
$this->reportCastedArrayKey = true;
94+
$this->analyse([__DIR__ . '/data/invalid-key-array-item.php'], [
95+
[
96+
'Invalid array key type null.',
97+
12,
98+
],
99+
[
100+
'Invalid array key type DateTimeImmutable.',
101+
13,
102+
],
103+
[
104+
'Invalid array key type array.',
105+
14,
106+
],
107+
]);
108+
}
109+
38110
public function testInvalidKeyInList(): void
39111
{
40112
$this->analyse([__DIR__ . '/data/invalid-key-list.php'], [

‎tests/PHPStan/Rules/Arrays/data/invalid-key-array-item.php‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,10 @@
1414
[] => 'bbb',
1515
$stringOrObject => 'aaa',
1616
];
17+
18+
/** @var string|null $stringOrNull */
19+
$stringOrNull = doFoo();
20+
21+
$b = [
22+
$stringOrNull => 'aaa',
23+
];
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace UnsetFalseKey;
4+
5+
/** @var array<int, int> $data */
6+
unset($data[false]);
7+
8+
function test_remove_element(): void {
9+
$modified = [1, 4, 6, 8];
10+
11+
// this would happen in the SUT
12+
unset($modified[array_search(4, $modified, true)]);
13+
unset($modified[array_search(5, $modified, true)]); // bug is here - will unset key `0` by accident
14+
15+
assert([1, 6, 8] === $modified); // actually is [6, 8]
16+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /