Skip to content

Commit d2f553f

Browse files
committed
Updated Rector to commit ba8614a8d2f09f3baf3c7ef930c0e26eb68e30d0
rectorphp/rector-src@ba8614a [CodeQuality] Skip ArrayDimFetch on IssetOnPropertyObjectToPropertyExistsRector (#6862)
1 parent 0cb5e11 commit d2f553f

9 files changed

Lines changed: 227 additions & 8 deletions

File tree

vendor/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2407,6 +2407,7 @@
24072407
'Rector\\Symfony\\Symfony63\\Rector\\Class_\\SignalableCommandInterfaceReturnTypeRector' => $vendorDir . '/rector/rector-symfony/rules/Symfony63/Rector/Class_/SignalableCommandInterfaceReturnTypeRector.php',
24082408
'Rector\\Symfony\\Symfony73\\NodeAnalyzer\\CommandArgumentsAndOptionsResolver' => $vendorDir . '/rector/rector-symfony/rules/Symfony73/NodeAnalyzer/CommandArgumentsAndOptionsResolver.php',
24092409
'Rector\\Symfony\\Symfony73\\NodeFactory\\CommandInvokeParamsFactory' => $vendorDir . '/rector/rector-symfony/rules/Symfony73/NodeFactory/CommandInvokeParamsFactory.php',
2410+
'Rector\\Symfony\\Symfony73\\Rector\\Class_\\CommandHelpToAttributeRector' => $vendorDir . '/rector/rector-symfony/rules/Symfony73/Rector/Class_/CommandHelpToAttributeRector.php',
24102411
'Rector\\Symfony\\Symfony73\\Rector\\Class_\\InvokableCommandRector' => $vendorDir . '/rector/rector-symfony/rules/Symfony73/Rector/Class_/InvokableCommandRector.php',
24112412
'Rector\\Symfony\\Symfony73\\ValueObject\\CommandArgument' => $vendorDir . '/rector/rector-symfony/rules/Symfony73/ValueObject/CommandArgument.php',
24122413
'Rector\\Symfony\\Symfony73\\ValueObject\\CommandOption' => $vendorDir . '/rector/rector-symfony/rules/Symfony73/ValueObject/CommandOption.php',

vendor/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2626,6 +2626,7 @@ class ComposerStaticInitf80ed6cfbb29252baeb5933d3cb8debd
26262626
'Rector\\Symfony\\Symfony63\\Rector\\Class_\\SignalableCommandInterfaceReturnTypeRector' => __DIR__ . '/..' . '/rector/rector-symfony/rules/Symfony63/Rector/Class_/SignalableCommandInterfaceReturnTypeRector.php',
26272627
'Rector\\Symfony\\Symfony73\\NodeAnalyzer\\CommandArgumentsAndOptionsResolver' => __DIR__ . '/..' . '/rector/rector-symfony/rules/Symfony73/NodeAnalyzer/CommandArgumentsAndOptionsResolver.php',
26282628
'Rector\\Symfony\\Symfony73\\NodeFactory\\CommandInvokeParamsFactory' => __DIR__ . '/..' . '/rector/rector-symfony/rules/Symfony73/NodeFactory/CommandInvokeParamsFactory.php',
2629+
'Rector\\Symfony\\Symfony73\\Rector\\Class_\\CommandHelpToAttributeRector' => __DIR__ . '/..' . '/rector/rector-symfony/rules/Symfony73/Rector/Class_/CommandHelpToAttributeRector.php',
26292630
'Rector\\Symfony\\Symfony73\\Rector\\Class_\\InvokableCommandRector' => __DIR__ . '/..' . '/rector/rector-symfony/rules/Symfony73/Rector/Class_/InvokableCommandRector.php',
26302631
'Rector\\Symfony\\Symfony73\\ValueObject\\CommandArgument' => __DIR__ . '/..' . '/rector/rector-symfony/rules/Symfony73/ValueObject/CommandArgument.php',
26312632
'Rector\\Symfony\\Symfony73\\ValueObject\\CommandOption' => __DIR__ . '/..' . '/rector/rector-symfony/rules/Symfony73/ValueObject/CommandOption.php',

vendor/composer/installed.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,12 +1864,12 @@
18641864
"source": {
18651865
"type": "git",
18661866
"url": "https:\/\/github.com\/rectorphp\/rector-symfony.git",
1867-
"reference": "9a4e2c8f07b227da7df27987f4ab13503abd8b86"
1867+
"reference": "b3a4192e97a4ea787becb19929902897a5d6e4d6"
18681868
},
18691869
"dist": {
18701870
"type": "zip",
1871-
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/9a4e2c8f07b227da7df27987f4ab13503abd8b86",
1872-
"reference": "9a4e2c8f07b227da7df27987f4ab13503abd8b86",
1871+
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-symfony\/zipball\/b3a4192e97a4ea787becb19929902897a5d6e4d6",
1872+
"reference": "b3a4192e97a4ea787becb19929902897a5d6e4d6",
18731873
"shasum": ""
18741874
},
18751875
"require": {
@@ -1897,7 +1897,7 @@
18971897
"tomasvotruba\/unused-public": "^2.0",
18981898
"tracy\/tracy": "^2.10"
18991899
},
1900-
"time": "2025-04-22T11:25:39+00:00",
1900+
"time": "2025-04-24T10:45:36+00:00",
19011901
"default-branch": true,
19021902
"type": "rector-extension",
19031903
"extra": {

vendor/composer/installed.php

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

vendor/rector/extension-installer/src/GeneratedConfig.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010
final class GeneratedConfig
1111
{
12-
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main c2dac7b'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main a719629'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main 6f67935'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 9a4e2c8'));
12+
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main c2dac7b'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main a719629'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main 6f67935'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main b3a4192'));
1313
private function __construct()
1414
{
1515
}

