Skip to content

Commit

Permalink
RegexArrayShapeMatcher - support resetting non-capturing groups
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm authored and ondrejmirtes committed Jul 6, 2024
1 parent d931c89 commit 7c61b03
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/Type/Php/RegexArrayShapeMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched
$isOptionalAlternation = $group->inOptionalAlternation();
$group->forceNonOptional();
$beforeCurrentCombo = false;
} elseif ($beforeCurrentCombo) {
} elseif ($beforeCurrentCombo && !$group->resetsGroupCounter()) {
$group->forceNonOptional();
} elseif ($group->getAlternationId() === $onlyTopLevelAlternationId) {
unset($comboList[$groupId]);
Expand Down Expand Up @@ -385,6 +385,15 @@ private function walkRegexAst(
$inAlternation ? $alternationId : null,
$inOptionalQuantification,
$parentGroup,
false,
);
$parentGroup = $group;
} elseif ($ast->getId() === '#noncapturingreset') {
$group = new RegexNonCapturingGroup(
$inAlternation ? $alternationId : null,
$inOptionalQuantification,
$parentGroup,
true,
);
$parentGroup = $group;
}
Expand Down
5 changes: 5 additions & 0 deletions src/Type/Php/RegexCapturingGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public function restoreNonOptional(): void
$this->forceNonOptional = false;
}

public function resetsGroupCounter(): bool
{
return $this->parent instanceof RegexNonCapturingGroup && $this->parent->resetsGroupCounter();
}

/** @phpstan-assert-if-true !null $this->getAlternationId() */
public function inAlternation(): bool
{
Expand Down
6 changes: 6 additions & 0 deletions src/Type/Php/RegexNonCapturingGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public function __construct(
private ?int $alternationId,
private bool $inOptionalQuantification,
private RegexCapturingGroup|RegexNonCapturingGroup|null $parent,
private bool $resetGroupCounter,
)
{
}
Expand Down Expand Up @@ -42,4 +43,9 @@ public function getParent(): RegexCapturingGroup|RegexNonCapturingGroup|null
return $this->parent;
}

public function resetsGroupCounter(): bool
{
return $this->resetGroupCounter;
}

}
11 changes: 11 additions & 0 deletions tests/PHPStan/Analyser/nsrt/preg_match_shapes.php
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,14 @@ function bug11277b(string $value): void
}
}
}

// https://www.pcre.org/current/doc/html/pcre2pattern.html#dupgroupnumber
// https://3v4l.org/09qdT
function bug11291(string $s): void {
if (preg_match('/(?|(a)|(b)(c)|(d)(e)(f))/', $s, $matches)) {
assertType('array{0: string, 1: string, 2?: string, 3?: string}', $matches);
} else {
assertType('array{}', $matches);
}
assertType('array{}|array{0: string, 1: string, 2?: string, 3?: string}', $matches);
}

0 comments on commit 7c61b03

Please sign in to comment.