Skip to content

Commit 5d0ec22

Browse files
committed
Updated Rector to commit 11b6e0227021e4e048b71ee4acd7ad8ffd91e9ee
rectorphp/rector-src@11b6e02 feat(php86): add min/max to clamp rector (#7942)
1 parent 661063f commit 5d0ec22

14 files changed

Lines changed: 178 additions & 5 deletions

File tree

config/set/level/up-to-php86.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare (strict_types=1);
4+
namespace RectorPrefix202604;
5+
6+
use Rector\Config\RectorConfig;
7+
use Rector\Set\ValueObject\LevelSetList;
8+
use Rector\Set\ValueObject\SetList;
9+
return static function (RectorConfig $rectorConfig): void {
10+
$rectorConfig->sets([SetList::PHP_86, LevelSetList::UP_TO_PHP_85]);
11+
};

config/set/php86.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare (strict_types=1);
4+
namespace RectorPrefix202604;
5+
6+
use Rector\Config\RectorConfig;
7+
use Rector\Php86\Rector\FuncCall\MinMaxToClampRector;
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rules([MinMaxToClampRector::class]);
10+
};
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
3+
declare (strict_types=1);
4+
namespace Rector\Php86\Rector\FuncCall;
5+
6+
use PhpParser\Node;
7+
use PhpParser\Node\Arg;
8+
use PhpParser\Node\Expr;
9+
use PhpParser\Node\Expr\FuncCall;
10+
use Rector\Rector\AbstractRector;
11+
use Rector\ValueObject\PhpVersionFeature;
12+
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
13+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
14+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
15+
/**
16+
* @see \Rector\Tests\Php86\Rector\FuncCall\MinMaxToClampRector\MinMaxToClampRectorTest
17+
*/
18+
final class MinMaxToClampRector extends AbstractRector implements MinPhpVersionInterface
19+
{
20+
public function getRuleDefinition(): RuleDefinition
21+
{
22+
return new RuleDefinition('Convert nested min()/max() calls to clamp()', [new CodeSample(<<<'CODE_SAMPLE'
23+
$result = max(0, min(100, $value));
24+
CODE_SAMPLE
25+
, <<<'CODE_SAMPLE'
26+
$result = clamp($value, 0, 100);
27+
CODE_SAMPLE
28+
)]);
29+
}
30+
public function getNodeTypes(): array
31+
{
32+
return [FuncCall::class];
33+
}
34+
/**
35+
* @param FuncCall $node
36+
*/
37+
public function refactor(Node $node): ?Node
38+
{
39+
if ($node->isFirstClassCallable()) {
40+
return null;
41+
}
42+
if ($this->isName($node, 'max')) {
43+
return $this->matchClampFuncCall($node, 'min');
44+
}
45+
if ($this->isName($node, 'min')) {
46+
return $this->matchClampFuncCall($node, 'max');
47+
}
48+
return null;
49+
}
50+
public function provideMinPhpVersion(): int
51+
{
52+
return PhpVersionFeature::CLAMP;
53+
}
54+
private function matchClampFuncCall(FuncCall $outerFuncCall, string $expectedInnerFuncName): ?FuncCall
55+
{
56+
$args = $outerFuncCall->getArgs();
57+
if (count($args) !== 2) {
58+
return null;
59+
}
60+
if (!$this->isSupportedArg($args[0]) || !$this->isSupportedArg($args[1])) {
61+
return null;
62+
}
63+
$leftValue = $args[0]->value;
64+
$rightValue = $args[1]->value;
65+
if ($leftValue instanceof FuncCall) {
66+
return $this->createClampFuncCall($outerFuncCall, $leftValue, $rightValue, $expectedInnerFuncName);
67+
}
68+
if ($rightValue instanceof FuncCall) {
69+
return $this->createClampFuncCall($outerFuncCall, $rightValue, $leftValue, $expectedInnerFuncName);
70+
}
71+
return null;
72+
}
73+
private function createClampFuncCall(FuncCall $outerFuncCall, FuncCall $innerFuncCall, Expr $outerBoundExpr, string $expectedInnerFuncName): ?FuncCall
74+
{
75+
if ($innerFuncCall->isFirstClassCallable()) {
76+
return null;
77+
}
78+
if (!$this->isName($innerFuncCall, $expectedInnerFuncName)) {
79+
return null;
80+
}
81+
$args = $innerFuncCall->getArgs();
82+
if (count($args) !== 2) {
83+
return null;
84+
}
85+
if (!$this->isSupportedArg($args[0]) || !$this->isSupportedArg($args[1])) {
86+
return null;
87+
}
88+
$valueAndBound = $this->matchValueAndKnownBound($args[0]->value, $args[1]->value);
89+
if ($valueAndBound === null) {
90+
return null;
91+
}
92+
[$valueExpr, $innerBoundExpr] = $valueAndBound;
93+
if ($this->isName($outerFuncCall, 'max')) {
94+
return $this->nodeFactory->createFuncCall('clamp', [$valueExpr, $outerBoundExpr, $innerBoundExpr]);
95+
}
96+
return $this->nodeFactory->createFuncCall('clamp', [$valueExpr, $innerBoundExpr, $outerBoundExpr]);
97+
}
98+
private function isSupportedArg(Arg $arg): bool
99+
{
100+
return !$arg->unpack && $arg->name === null;
101+
}
102+
/**
103+
* @return array{Expr, Expr}|null
104+
*/
105+
private function matchValueAndKnownBound(Expr $firstExpr, Expr $secondExpr): ?array
106+
{
107+
$isFirstKnownBound = $this->isKnownBound($firstExpr);
108+
$isSecondKnownBound = $this->isKnownBound($secondExpr);
109+
if ($isFirstKnownBound === $isSecondKnownBound) {
110+
return null;
111+
}
112+
if ($isFirstKnownBound) {
113+
return [$secondExpr, $firstExpr];
114+
}
115+
return [$firstExpr, $secondExpr];
116+
}
117+
private function isKnownBound(Expr $expr): bool
118+
{
119+
return $this->getNativeType($expr)->isConstantScalarValue()->yes();
120+
}
121+
}