vendor/rector/rector-symfony/config/sets/symfony/symfony73.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace RectorPrefix202504;
55

66
use Rector\Config\RectorConfig;
7+
use Rector\Symfony\Symfony73\Rector\Class_\CommandHelpToAttributeRector;
78
use Rector\Symfony\Symfony73\Rector\Class_\InvokableCommandRector;
89
// @see https://github.com/symfony/symfony/blame/7.3/UPGRADE-7.3.md
9-
return RectorConfig::configure()->withRules([InvokableCommandRector::class]);
10+
return RectorConfig::configure()->withRules([CommandHelpToAttributeRector::class, InvokableCommandRector::class]);
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
<?php
2+
3+
declare (strict_types=1);
4+
namespace Rector\Symfony\Symfony73\Rector\Class_;
5+
6+
use PhpParser\Node;
7+
use PhpParser\Node\Arg;
8+
use PhpParser\Node\Attribute;
9+
use PhpParser\Node\Expr\MethodCall;
10+
use PhpParser\Node\Expr\Variable;
11+
use PhpParser\Node\Identifier;
12+
use PhpParser\Node\Scalar\String_;
13+
use PhpParser\Node\Stmt;
14+
use PhpParser\Node\Stmt\Class_;
15+
use PhpParser\Node\Stmt\ClassMethod;
16+
use PhpParser\Node\Stmt\Expression;
17+
use PhpParser\Node\Stmt\Function_;
18+
use PhpParser\NodeVisitor;
19+
use PHPStan\Reflection\ReflectionProvider;
20+
use PHPStan\Type\ObjectType;
21+
use Rector\NodeTypeResolver\Node\AttributeKey;
22+
use Rector\Rector\AbstractRector;
23+
use Rector\Symfony\Enum\CommandMethodName;
24+
use Rector\Symfony\Enum\SymfonyAttribute;
25+
use Rector\Symfony\Enum\SymfonyClass;
26+
use Rector\ValueObject\PhpVersionFeature;
27+
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
28+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
29+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
30+
/**
31+
* @see https://symfony.com/doc/current/console.html#help-message
32+
*
33+
* @see \Rector\Symfony\Tests\Symfony73\Rector\Class_\CommandHelpToAttributeRector\CommandHelpToAttributeRectorTest
34+
*/
35+
final class CommandHelpToAttributeRector extends AbstractRector implements MinPhpVersionInterface
36+
{
37+
/**
38+
* @readonly
39+
*/
40+
private ReflectionProvider $reflectionProvider;
41+
public function __construct(ReflectionProvider $reflectionProvider)
42+
{
43+
$this->reflectionProvider = $reflectionProvider;
44+
}
45+
public function provideMinPhpVersion() : int
46+
{
47+
return PhpVersionFeature::ATTRIBUTES;
48+
}
49+
public function getRuleDefinition() : RuleDefinition
50+
{
51+
return new RuleDefinition('Moves $this->setHelp() to the "help" named argument of #[AsCommand]', [new CodeSample(<<<'CODE_SAMPLE'
52+
use Symfony\Component\Console\Command\Command;
53+
54+
final class SomeCommand extends Command
55+
{
56+
protected function configure(): void
57+
{
58+
$this->setHelp('Some help text');
59+
}
60+
}
61+
CODE_SAMPLE
62+
, <<<'CODE_SAMPLE'
63+
use Symfony\Component\Console\Attribute\AsCommand;
64+
use Symfony\Component\Console\Command\Command;
65+
66+
#[AsCommand(name: 'app:some', help: <<<'TXT'
67+
Some help text
68+
TXT)]
69+
final class SomeCommand extends Command
70+
{
71+
}
72+
CODE_SAMPLE
73+
)]);
74+
}
75+
/**
76+
* @return array<class-string<Node>>
77+
*/
78+
public function getNodeTypes() : array
79+
{
80+
return [Class_::class];
81+
}
82+
/**
83+
* @param Class_ $node
84+
*/
85+
public function refactor(Node $node) : ?Node
86+
{
87+
if ($node->isAbstract()) {
88+
return null;
89+
}
90+
if (!$this->reflectionProvider->hasClass(SymfonyAttribute::AS_COMMAND)) {
91+
return null;
92+
}
93+
if (!$this->isObjectType($node, new ObjectType(SymfonyClass::COMMAND))) {
94+
return null;
95+
}
96+
$asCommandAttribute = $this->getAsCommandAttribute($node);
97+
if ($asCommandAttribute === null) {
98+
return null;
99+
}
100+
foreach ($asCommandAttribute->args as $arg) {
101+
if ((($nullsafeVariable1 = $arg->name) ? $nullsafeVariable1->toString() : null) === 'help') {
102+
return null;
103+
}
104+
}
105+
$configureClassMethod = $node->getMethod(CommandMethodName::CONFIGURE);
106+
if (!$configureClassMethod instanceof ClassMethod) {
107+
return null;
108+
}
109+
$helpExpr = $this->findAndRemoveSetHelpExpr($configureClassMethod);
110+
if (!$helpExpr instanceof String_) {
111+
return null;
112+
}
113+
$wrappedHelp = new String_($helpExpr->value, [Attributekey::KIND => String_::KIND_NOWDOC, AttributeKey::DOC_LABEL => 'TXT']);
114+
$asCommandAttribute->args[] = new Arg($wrappedHelp, \false, \false, [], new Identifier('help'));
115+
if ($configureClassMethod->stmts === []) {
116+
unset($configureClassMethod);
117+
}
118+
return $node;
119+
}
120+
private function getAsCommandAttribute(Class_ $class) : ?Attribute
121+
{
122+
foreach ($class->attrGroups as $attrGroup) {
123+
foreach ($attrGroup->attrs as $attribute) {
124+
if ($this->nodeNameResolver->isName($attribute->name, SymfonyAttribute::AS_COMMAND)) {
125+
return $attribute;
126+
}
127+
}
128+
}
129+
return null;
130+
}
131+
/**
132+
* Returns the argument passed to setHelp() and removes the MethodCall node.
133+
*/
134+
private function findAndRemoveSetHelpExpr(ClassMethod $configureMethod) : ?String_
135+
{
136+
$helpString = null;
137+
$this->traverseNodesWithCallable((array) $configureMethod->stmts, function (Node $node) use(&$helpString) {
138+
if ($node instanceof Class_ || $node instanceof Function_) {
139+
return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
140+
}
141+
if (!$node instanceof MethodCall) {
142+
return null;
143+
}
144+
if (!$this->isName($node->name, 'setHelp')) {
145+
return null;
146+
}
147+
if ($node->isFirstClassCallable() || !isset($node->getArgs()[0])) {
148+
return null;
149+
}
150+
$argExpr = $node->getArgs()[0]->value;
151+
if ($argExpr instanceof String_) {
152+
$helpString = $argExpr;
153+
}
154+
$parent = $node->getAttribute('parent');
155+
if ($parent instanceof Expression) {
156+
unset($parent);
157+
}
158+
return $node->var;
159+
});
160+
foreach ((array) $configureMethod->stmts as $key => $stmt) {
161+
if ($this->isExpressionVariableThis($stmt)) {
162+
unset($configureMethod->stmts[$key]);
163+
}
164+
}
165+
return $helpString;
166+
}
167+
private function isExpressionVariableThis(Stmt $stmt) : bool
168+
{
169+
if (!$stmt instanceof Expression) {
170+
return \false;
171+
}
172+
if (!$stmt->expr instanceof Variable) {
173+
return \false;
174+
}
175+
return $this->isName($stmt->expr, 'this');
176+
}
177+
}

