From 255b97f310ba58b97e961eeaf65771738ccee2a6 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 22 Feb 2022 09:31:44 +0100 Subject: [PATCH 1/3] implemented ConstantStringType inference to StrRepeatFunctionReturnTypeExtension --- src/Type/Php/StrRepeatFunctionReturnTypeExtension.php | 4 ++++ tests/PHPStan/Analyser/data/literal-string.php | 1 + 2 files changed, 5 insertions(+) diff --git a/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php b/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php index 793adbffe7..8bb6556277 100644 --- a/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php @@ -42,6 +42,10 @@ public function getTypeFromFunctionCall( return new ConstantStringType(''); } + if ($inputType instanceof ConstantStringType && $multiplierType instanceof ConstantIntegerType) { + return new ConstantStringType(str_repeat($inputType->getValue(), $multiplierType->getValue())); + } + $accessoryTypes = []; if ($inputType->isNonEmptyString()->yes()) { if (IntegerRangeType::fromInterval(1, null)->isSuperTypeOf($multiplierType)->yes()) { diff --git a/tests/PHPStan/Analyser/data/literal-string.php b/tests/PHPStan/Analyser/data/literal-string.php index 28fce66175..3f95feab8c 100644 --- a/tests/PHPStan/Analyser/data/literal-string.php +++ b/tests/PHPStan/Analyser/data/literal-string.php @@ -27,6 +27,7 @@ public function doFoo($literalString, string $string) assertType('literal-string', str_repeat($literalString, 10)); assertType('literal-string', str_repeat('', 10)); assertType('literal-string&non-empty-string', str_repeat('foo', 10)); + assertType("'?,?,?,'", str_repeat('?,', 3)); assertType('non-empty-string', str_pad($string, 5, $string)); assertType('non-empty-string', str_pad($literalString, 5, $string)); From 954e089b4d25d5100d86bc22542a8769536e6f70 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 22 Feb 2022 09:32:56 +0100 Subject: [PATCH 2/3] adjusted test-expectations for the more precise result --- tests/PHPStan/Analyser/data/literal-string.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PHPStan/Analyser/data/literal-string.php b/tests/PHPStan/Analyser/data/literal-string.php index 3f95feab8c..4787fbd356 100644 --- a/tests/PHPStan/Analyser/data/literal-string.php +++ b/tests/PHPStan/Analyser/data/literal-string.php @@ -25,8 +25,8 @@ public function doFoo($literalString, string $string) assertType('string', str_repeat($string, 10)); assertType('literal-string', str_repeat($literalString, 10)); - assertType('literal-string', str_repeat('', 10)); - assertType('literal-string&non-empty-string', str_repeat('foo', 10)); + assertType("''", str_repeat('', 10)); + assertType("'foofoofoofoofoofoofoofoofoofoo'", str_repeat('foo', 10)); assertType("'?,?,?,'", str_repeat('?,', 3)); assertType('non-empty-string', str_pad($string, 5, $string)); From e3df0c3ab9ae7b2c3cb78947aeb8597fb4d336bd Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 22 Feb 2022 12:31:10 +0100 Subject: [PATCH 3/3] don't crash on negative multiplier --- src/Type/Php/StrRepeatFunctionReturnTypeExtension.php | 6 ++++++ tests/PHPStan/Analyser/data/literal-string.php | 1 + 2 files changed, 7 insertions(+) diff --git a/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php b/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php index 8bb6556277..cc8a09a3cd 100644 --- a/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrRepeatFunctionReturnTypeExtension.php @@ -12,9 +12,11 @@ use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\IntegerRangeType; use PHPStan\Type\IntersectionType; +use PHPStan\Type\NeverType; use PHPStan\Type\StringType; use PHPStan\Type\Type; use function count; +use function str_repeat; class StrRepeatFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension { @@ -42,6 +44,10 @@ public function getTypeFromFunctionCall( return new ConstantStringType(''); } + if ($multiplierType instanceof ConstantIntegerType && $multiplierType->getValue() < 0) { + return new NeverType(); + } + if ($inputType instanceof ConstantStringType && $multiplierType instanceof ConstantIntegerType) { return new ConstantStringType(str_repeat($inputType->getValue(), $multiplierType->getValue())); } diff --git a/tests/PHPStan/Analyser/data/literal-string.php b/tests/PHPStan/Analyser/data/literal-string.php index 4787fbd356..c55c34feff 100644 --- a/tests/PHPStan/Analyser/data/literal-string.php +++ b/tests/PHPStan/Analyser/data/literal-string.php @@ -28,6 +28,7 @@ public function doFoo($literalString, string $string) assertType("''", str_repeat('', 10)); assertType("'foofoofoofoofoofoofoofoofoofoo'", str_repeat('foo', 10)); assertType("'?,?,?,'", str_repeat('?,', 3)); + assertType("*NEVER*", str_repeat('?,', -3)); assertType('non-empty-string', str_pad($string, 5, $string)); assertType('non-empty-string', str_pad($literalString, 5, $string));