From ce9650cc378aed51e6e01f085383abfc69e9328b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 18 Jun 2022 09:50:45 +0200 Subject: [PATCH 1/2] cover vsprintf() --- .../NonEmptyStringFunctionsReturnTypeExtension.php | 1 - .../Php/SprintfFunctionDynamicReturnTypeExtension.php | 11 ++++++++--- tests/PHPStan/Analyser/data/bug-7387.php | 10 ++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php b/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php index a2e61f194f..4c1c78ca2a 100644 --- a/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php +++ b/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php @@ -31,7 +31,6 @@ public function isFunctionSupported(FunctionReflection $functionReflection): boo 'preg_quote', 'rawurlencode', 'rawurldecode', - 'vsprintf', ], true); } diff --git a/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php b/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php index 79a1cf88e0..7040f6e11e 100644 --- a/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php @@ -18,16 +18,18 @@ use function array_key_exists; use function array_shift; use function count; +use function in_array; use function is_string; use function preg_match; use function sprintf; +use function vsprintf; class SprintfFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { public function isFunctionSupported(FunctionReflection $functionReflection): bool { - return $functionReflection->getName() === 'sprintf'; + return in_array($functionReflection->getName(), ['sprintf', 'vsprintf'], true); } public function getTypeFromFunctionCall( @@ -42,7 +44,6 @@ public function getTypeFromFunctionCall( } $formatType = $scope->getType($args[0]->value); - if ($formatType instanceof ConstantStringType) { // The printf format is %[argnum$][flags][width][.precision] if (preg_match('/^%([0-9]*\$)?[0-9]*\.?[0-9]*[bdeEfFgGhHouxX]$/', $formatType->getValue(), $matches) === 1) { @@ -83,7 +84,11 @@ public function getTypeFromFunctionCall( } try { - $value = @sprintf($format, ...$values); + if ($functionReflection->getName() === 'sprtinf') { + $value = @sprintf($format, ...$values); + } else { + $value = @vsprintf($format, $values); + } } catch (Throwable) { return $returnType; } diff --git a/tests/PHPStan/Analyser/data/bug-7387.php b/tests/PHPStan/Analyser/data/bug-7387.php index ddfa237ae4..411bef4f87 100644 --- a/tests/PHPStan/Analyser/data/bug-7387.php +++ b/tests/PHPStan/Analyser/data/bug-7387.php @@ -72,4 +72,14 @@ public function escapedPercent(int $i) { // https://3v4l.org/2m50L assertType('non-empty-string', sprintf("%%d", $i)); } + + public function vsprintf(array $array) + { + assertType('numeric-string', vsprintf("%4d", explode('-', '1988-8-1'))); + assertType('numeric-string', vsprintf("%4d", $array)); + assertType('numeric-string', vsprintf("%4d", ['123'])); + assertType('non-empty-string', vsprintf("%s", ['123'])); + // too many arguments.. php silently allows it + assertType('numeric-string', vsprintf("%4d", ['123', '456'])); + } } From c367e11a1dfe8a9af00a9446e38787a6b0d2ffaf Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 18 Jun 2022 10:01:00 +0200 Subject: [PATCH 2/2] typo --- src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php b/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php index 7040f6e11e..627759ab54 100644 --- a/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php @@ -84,7 +84,7 @@ public function getTypeFromFunctionCall( } try { - if ($functionReflection->getName() === 'sprtinf') { + if ($functionReflection->getName() === 'sprintf') { $value = @sprintf($format, ...$values); } else { $value = @vsprintf($format, $values);