vendor/rector/rector-symfony/rules/Symfony73/Rector/Class_/InvokableCommandRector.php

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use PhpParser\Node\Scalar\String_;
1313
use PhpParser\Node\Stmt\Class_;
1414
use PhpParser\Node\Stmt\ClassMethod;
15+
use PhpParser\Node\Stmt\Expression;
1516
use Rector\Doctrine\NodeAnalyzer\AttributeFinder;
1617
use Rector\Exception\ShouldNotHappenException;
1718
use Rector\Rector\AbstractRector;
@@ -42,6 +43,7 @@ final class InvokableCommandRector extends AbstractRector
4243
* @readonly
4344
*/
4445
private CommandInvokeParamsFactory $commandInvokeParamsFactory;
46+
private const MIGRATED_CONFIGURE_CALLS = ['addArgument', 'addOption'];
4547
public function __construct(AttributeFinder $attributeFinder, CommandArgumentsAndOptionsResolver $commandArgumentsAndOptionsResolver, CommandInvokeParamsFactory $commandInvokeParamsFactory)
4648
{
4749
$this->attributeFinder = $attributeFinder;
@@ -171,7 +173,26 @@ private function removeConfigureClassMethod(Class_ $class) : void
171173
if (!$this->isName($stmt->name, CommandMethodName::CONFIGURE)) {
172174
continue;
173175
}
174-
unset($class->stmts[$key]);
176+
foreach ((array) $stmt->stmts as $innerKey => $innerStmt) {
177+
if (!$innerStmt instanceof Expression) {
178+
continue;
179+
}
180+
$expr = $innerStmt->expr;
181+
if (!$expr instanceof MethodCall) {
182+
continue;
183+
}
184+
if ($this->isFluentArgumentOptionChain($expr)) {
185+
unset($stmt->stmts[$innerKey]);
186+
continue;
187+
}
188+
if ($this->isName($expr->var, 'this') && $this->isNames($expr->name, self::MIGRATED_CONFIGURE_CALLS)) {
189+
unset($stmt->stmts[$innerKey]);
190+
}
191+
}
192+
// 2. if configure() has become empty → remove the method itself
193+
if ($stmt->stmts === [] || $stmt->stmts === null) {
194+
unset($class->stmts[$key]);
195+
}
175196
return;
176197
}
177198
}
@@ -195,4 +216,18 @@ private function replaceInputArgumentOptionFetchWithVariables(ClassMethod $execu
195216
return new Variable($firstArgValue->value);
196217
});
197218
}
219+
private function isFluentArgumentOptionChain(MethodCall $call) : bool
220+
{
221+
$current = $call;
222+
while ($current instanceof MethodCall) {
223+
// every link must be addArgument() or addOption()
224+
if (!$this->isNames($current->name, self::MIGRATED_CONFIGURE_CALLS)) {
225+
return \false;
226+
}
227+
$current = $current->var;
228+
// go one step left
229+
}
230+
// the left-most var must be $this
231+
return $current instanceof Variable && $this->isName($current, 'this');
232+
}
198233
}

vendor/rector/rector-symfony/src/Set/SymfonySetList.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ final class SymfonySetList
129129
* @var string
130130
*/
131131
public const SYMFONY_72 = __DIR__ . '/../../config/sets/symfony/symfony72.php';
132+
/**
133+
* @var string
134+
*/
135+
public const SYMFONY_73 = __DIR__ . '/../../config/sets/symfony/symfony73.php';
132136
/**
133137
* @var string
134138
*/

0 commit comments

Comments
 (0)