src/Application/VersionResolver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ final class VersionResolver
1919
* @api
2020
* @var string
2121
*/
22-
public const PACKAGE_VERSION = 'febd1cc5cd7e0e7523fedad957fa45384c1764eb';
22+
public const PACKAGE_VERSION = '11b6e0227021e4e048b71ee4acd7ad8ffd91e9ee';
2323
/**
2424
* @api
2525
* @var string
2626
*/
27-
public const RELEASE_DATE = '2026-04-01 18:25:54';
27+
public const RELEASE_DATE = '2026-04-02 18:13:42';
2828
/**
2929
* @var int
3030
*/

src/Config/Level/CodingStyleLevel.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use Rector\CodingStyle\Rector\Use_\SeparateMultiUseImportsRector;
3232
use Rector\Contract\Rector\RectorInterface;
3333
use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
34+
use Rector\Php86\Rector\FuncCall\MinMaxToClampRector;
3435
use Rector\Transform\Rector\FuncCall\FuncCallToConstFetchRector;
3536
use Rector\Visibility\Rector\ClassMethod\ExplicitPublicClassMethodRector;
3637
/**
@@ -52,7 +53,7 @@ final class CodingStyleLevel
5253
*
5354
* @var array<class-string<RectorInterface>>
5455
*/
55-
public const RULES = [SeparateMultiUseImportsRector::class, NewlineBetweenClassLikeStmtsRector::class, NewlineAfterStatementRector::class, RemoveFinalFromConstRector::class, NullableCompareToNullRector::class, ConsistentImplodeRector::class, TernaryConditionVariableAssignmentRector::class, SimplifyQuoteEscapeRector::class, StringClassNameToClassConstantRector::class, CatchExceptionNameMatchingTypeRector::class, SplitDoubleAssignRector::class, EncapsedStringsToSprintfRector::class, WrapEncapsedVariableInCurlyBracesRector::class, NewlineBeforeNewAssignSetRector::class, MakeInheritedMethodVisibilitySameAsParentRector::class, CallUserFuncArrayToVariadicRector::class, VersionCompareFuncCallToConstantRector::class, CountArrayToEmptyArrayComparisonRector::class, CallUserFuncToMethodCallRector::class, FuncGetArgsToVariadicParamRector::class, StrictArraySearchRector::class, StrictInArrayRector::class, UseClassKeywordForClassNameResolutionRector::class, SplitGroupedPropertiesRector::class, SplitGroupedClassConstantsRector::class, ExplicitPublicClassMethodRector::class, RemoveUselessAliasInUseStatementRector::class, BinaryOpStandaloneAssignsToDirectRector::class];
56+
public const RULES = [SeparateMultiUseImportsRector::class, NewlineBetweenClassLikeStmtsRector::class, NewlineAfterStatementRector::class, RemoveFinalFromConstRector::class, NullableCompareToNullRector::class, ConsistentImplodeRector::class, TernaryConditionVariableAssignmentRector::class, SimplifyQuoteEscapeRector::class, StringClassNameToClassConstantRector::class, CatchExceptionNameMatchingTypeRector::class, SplitDoubleAssignRector::class, EncapsedStringsToSprintfRector::class, WrapEncapsedVariableInCurlyBracesRector::class, NewlineBeforeNewAssignSetRector::class, MakeInheritedMethodVisibilitySameAsParentRector::class, CallUserFuncArrayToVariadicRector::class, VersionCompareFuncCallToConstantRector::class, CountArrayToEmptyArrayComparisonRector::class, CallUserFuncToMethodCallRector::class, FuncGetArgsToVariadicParamRector::class, StrictArraySearchRector::class, StrictInArrayRector::class, UseClassKeywordForClassNameResolutionRector::class, SplitGroupedPropertiesRector::class, SplitGroupedClassConstantsRector::class, ExplicitPublicClassMethodRector::class, RemoveUselessAliasInUseStatementRector::class, BinaryOpStandaloneAssignsToDirectRector::class, MinMaxToClampRector::class];
5657
/**
5758
* @var array<class-string<RectorInterface>, mixed[]>
5859
*/

