Skip to content

Commit 48ff64a

Browse files
authored
Merge branch refs/heads/2.1.x into 2.2.x
2 parents 5201448 + 84639d0 commit 48ff64a

File tree

3 files changed

+175
-0
lines changed

3 files changed

+175
-0
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,22 @@ public function specifyTypesInCondition(
333333
);
334334
}
335335
}
336+
337+
// infer $list[$index] after $index < count($list)
338+
if (
339+
$context->true()
340+
&& !$orEqual
341+
// constant offsets are handled via HasOffsetType/HasOffsetValueType
342+
&& !$leftType instanceof ConstantIntegerType
343+
&& $argType->isList()->yes()
344+
&& IntegerRangeType::fromInterval(0, null)->isSuperTypeOf($leftType)->yes()
345+
) {
346+
$arrayArg = $expr->right->getArgs()[0]->value;
347+
$dimFetch = new ArrayDimFetch($arrayArg, $expr->left);
348+
$result = $result->unionWith(
349+
$this->create($dimFetch, $argType->getIterableValueType(), TypeSpecifierContext::createTrue(), $scope)->setRootExpr($expr),
350+
);
351+
}
336352
}
337353

338354
if (

tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,4 +1161,32 @@ public function testBug13526(): void
11611161
$this->analyse([__DIR__ . '/data/bug-13526.php'], []);
11621162
}
11631163

1164+
public function testBug13770(): void
1165+
{
1166+
$this->reportPossiblyNonexistentGeneralArrayOffset = true;
1167+
1168+
$this->analyse([__DIR__ . '/data/bug-13770.php'], [
1169+
[
1170+
'Offset int<1, max> might not exist on non-empty-list<int>.',
1171+
53,
1172+
],
1173+
[
1174+
'Offset int might not exist on list<int>.',
1175+
66,
1176+
],
1177+
[
1178+
'Offset int might not exist on list<int>.',
1179+
91,
1180+
],
1181+
[
1182+
'Offset int might not exist on array.',
1183+
100,
1184+
],
1185+
[
1186+
'Offset -1|3|6|10 might not exist on list<int>.',
1187+
126,
1188+
],
1189+
]);
1190+
}
1191+
11641192
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug13770;
4+
5+
class HelloWorld
6+
{
7+
/**
8+
* @param list<int> $array
9+
* @param positive-int $index
10+
*/
11+
public function positiveIntLessThanCount(array $array, int $index): int
12+
{
13+
if ($index < count($array)) {
14+
return $array[$index]; // should not report
15+
}
16+
17+
return 0;
18+
}
19+
20+
/**
21+
* @param list<int> $array
22+
* @param positive-int $index
23+
*/
24+
public function positiveIntLessThanCountInversed(array $array, int $index): int
25+
{
26+
if (count($array) > $index) {
27+
return $array[$index]; // should not report
28+
}
29+
30+
return 0;
31+
}
32+
33+
/**
34+
* @param list<int> $array
35+
* @param int<0, max> $index
36+
*/
37+
public function nonNegativeIntLessThanCount(array $array, int $index): int
38+
{
39+
if ($index < count($array)) {
40+
return $array[$index]; // should not report
41+
}
42+
43+
return 0;
44+
}
45+
46+
/**
47+
* @param list<int> $array
48+
* @param positive-int $index
49+
*/
50+
public function positiveIntLessThanOrEqualCount(array $array, int $index): int
51+
{
52+
if ($index <= count($array)) {
53+
return $array[$index]; // SHOULD still report - off by one
54+
}
55+
56+
return 0;
57+
}
58+
59+
/**
60+
* @param list<int> $array
61+
* @param int $index
62+
*/
63+
public function anyIntLessThanCount(array $array, int $index): int
64+
{
65+
if ($index < count($array)) {
66+
return $array[$index]; // SHOULD still report - could be negative
67+
}
68+
69+
return 0;
70+
}
71+
72+
/**
73+
* @param list<int> $array
74+
* @param int<0, max> $index
75+
*/
76+
public function positiveIntOnNormalCountMode(array $array, int $index): int
77+
{
78+
if ($index < count($array, COUNT_NORMAL)) {
79+
return $array[$index]; // should not error
80+
}
81+
82+
return 0;
83+
}
84+
85+
/**
86+
* @param list<int> $array
87+
*/
88+
public function anyIntOnUnknownCountMode(array $array, int $index, $countMode): int
89+
{
90+
if ($index < count($array, $countMode)) {
91+
return $array[$index]; // SHOULD still report - could be negative
92+
}
93+
94+
return 0;
95+
}
96+
97+
public function anyIntOnRecursiveCount(array $array, int $index): int
98+
{
99+
if ($index < count($array, COUNT_RECURSIVE)) {
100+
return $array[$index]; // SHOULD still report - could be negative
101+
}
102+
103+
return 0;
104+
}
105+
106+
/**
107+
* @param list<int> $array
108+
* @param 3|6|10 $index
109+
*/
110+
public function constantPositiveIntLessThanCount(array $array, int $index): int
111+
{
112+
if ($index < count($array)) {
113+
return $array[$index]; // should not report
114+
}
115+
116+
return 0;
117+
}
118+
119+
/**
120+
* @param list<int> $array
121+
* @param -1|3|6|10 $index
122+
*/
123+
public function constantMaybeNegativeIntLessThanCount(array $array, int $index): int
124+
{
125+
if ($index < count($array)) {
126+
return $array[$index]; // SHOULD still report - could be negative
127+
}
128+
129+
return 0;
130+
}
131+
}

0 commit comments

Comments
 (0)