diff --git a/composer.json b/composer.json index 3ab7df2..a33169a 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": "^8.1", - "phpstan/phpstan": "^2.1.30", + "phpstan/phpstan": "^2.2.2", "thecodingmachine/safe": "^3.1", "nikic/php-parser": "^5" }, diff --git a/src/Type/Php/PregMatchTypeSpecifyingExtension.php b/src/Type/Php/PregMatchTypeSpecifyingExtension.php index f560a08..97dc7d2 100644 --- a/src/Type/Php/PregMatchTypeSpecifyingExtension.php +++ b/src/Type/Php/PregMatchTypeSpecifyingExtension.php @@ -42,12 +42,32 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n { $args = $node->getArgs(); $patternArg = $args[0] ?? null; + $subjectArg = $args[1] ?? null; $matchesArg = $args[2] ?? null; $flagsArg = $args[3] ?? null; - if ($patternArg === null || $matchesArg === null + $subjectTypes = new SpecifiedTypes(); + if ($patternArg === null) { + return $subjectTypes; + } + + if ($subjectArg !== null + && $context->true() + && $scope->getType($subjectArg->value)->isString()->yes() ) { - return new SpecifiedTypes(); + $subjectType = $this->regexShapeMatcher->matchSubjectExpr($patternArg->value, $scope); + if ($subjectType !== null) { + $subjectTypes = $this->typeSpecifier->create( + $subjectArg->value, + $subjectType, + $context, + $scope, + )->setRootExpr($node); + } + } + + if ($matchesArg === null) { + return $subjectTypes; } $flagsType = null; @@ -69,7 +89,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $matchedType = $this->regexShapeMatcher->matchAllExpr($patternArg->value, $flagsType, $wasMatched, $scope); } if ($matchedType === null) { - return new SpecifiedTypes(); + return $subjectTypes; } $overwrite = false; @@ -88,6 +108,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $types = $types->setAlwaysOverwriteTypes(); } - return $types; + return $subjectTypes->unionWith($types); } } diff --git a/tests/Type/Php/data/preg_match_checked.php b/tests/Type/Php/data/preg_match_checked.php index 0fbb3d9..70da43e 100644 --- a/tests/Type/Php/data/preg_match_checked.php +++ b/tests/Type/Php/data/preg_match_checked.php @@ -18,3 +18,9 @@ if(\Safe\preg_match($pattern, $string, $matches)) { \PHPStan\Testing\assertSuperType($type, $matches); } + +function doFoo(string $string) { + if(\Safe\preg_match('/Price: /i', $string)) { + \PHPStan\Testing\assertType('non-falsy-string', $string); + } +} \ No newline at end of file