Skip to content

Commit 5ca8b49

Browse files
Detect more possibly-nonexistent offset types
1 parent 5732016 commit 5ca8b49

File tree

4 files changed

+60
-9
lines changed

4 files changed

+60
-9
lines changed

src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use PHPStan\Type\ErrorType;
1515
use PHPStan\Type\Type;
1616
use PHPStan\Type\TypeUtils;
17-
use PHPStan\Type\UnionType;
1817
use PHPStan\Type\VerbosityLevel;
1918
use function count;
2019
use function sprintf;
@@ -76,6 +75,7 @@ public function check(
7675
} else {
7776
$flattenedTypes = TypeUtils::flattenTypes($type);
7877
}
78+
7979
foreach ($flattenedTypes as $innerType) {
8080
if (
8181
$this->reportPossiblyNonexistentGeneralArrayOffset
@@ -94,15 +94,15 @@ public function check(
9494
$report = true;
9595
break;
9696
}
97-
if ($dimType instanceof UnionType) {
98-
if ($innerType->hasOffsetValueType($dimType)->no()) {
99-
$report = true;
100-
break;
101-
}
102-
continue;
97+
if ($dimType instanceof BenevolentUnionType) {
98+
$flattenedInnerTypes = [$dimType];
99+
} else {
100+
$flattenedInnerTypes = TypeUtils::flattenTypes($dimType);
103101
}
104-
foreach (TypeUtils::flattenTypes($dimType) as $innerDimType) {
105-
if ($innerType->hasOffsetValueType($innerDimType)->no()) {
102+
foreach ($flattenedInnerTypes as $innerDimType) {
103+
if (
104+
$innerType->hasOffsetValueType($innerDimType)->no()
105+
) {
106106
$report = true;
107107
break 2;
108108
}

tests/PHPStan/Levels/data/stringOffsetAccess-7.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
[
2+
{
3+
"message": "Offset int|object might not exist on 'foo'.",
4+
"line": 19,
5+
"ignorable": true
6+
},
27
{
38
"message": "Offset 'foo' might not exist on array|string.",
49
"line": 27,
@@ -9,6 +14,11 @@
914
"line": 31,
1015
"ignorable": true
1116
},
17+
{
18+
"message": "Offset int|object might not exist on array|string.",
19+
"line": 35,
20+
"ignorable": true
21+
},
1222
{
1323
"message": "Possibly invalid array key type int|object.",
1424
"line": 35,

tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ public function testRule(): void
119119
'Cannot access offset \'a\' on array{a: 1, b: 1}|(Closure(): void).',
120120
258,
121121
],
122+
[
123+
'Offset int|null might not exist on array<int, string>.',
124+
309,
125+
],
122126
[
123127
'Offset null does not exist on array<int, string>.',
124128
310,
@@ -127,6 +131,10 @@ public function testRule(): void
127131
'Offset int does not exist on array<string, string>.',
128132
312,
129133
],
134+
[
135+
'Offset int|null might not exist on array<string, string>.',
136+
314,
137+
],
130138
[
131139
'Offset \'baz\' might not exist on array{bar: 1, baz?: 2}.',
132140
344,
@@ -185,6 +193,10 @@ public function testStrings(): void
185193
'Offset 12.34 does not exist on \'foo\'.',
186194
13,
187195
],
196+
[
197+
'Offset int|object might not exist on \'foo\'.',
198+
16,
199+
],
188200
[
189201
'Offset \'foo\' might not exist on array|string.',
190202
24,
@@ -193,6 +205,10 @@ public function testStrings(): void
193205
'Offset 12.34 might not exist on array|string.',
194206
28,
195207
],
208+
[
209+
'Offset int|object might not exist on array|string.',
210+
32,
211+
],
196212
]);
197213
}
198214

@@ -954,4 +970,14 @@ public function testBug12447(): void
954970
]);
955971
}
956972

973+
public function testBug1061(): void
974+
{
975+
$this->analyse([__DIR__ . '/data/bug-1061.php'], [
976+
[
977+
"Offset 'one'|'two' might not exist on array{two: 1, three: 2}.",
978+
14,
979+
],
980+
]);
981+
}
982+
957983
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug1061;
4+
5+
class A {
6+
const KEYS = ["one", "two"];
7+
const ARR = [
8+
"two" => 1,
9+
"three" => 2
10+
];
11+
}
12+
13+
foreach (A::KEYS as $key) {
14+
echo A::ARR[$key];
15+
}

0 commit comments

Comments
 (0)