src/Configuration/PhpLevelSetResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ final class PhpLevelSetResolver
1616
/**
1717
* @var array<PhpVersion::*, SetList::PHP_*>
1818
*/
19-
private const VERSION_LOWER_BOUND_CONFIGS = [PhpVersion::PHP_52 => SetList::PHP_52, PhpVersion::PHP_53 => SetList::PHP_53, PhpVersion::PHP_54 => SetList::PHP_54, PhpVersion::PHP_55 => SetList::PHP_55, PhpVersion::PHP_56 => SetList::PHP_56, PhpVersion::PHP_70 => SetList::PHP_70, PhpVersion::PHP_71 => SetList::PHP_71, PhpVersion::PHP_72 => SetList::PHP_72, PhpVersion::PHP_73 => SetList::PHP_73, PhpVersion::PHP_74 => SetList::PHP_74, PhpVersion::PHP_80 => SetList::PHP_80, PhpVersion::PHP_81 => SetList::PHP_81, PhpVersion::PHP_82 => SetList::PHP_82, PhpVersion::PHP_83 => SetList::PHP_83, PhpVersion::PHP_84 => SetList::PHP_84, PhpVersion::PHP_85 => SetList::PHP_85];
19+
private const VERSION_LOWER_BOUND_CONFIGS = [PhpVersion::PHP_52 => SetList::PHP_52, PhpVersion::PHP_53 => SetList::PHP_53, PhpVersion::PHP_54 => SetList::PHP_54, PhpVersion::PHP_55 => SetList::PHP_55, PhpVersion::PHP_56 => SetList::PHP_56, PhpVersion::PHP_70 => SetList::PHP_70, PhpVersion::PHP_71 => SetList::PHP_71, PhpVersion::PHP_72 => SetList::PHP_72, PhpVersion::PHP_73 => SetList::PHP_73, PhpVersion::PHP_74 => SetList::PHP_74, PhpVersion::PHP_80 => SetList::PHP_80, PhpVersion::PHP_81 => SetList::PHP_81, PhpVersion::PHP_82 => SetList::PHP_82, PhpVersion::PHP_83 => SetList::PHP_83, PhpVersion::PHP_84 => SetList::PHP_84, PhpVersion::PHP_85 => SetList::PHP_85, PhpVersion::PHP_86 => SetList::PHP_86];
2020
/**
2121
* @param PhpVersion::* $phpVersion
2222
* @return string[]

src/Configuration/RectorConfigBuilder.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,8 @@ public function withPhpSets(
402402
bool $php53 = \false,
403403
// place on later as BC break when used in php 7.x without named arg
404404
bool $php84 = \false,
405-
bool $php85 = \false
405+
bool $php85 = \false,
406+
bool $php86 = \false
406407
): self
407408
{
408409
if ($this->isWithPhpSetsUsed === \true) {
@@ -470,6 +471,8 @@ public function withPhpSets(
470471
$targetPhpVersion = PhpVersion::PHP_84;
471472
} elseif ($php85) {
472473
$targetPhpVersion = PhpVersion::PHP_85;
474+
} elseif ($php86) {
475+
$targetPhpVersion = PhpVersion::PHP_86;
473476
} else {
474477
throw new InvalidConfigurationException('Invalid PHP version set');
475478
}

src/Rector/AbstractRector.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace Rector\Rector;
55

66
use PhpParser\Node;
7+
use PhpParser\Node\Expr;
78
use PhpParser\Node\Name;
89
use PhpParser\Node\PropertyItem;
910
use PhpParser\Node\Stmt\ClassMethod;
@@ -176,6 +177,13 @@ protected function getType(Node $node): Type
176177
{
177178
return $this->nodeTypeResolver->getType($node);
178179
}
180+
/**
181+
* Use this method for getting native expr type
182+
*/
183+
protected function getNativeType(Expr $node): Type
184+
{
185+
return $this->nodeTypeResolver->getNativeType($node);
186+
}
179187
/**
180188
* @param Node|Node[] $nodes
181189
* @param callable(Node): (int|Node|null|Node[]) $callable

src/Set/ValueObject/LevelSetList.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
*/
99
final class LevelSetList
1010
{
11+
/**
12+
* @var string
13+
*/
14+
public const UP_TO_PHP_86 = __DIR__ . '/../../../config/set/level/up-to-php86.php';
1115
/**
1216
* @var string
1317
*/

src/Set/ValueObject/SetList.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ final class SetList
107107
* @var string
108108
*/
109109
public const PHP_85 = __DIR__ . '/../../../config/set/php85.php';
110+
/**
111+
* @var string
112+
*/
113+
public const PHP_86 = __DIR__ . '/../../../config/set/php86.php';
110114
/**
111115
* @var string
112116
*/

0 commit comments

Comments
 (0)