From 466bed0befcadcede0001f913a576112ce470ddf Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 10 Sep 2025 16:37:04 +0200 Subject: [PATCH 1/5] Fix "Crash: str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters" --- src/Analyser/MutatingScope.php | 7 +++++- .../Analyser/nsrt/bug-13481-before-php83.php | 21 +++++++++++++++++ .../PHPStan/Analyser/nsrt/bug-13481-php83.php | 23 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php create mode 100644 tests/PHPStan/Analyser/nsrt/bug-13481-php83.php diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 8be043daf2..eac5617023 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -139,6 +139,7 @@ use PHPStan\Type\VoidType; use stdClass; use Throwable; +use ValueError; use function abs; use function array_filter; use function array_key_exists; @@ -1750,7 +1751,11 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu && !is_numeric($varValue) && function_exists('str_increment') ) { - $varValue = str_increment($varValue); + try { + $varValue = str_increment($varValue); + } catch (ValueError) { + return new ErrorType(); + } } elseif (!is_bool($varValue)) { ++$varValue; } diff --git a/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php b/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php new file mode 100644 index 0000000000..28e0a34974 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php @@ -0,0 +1,21 @@ += 8.3 + +namespace bug13481Php83; + +use function PHPStan\Testing\assertType; +use function str_increment; + +function bug13481() { + $s = 'ab c1'; + assertType("*ERROR*", str_increment($s)); + + ++$s; + assertType("*ERROR*", $s); +} + +function bug13481b() { + $s = '%'; + assertType("*ERROR*", str_increment($s)); + + ++$s; + assertType("*ERROR*", $s); +} + From e68e1e4ab2b07a0ab37bdff85ae3b3b2b1f640e6 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 10 Sep 2025 17:28:26 +0200 Subject: [PATCH 2/5] Update bug-13481-before-php83.php --- tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php b/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php index 28e0a34974..ef4dc043d8 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php +++ b/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php @@ -6,7 +6,7 @@ function bug13481() { $s = 'ab c1'; - assertType("'ab c2'", str_increment($s)); + assertType("*ERROR*", str_increment($s)); ++$s; assertType("'ab c2'", $s); @@ -14,7 +14,7 @@ function bug13481() { function bug13481b() { $s = '%'; - assertType("'%'", str_increment($s)); + assertType("*ERROR*", str_increment($s)); ++$s; assertType("'%'", $s); From b8e797c520afa5b7741ae531ba1399e800646c60 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 10 Sep 2025 20:23:17 +0200 Subject: [PATCH 3/5] simplify --- src/Analyser/MutatingScope.php | 37 ++++++------------- .../Analyser/nsrt/bug-13481-before-php83.php | 21 ----------- .../{bug-13481-php83.php => bug-13481.php} | 4 +- 3 files changed, 13 insertions(+), 49 deletions(-) delete mode 100644 tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php rename tests/PHPStan/Analyser/nsrt/{bug-13481-php83.php => bug-13481.php} (86%) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index eac5617023..83c6cc3f27 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -139,7 +139,6 @@ use PHPStan\Type\VoidType; use stdClass; use Throwable; -use ValueError; use function abs; use function array_filter; use function array_key_exists; @@ -152,18 +151,17 @@ use function array_values; use function count; use function explode; -use function function_exists; use function get_class; use function implode; use function in_array; use function is_array; use function is_bool; -use function is_numeric; use function is_string; use function ltrim; use function md5; +use function restore_error_handler; +use function set_error_handler; use function sprintf; -use function str_increment; use function str_starts_with; use function strlen; use function strtolower; @@ -1738,37 +1736,24 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu $varScalars = $varType->getConstantScalarValues(); if (count($varScalars) > 0) { - $newTypes = []; + $newValues = []; + // silence string incrementing deprecation warnings + set_error_handler(static fn (): bool => true); foreach ($varScalars as $varValue) { - // until PHP 8.5 it was valid to increment/decrement an empty string. - // see https://github.com/php/php-src/issues/19597 if ($node instanceof Expr\PreInc) { - if ($varValue === '') { - $varValue = '1'; - } elseif ( - is_string($varValue) - && !is_numeric($varValue) - && function_exists('str_increment') - ) { - try { - $varValue = str_increment($varValue); - } catch (ValueError) { - return new ErrorType(); - } - } elseif (!is_bool($varValue)) { + if (!is_bool($varValue)) { ++$varValue; } } else { - if ($varValue === '') { - $varValue = -1; - } elseif (is_numeric($varValue)) { - --$varValue; - } + --$varValue; } - $newTypes[] = $this->getTypeFromValue($varValue); + $newValues[] = $varValue; } + restore_error_handler(); + + $newTypes = array_map(fn ($value): Type => $this->getTypeFromValue($value), $newValues); return TypeCombinator::union(...$newTypes); } elseif ($varType->isString()->yes()) { if ($varType->isLiteralString()->yes()) { diff --git a/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php b/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php deleted file mode 100644 index ef4dc043d8..0000000000 --- a/tests/PHPStan/Analyser/nsrt/bug-13481-before-php83.php +++ /dev/null @@ -1,21 +0,0 @@ -= 8.3 + Date: Wed, 10 Sep 2025 20:25:50 +0200 Subject: [PATCH 4/5] Update bug-13481.php --- tests/PHPStan/Analyser/nsrt/bug-13481.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PHPStan/Analyser/nsrt/bug-13481.php b/tests/PHPStan/Analyser/nsrt/bug-13481.php index 059bcb300d..6af131f1e3 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-13481.php +++ b/tests/PHPStan/Analyser/nsrt/bug-13481.php @@ -10,7 +10,7 @@ function bug13481() { assertType("*ERROR*", str_increment($s)); ++$s; - assertType("*ERROR*", $s); + assertType("'ab c2'", $s); } function bug13481b() { @@ -18,6 +18,6 @@ function bug13481b() { assertType("*ERROR*", str_increment($s)); ++$s; - assertType("*ERROR*", $s); + assertType("'%'", $s); } From 5cbcf06e149ad17be60b826cdddcac3ee2567714 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 10 Sep 2025 20:36:58 +0200 Subject: [PATCH 5/5] fix build --- src/Analyser/MutatingScope.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 83c6cc3f27..a0c29e5f0e 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1746,7 +1746,7 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu ++$varValue; } } else { - --$varValue; + --$varValue; // @phpstan-ignore preDec.nonNumeric } $newValues[] = $varValue;