Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions build/ignore-by-php-version.neon.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@
} else {
$includes[] = __DIR__ . '/new-phpunit.neon';
}

if (PHP_VERSION_ID < 80300) {
$includes[] = __DIR__ . '/str-increment.neon';
}

$config = [];
$config['includes'] = $includes;

Expand Down
4 changes: 4 additions & 0 deletions build/str-increment.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
parameters:
ignoreErrors:
-
message: '#^Used function str_increment not found\.#'
22 changes: 19 additions & 3 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
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;
Expand All @@ -160,6 +161,7 @@
use function ltrim;
use function md5;
use function sprintf;
use function str_increment;
use function str_starts_with;
use function strlen;
use function strtolower;
Expand Down Expand Up @@ -1731,12 +1733,26 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu
$newTypes = [];

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 (!is_bool($varValue)) {
if ($varValue === '') {
$varValue = '1';
Comment on lines +1739 to +1740
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neither ++$varValue nor str_increment($varValue) is allowed on PHP 8.5 when $varValue is a empty string.

therefore we hardcode the value which this operation lead to when PHP < 8.5

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And what about non-empty strings? This PR initially handled that but does not anymore.

} elseif (
is_string($varValue)
&& !is_numeric($varValue)
&& function_exists('str_increment')
) {
$varValue = str_increment($varValue);
} elseif (!is_bool($varValue)) {
++$varValue;
}
} elseif (is_numeric($varValue)) {
--$varValue;
} else {
if ($varValue === '') {
$varValue = -1;
} elseif (is_numeric($varValue)) {
--$varValue;
}
}

$newTypes[] = $this->getTypeFromValue($varValue);
Expand Down
11 changes: 11 additions & 0 deletions src/Type/Php/StrIncrementDecrementFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\AutowiredService;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use function chr;
use function count;
use function function_exists;
use function implode;
use function in_array;
use function is_float;
Expand All @@ -21,6 +23,7 @@
use function is_string;
use function ord;
use function preg_match;
use function str_increment;
use function str_split;
use function stripos;

Expand Down Expand Up @@ -103,6 +106,14 @@ private function increment(string $s): string
}
}

if ($s === '') {
throw new ShouldNotHappenException();
}

if (function_exists('str_increment')) {
return str_increment($s);
}

return (string) ++$s;
}

Expand Down
23 changes: 23 additions & 0 deletions tests/PHPStan/Analyser/nsrt/pre-dec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace PreDec;

use function PHPStan\Testing\assertType;

function doFoo() {
$s = '';
--$s;
assertType("-1", $s);
}

function doFoo2() {
$s = '123';
--$s;
assertType("122", $s);
}

function doFooBar() {
$s = 'abc';
--$s;
assertType("'abc'", $s);
}
23 changes: 23 additions & 0 deletions tests/PHPStan/Analyser/nsrt/pre-inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace PreInc;

use function PHPStan\Testing\assertType;

function doFoo() {
$s = '';
++$s;
assertType("'1'", $s);
}

function doFoo2() {
$s = '123';
++$s;
assertType("124", $s);
}

function doFooBar() {
$s = 'abc';
++$s;
assertType("'abd'", $s);
}
Loading