Skip to content

Commit 1485ccb

Browse files
committed
Merge remote-tracking branch 'origin/1.12.x' into 2.1.x
2 parents e43abf8 + 14faee1 commit 1485ccb

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

src/Type/Constant/ConstantStringType.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,8 @@ public function isUppercaseString(): TrinaryLogic
352352
public function hasOffsetValueType(Type $offsetType): TrinaryLogic
353353
{
354354
if ($offsetType->isInteger()->yes()) {
355-
$strLenType = IntegerRangeType::fromInterval(0, strlen($this->value) - 1);
355+
$strlen = strlen($this->value);
356+
$strLenType = IntegerRangeType::fromInterval(-$strlen, $strlen - 1);
356357
return $strLenType->isSuperTypeOf($offsetType)->result;
357358
}
358359

@@ -362,15 +363,17 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic
362363
public function getOffsetValueType(Type $offsetType): Type
363364
{
364365
if ($offsetType->isInteger()->yes()) {
366+
$strlen = strlen($this->value);
367+
$strLenType = IntegerRangeType::fromInterval(-$strlen, $strlen - 1);
368+
365369
if ($offsetType instanceof ConstantIntegerType) {
366-
if ($offsetType->getValue() < strlen($this->value)) {
370+
if ($strLenType->isSuperTypeOf($offsetType)->yes()) {
367371
return new self($this->value[$offsetType->getValue()]);
368372
}
369373

370374
return new ErrorType();
371375
}
372376

373-
$strLenType = IntegerRangeType::fromInterval(0, strlen($this->value) - 1);
374377
$intersected = TypeCombinator::intersect($strLenType, $offsetType);
375378
if ($intersected instanceof IntegerRangeType) {
376379
$finiteTypes = $intersected->getFiniteTypes();

tests/PHPStan/Analyser/nsrt/string-offsets.php

+16-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
* @param int<3, 10> $threeToTen
1010
* @param int<10, max> $tenOrMore
1111
* @param int<-10, -5> $negative
12+
* @param int<min, -6> $smallerMinusSix
1213
* @param lowercase-string $lowercase
1314
*
1415
* @return void
1516
*/
16-
function doFoo($oneToThree, $threeToTen, $tenOrMore, $negative, int $i, string $lowercase) {
17+
function doFoo($oneToThree, $threeToTen, $tenOrMore, $negative, int $smallerMinusSix, int $i, string $lowercase) {
1718
$s = "world";
1819
if (rand(0, 1)) {
1920
$s = "hello";
@@ -26,10 +27,23 @@ function doFoo($oneToThree, $threeToTen, $tenOrMore, $negative, int $i, string $
2627
assertType("'e'|'l'|'o'|'r'", $s[$oneToThree]);
2728
assertType('*ERROR*', $s[$tenOrMore]);
2829
assertType("''|'d'|'l'|'o'", $s[$threeToTen]);
29-
assertType("*ERROR*", $s[$negative]);
30+
assertType("non-empty-string", $s[$negative]);
31+
assertType("*ERROR*", $s[$smallerMinusSix]);
3032

3133
$longString = "myF5HnJv799kWf8VRI7g97vwnABTwN9y2CzAVELCBfRqyqkdTzXg7BkGXcwuIOscAiT6tSuJGzVZOJnYXvkiKQzYBNjjkCPOzSKXR5YHRlVxV1BetqZz4XOmaH9mtacJ9azNYL6bNXezSBjX13BSZy02SK2udzQLbTPNQwlKadKaNkUxjtWegkb8QDFaXbzH1JENVSLVH0FYd6POBU82X1xu7FDDKYLzwsWJHBGVhG8iugjEGwLj22x5ViosUyKR";
3234
assertType("non-empty-string", $longString[$i]);
3335

3436
assertType("lowercase-string&non-empty-string", $lowercase[$i]);
3537
}
38+
39+
function bug12122()
40+
{
41+
// see https://3v4l.org/8EMdX
42+
$foo = 'fo';
43+
assertType('*ERROR*', $foo[2]);
44+
assertType("'o'", $foo[1]);
45+
assertType("'f'", $foo[0]);
46+
assertType("'o'", $foo[-1]);
47+
assertType("'f'", $foo[-2]);
48+
assertType('*ERROR*', $foo[-3]);
49+
}

tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php

+5
Original file line numberDiff line numberDiff line change
@@ -780,4 +780,9 @@ public function testInternalClassesWithOverloadedOffsetAccessInvalid84(): void
780780
$this->analyse([__DIR__ . '/data/internal-classes-overload-offset-access-invalid-php84.php'], []);
781781
}
782782

783+
public function testBug12122(): void
784+
{
785+
$this->analyse([__DIR__ . '/data/bug-12122.php'], []);
786+
}
787+
783788
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Bug12122;
4+
5+
function doFoo() {
6+
$foo = 'mystring';
7+
var_dump($foo[-1]);
8+
}

0 commit comments

Comments
 (0)