diff --git a/extension.neon b/extension.neon index 49f2125..2895326 100644 --- a/extension.neon +++ b/extension.neon @@ -128,6 +128,11 @@ services: tags: - phpstan.broker.dynamicStaticMethodReturnTypeExtension + - + class: PHPStan\Type\Nette\StringsMatchTypeSpecifiyingExtension + tags: + - phpstan.typeSpecifier.staticMethodTypeSpecifyingExtension + - class: PHPStan\Type\Nette\StringsReplaceCallbackClosureTypeExtension tags: diff --git a/src/Type/Nette/StringsMatchTypeSpecifiyingExtension.php b/src/Type/Nette/StringsMatchTypeSpecifiyingExtension.php new file mode 100644 index 0000000..37977a6 --- /dev/null +++ b/src/Type/Nette/StringsMatchTypeSpecifiyingExtension.php @@ -0,0 +1,70 @@ +regexArrayShapeMatcher = $regexArrayShapeMatcher; + } + + public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void + { + $this->typeSpecifier = $typeSpecifier; + } + + public function getClass(): string + { + return Strings::class; + } + + public function isStaticMethodSupported(MethodReflection $staticMethodReflection, StaticCall $node, TypeSpecifierContext $context): bool + { + return $context->true() && in_array($staticMethodReflection->getName(), ['match', 'matchAll'], true); + } + + public function specifyTypes(MethodReflection $staticMethodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes + { + $args = $node->getArgs(); + $subjectArg = $args[0] ?? null; + $patternArg = $args[1] ?? null; + + $subjectTypes = new SpecifiedTypes(); + if ($patternArg === null || $subjectArg === null) { + return $subjectTypes; + } + + if ($scope->getType($subjectArg->value)->isString()->yes()) { + $subjectType = $this->regexArrayShapeMatcher->matchSubjectExpr($patternArg->value, $scope); + if ($subjectType !== null) { + $subjectTypes = $this->typeSpecifier->create( + $subjectArg->value, + $subjectType, + $context, + $scope, + )->setRootExpr($node); + } + } + + return $subjectTypes; + } + +} diff --git a/tests/Type/Nette/StringsMatchDynamicReturnTypeExtensionTest.php b/tests/Type/Nette/StringsMatchTypeInferenceExtensionTest.php similarity index 82% rename from tests/Type/Nette/StringsMatchDynamicReturnTypeExtensionTest.php rename to tests/Type/Nette/StringsMatchTypeInferenceExtensionTest.php index 9bf6536..9686f8d 100644 --- a/tests/Type/Nette/StringsMatchDynamicReturnTypeExtensionTest.php +++ b/tests/Type/Nette/StringsMatchTypeInferenceExtensionTest.php @@ -4,13 +4,14 @@ use PHPStan\Testing\TypeInferenceTestCase; -class StringsMatchDynamicReturnTypeExtensionTest extends TypeInferenceTestCase +class StringsMatchTypeInferenceExtensionTest extends TypeInferenceTestCase { public function dataFileAsserts(): iterable { yield from self::gatherAssertTypes(__DIR__ . '/data/strings-match.php'); yield from self::gatherAssertTypes(__DIR__ . '/data/strings-match-74.php'); + yield from self::gatherAssertTypes(__DIR__ . '/data/strings-match-subject.php'); } /** diff --git a/tests/Type/Nette/data/strings-match-subject.php b/tests/Type/Nette/data/strings-match-subject.php new file mode 100644 index 0000000..424d23a --- /dev/null +++ b/tests/Type/Nette/data/strings-match-subject.php @@ -0,0 +1,32 @@ +