Skip to content

Commit ef73f11

Browse files
arshidkv12Arshid
andauthored
[Php85] Add ChrArgModuloRector (#7190)
* Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers * Wrap chr() argument with % 256 to avoid deprecated out-of-range integers --------- Co-authored-by: Arshid <arshid@Arshids-MacBook-Air.local>
1 parent b5f3663 commit ef73f11

8 files changed

Lines changed: 175 additions & 0 deletions

File tree

config/set/php85.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Rector\Php85\Rector\ClassMethod\NullDebugInfoReturnRector;
1212
use Rector\Php85\Rector\Const_\DeprecatedAnnotationToDeprecatedAttributeRector;
1313
use Rector\Php85\Rector\FuncCall\ArrayKeyExistsNullToEmptyStringRector;
14+
use Rector\Php85\Rector\FuncCall\ChrArgModuloRector;
1415
use Rector\Php85\Rector\FuncCall\RemoveFinfoBufferContextArgRector;
1516
use Rector\Php85\Rector\Switch_\ColonAfterSwitchCaseRector;
1617
use Rector\Removing\Rector\FuncCall\RemoveFuncCallArgRector;
@@ -34,6 +35,7 @@
3435
DeprecatedAnnotationToDeprecatedAttributeRector::class,
3536
ColonAfterSwitchCaseRector::class,
3637
ArrayKeyExistsNullToEmptyStringRector::class,
38+
ChrArgModuloRector::class,
3739
]
3840
);
3941

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Php85\Rector\FuncCall\ChrArgModuloRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class ChrArgModuloRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
namespace Rector\Tests\Php85\Rector\FuncCall\ChrArgModuloRector\Fixture;
3+
4+
echo chr(300);
5+
?>
6+
-----
7+
<?php
8+
namespace Rector\Tests\Php85\Rector\FuncCall\ChrArgModuloRector\Fixture;
9+
10+
echo chr(300 % 256);
11+
?>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
namespace Rector\Tests\Php85\Rector\FuncCall\ChrArgModuloRector\Fixture;
3+
4+
$n = 400;
5+
echo chr($n);
6+
?>
7+
-----
8+
<?php
9+
namespace Rector\Tests\Php85\Rector\FuncCall\ChrArgModuloRector\Fixture;
10+
11+
$n = 400;
12+
echo chr($n % 256);
13+
?>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
namespace Rector\Tests\Php85\Rector\FuncCall\ChrArgModuloRector\Fixture;
3+
4+
echo chr(44);
5+
?>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Php85\Rector\FuncCall\ChrArgModuloRector;
7+
use Rector\ValueObject\PhpVersion;
8+
9+
return static function (RectorConfig $rectorConfig): void {
10+
$rectorConfig->rule(ChrArgModuloRector::class);
11+
12+
$rectorConfig->phpVersion(PhpVersion::PHP_85);
13+
};
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Php85\Rector\FuncCall;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\BinaryOp\Mod;
9+
use PhpParser\Node\Expr\FuncCall;
10+
use PhpParser\Node\Scalar\LNumber;
11+
use Rector\PhpParser\Node\Value\ValueResolver;
12+
use Rector\Rector\AbstractRector;
13+
use Rector\ValueObject\PhpVersionFeature;
14+
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
15+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
16+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
17+
18+
/**
19+
* @see https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_passing_integers_outside_the_interval_0_255_to_chr
20+
* @see \Rector\Tests\Php85\Rector\FuncCall\ChrArgModuloRector\ChrArgModuloRectorTest
21+
*/
22+
final class ChrArgModuloRector extends AbstractRector implements MinPhpVersionInterface
23+
{
24+
public function __construct(
25+
private readonly ValueResolver $valueResolver
26+
){
27+
28+
}
29+
30+
public function getRuleDefinition(): RuleDefinition
31+
{
32+
return new RuleDefinition(
33+
'Wrap chr() argument with % 256 to avoid deprecated out-of-range integers',
34+
[
35+
new CodeSample(
36+
<<<'CODE_SAMPLE'
37+
echo chr(300);
38+
CODE_SAMPLE
39+
,
40+
<<<'CODE_SAMPLE'
41+
echo chr(300 % 256);
42+
CODE_SAMPLE
43+
),
44+
]
45+
);
46+
}
47+
48+
public function getNodeTypes(): array
49+
{
50+
return [FuncCall::class];
51+
}
52+
53+
/**
54+
* @param FuncCall $node
55+
*/
56+
public function refactor(Node $node): ?Node
57+
{
58+
if ($node->isFirstClassCallable()) {
59+
return null;
60+
}
61+
62+
if (! $this->isName($node, 'chr')) {
63+
return null;
64+
}
65+
66+
$args = $node->getArgs();
67+
68+
if (! isset($node->args[0])) {
69+
return null;
70+
}
71+
72+
$argExpr = $args[0]->value;
73+
74+
if ($argExpr instanceof Mod) {
75+
return null;
76+
}
77+
78+
$value = $this->valueResolver->getValue($argExpr);
79+
if (! is_int($value)) {
80+
return null;
81+
}
82+
83+
if ( $value >= 0 && $value <= 255) {
84+
return null;
85+
}
86+
87+
$args[0]->value = new Mod($argExpr, new LNumber(256));
88+
$node->args = $args;
89+
90+
return $node;
91+
}
92+
93+
public function provideMinPhpVersion(): int
94+
{
95+
return PhpVersionFeature::DEPRECATE_OUTSIDE_INTERVEL_VAL_IN_CHR_FUNCTION;
96+
}
97+
}

src/ValueObject/PhpVersionFeature.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,4 +798,10 @@ final class PhpVersionFeature
798798
* @var int
799799
*/
800800
public const DEPRECATE_NULL_ARG_IN_ARRAY_KEY_EXISTS_FUNCTION = PhpVersion::PHP_85;
801+
802+
/**
803+
* @see https://wiki.php.net/rfc/deprecations_php_8_5#eprecate_passing_integers_outside_the_interval_0_255_to_chr
804+
* @var int
805+
*/
806+
public const DEPRECATE_OUTSIDE_INTERVEL_VAL_IN_CHR_FUNCTION = PhpVersion::PHP_85;
801807
}

0 commit comments

Comments
 (0)