Skip to content

Commit 9a3c102

Browse files
authored
RegexArrayShapeMatcher: fix preg_match_all with PREG_OFFSET_CAPTURE
1 parent 2acc115 commit 9a3c102

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

src/Type/Php/RegexArrayShapeMatcher.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ private function createSubjectValueType(TrinaryLogic $wasMatched, int $flags, bo
351351
$subjectValueType = TypeCombinator::removeNull($this->getValueType(new StringType(), $flags, $matchesAll));
352352

353353
if ($matchesAll) {
354-
if (!$wasMatched->yes()) {
354+
if (!$wasMatched->yes() && !$this->containsOffsetCapture($flags)) {
355355
$subjectValueType = TypeCombinator::union($subjectValueType, new ConstantStringType(''));
356356
}
357357
if ($this->containsPatternOrder($flags)) {
@@ -421,6 +421,11 @@ private function createGroupValueType(RegexCapturingGroup $captureGroup, Trinary
421421
return $groupValueType;
422422
}
423423

424+
private function containsOffsetCapture(int $flags): bool
425+
{
426+
return ($flags & PREG_OFFSET_CAPTURE) !== 0;
427+
}
428+
424429
private function containsPatternOrder(int $flags): bool
425430
{
426431
// If no order flag is given, PREG_PATTERN_ORDER is assumed.
@@ -463,7 +468,7 @@ private function getValueType(Type $baseType, int $flags, bool $matchesAll): Typ
463468
$offsetType = IntegerRangeType::fromInterval(-1, null);
464469
}
465470

466-
if (($flags & PREG_OFFSET_CAPTURE) !== 0) {
471+
if ($this->containsOffsetCapture($flags)) {
467472
$builder = ConstantArrayTypeBuilder::createEmpty();
468473

469474
$builder->setOffsetValueType(

tests/PHPStan/Analyser/nsrt/preg_match_all_shapes.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,15 @@ function (string $size): void {
133133
assertType("array{0: list<array{string|null, int<-1, max>}>, num: list<array{numeric-string|null, int<-1, max>}>, 1: list<array{numeric-string|null, int<-1, max>}>, suffix: list<array{'ab'|null, int<-1, max>}>, 2: list<array{'ab'|null, int<-1, max>}>}", $matches);
134134
}
135135
};
136+
137+
class Bug11457
138+
{
139+
public function sayHello(string $content): void
140+
{
141+
if (preg_match_all("~text=~mU", $content, $matches, PREG_OFFSET_CAPTURE) === 0) {
142+
return;
143+
}
144+
145+
assertType('array{list<array{string, int<0, max>}>}', $matches);
146+
}
147+
}

0 commit comments

Comments
 (0)