Skip to content

Commit e991fad

Browse files
committed
RegexArrayShapeMatcher - Fix PREG_UNMATCHED_AS_NULL with optional leading groups
1 parent a0dc9ed commit e991fad

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

src/Type/Php/RegexArrayShapeMatcher.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ private function buildArrayType(
271271
} else {
272272
if ($i < $countGroups - $trailingOptionals) {
273273
$optional = false;
274-
if ($this->containsUnmatchedAsNull($flags)) {
274+
if ($this->containsUnmatchedAsNull($flags) && !$captureGroup->isOptional()) {
275275
$groupValueType = TypeCombinator::removeNull($groupValueType);
276276
}
277277
} elseif ($this->containsUnmatchedAsNull($flags)) {

tests/PHPStan/Analyser/nsrt/preg_match_shapes.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,44 @@ function bug11277b(string $value): void
353353
}
354354
}
355355

356+
function bug11331a(string $url):void {
357+
// group a is actually optional as the entire (?:...) around it is optional
358+
if (preg_match('{^
359+
(?:
360+
(?<a>.+)
361+
)?
362+
(?<b>.+)}mix', $url, $matches, PREG_UNMATCHED_AS_NULL)) {
363+
assertType('array{0: string, a: string|null, 1: string|null, b: string, 2: string}', $matches);
364+
}
365+
}
366+
367+
function bug11331b(string $url):void {
368+
if (preg_match('{^
369+
(?:
370+
(?<a>.+)
371+
)?
372+
(?<b>.+)?}mix', $url, $matches, PREG_UNMATCHED_AS_NULL)) {
373+
assertType('array{0: string, a: string|null, 1: string|null, b: string|null, 2: string|null}', $matches);
374+
}
375+
}
376+
377+
function bug11331c(string $url):void {
378+
if (preg_match('{^
379+
(?:
380+
(?:https?|git)://([^/]+)/ (?# group 1 here can be null if group 2 matches)
381+
| (?# the alternation making it so that only either should match)
382+
git@([^:]+):/? (?# group 2 here can be null if group 1 matches)
383+
)
384+
(?# removing what follows makes the two first groups nullable, although it then has group 2 unsettable which looks buggy too as PREG_UNMATCHED_AS_NULL is present)
385+
([^/]+)
386+
/
387+
([^/]+?)
388+
(?:\.git|/)?
389+
$}x', $url, $matches, PREG_UNMATCHED_AS_NULL)) {
390+
assertType('array{string, string|null, string|null, string, string}', $matches);
391+
}
392+
}
393+
356394
// https://www.pcre.org/current/doc/html/pcre2pattern.html#dupgroupnumber
357395
// https://3v4l.org/09qdT
358396
function bug11291(string $s): void {

0 commit comments

Comments
 (0)