Skip to content

Commit

Permalink
marchStrictGroups variants PHPStan support (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
Seldaek authored Jul 11, 2024
1 parent 9f7f3d2 commit 59a4eec
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/PHPStan/PregMatchParameterOutTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function isStaticMethodSupported(MethodReflection $methodReflection, Para
{
return
$methodReflection->getDeclaringClass()->getName() === Preg::class
&& in_array($methodReflection->getName(), ['match', 'isMatch'], true)
&& in_array($methodReflection->getName(), ['match', 'isMatch', 'matchStrictGroups', 'isMatchStrictGroups'], true)
&& $parameter->getName() === 'matches';
}

Expand Down
21 changes: 20 additions & 1 deletion src/PHPStan/PregMatchTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
use PHPStan\Analyser\TypeSpecifierContext;
use PHPStan\Reflection\MethodReflection;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Php\RegexArrayShapeMatcher;
use PHPStan\Type\StaticMethodTypeSpecifyingExtension;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\Type;

final class PregMatchTypeSpecifyingExtension implements StaticMethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
{
Expand Down Expand Up @@ -43,7 +46,7 @@ public function getClass(): string

public function isStaticMethodSupported(MethodReflection $methodReflection, StaticCall $node, TypeSpecifierContext $context): bool
{
return in_array($methodReflection->getName(), ['match', 'isMatch'], true) && !$context->null();
return in_array($methodReflection->getName(), ['match', 'isMatch', 'matchStrictGroups', 'isMatchStrictGroups'], true) && !$context->null();
}

public function specifyTypes(MethodReflection $methodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
Expand All @@ -70,6 +73,22 @@ public function specifyTypes(MethodReflection $methodReflection, StaticCall $nod
return new SpecifiedTypes();
}

if (
in_array($methodReflection->getName(), ['matchStrictGroups', 'isMatchStrictGroups'], true)
&& count($matchedType->getConstantArrays()) > 0
) {
$matchedType = $matchedType->getConstantArrays()[0];
$matchedType = new ConstantArrayType(
$matchedType->getKeyTypes(),
array_map(static function (Type $valueType): Type {
return TypeCombinator::removeNull($valueType);
}, $matchedType->getValueTypes()),
[0],
[],
$matchedType->isList()
);
}

$overwrite = false;
if ($context->false()) {
$overwrite = true;
Expand Down
24 changes: 24 additions & 0 deletions tests/PHPStanTests/nsrt/preg-match.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,30 @@ function doMatch(string $s): void
assertType('array{}|array{0: string, currency: string|null, 1: string|null}', $matches);
}

function doMatchStrictGroups(string $s): void
{
if (Preg::matchStrictGroups('/Price: /i', $s, $matches)) {
assertType('array{string}', $matches);
} else {
assertType('array{}', $matches);
}
assertType('array{}|array{string}', $matches);

if (Preg::matchStrictGroups('/Price: (£|€)\d+/', $s, $matches)) {
assertType('array{string, string}', $matches);
} else {
assertType('array{}', $matches);
}
assertType('array{}|array{string, string}', $matches);

if (Preg::isMatchStrictGroups('/Price: (?<test>£|€)\d+/', $s, $matches)) {
assertType('array{0: string, test: string, 1: string}', $matches);
} else {
assertType('array{}', $matches);
}
assertType('array{}|array{0: string, test: string, 1: string}', $matches);
}

// disabled until https://github.com/phpstan/phpstan-src/pull/3185 can be resolved
//
//function identicalMatch(string $s): void
Expand Down

0 comments on commit 59a4eec

Please sign in to comment.