Skip to content

Commit 8cd3cc6

Browse files
authored
Remove direct NodeTravser::* where possible, use node visitor attribute key instead (#7697)
* bump phpstan rules * make use of is assign attribute * add SymfonyClosureNodeVisitor
1 parent 3f60b07 commit 8cd3cc6

File tree

8 files changed

+60
-34
lines changed

8 files changed

+60
-34
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"rector/type-perfect": "^2.1",
5757
"shipmonk/composer-dependency-analyser": "^1.8",
5858
"symplify/phpstan-extensions": "^12.0.2",
59-
"symplify/phpstan-rules": "^14.9.1",
59+
"symplify/phpstan-rules": "dev-main",
6060
"symplify/vendor-patches": "^11.5",
6161
"tomasvotruba/class-leak": "^2.1",
6262
"tracy/tracy": "^2.11"

phpstan.neon

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,3 +387,12 @@ parameters:
387387
-
388388
path: rules/TypeDeclaration/Rector/StmtsAwareInterface/IncreaseDeclareStrictTypesRector.php
389389
identifier: rector.noOnlyNullReturnInRefactor
390+
391+
# handle next
392+
-
393+
identifier: rector.noIntegerRefactorReturn
394+
paths:
395+
- rules/CodeQuality/Rector/FuncCall/SetTypeToCastRector.php
396+
- rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php
397+
- rules/Php80/Rector/Switch_/ChangeSwitchToMatchRector.php
398+
- tests/Issues/InfiniteLoop/Rector/MethodCall/InfinityLoopRector.php

rules-tests/Transform/Rector/ArrayDimFetch/ArrayDimFetchToMethodCallRector/Fixture/skip_assign_ops.php.inc

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,3 @@ namespace Rector\Tests\Transform\Rector\ArrayDimFetch\ArrayDimFetchToMethodCallR
66
$object['key'] += 42;
77
$object['key'] -= 42;
88
$object['key'] *= 42;
9-
$object['key'] /= 42;
10-
$object['key'] %= 42;
11-
$object['key'] **= 42;
12-
$object['key'] .= 'value';
13-
$object['key'] &= 42;
14-
$object['key'] |= 42;
15-
$object['key'] ^= 42;
16-
$object['key'] <<= 42;
17-
$object['key'] >>= 42;
18-
$object['key'] ??= 'value';
19-
20-
?>

rules/Php81/Rector/Array_/FirstClassCallableRector.php

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
use PhpParser\Node;
88
use PhpParser\Node\Expr\Array_;
99
use PhpParser\Node\Expr\ClassConstFetch;
10-
use PhpParser\Node\Expr\Closure;
1110
use PhpParser\Node\Expr\MethodCall;
1211
use PhpParser\Node\Expr\PropertyFetch;
1312
use PhpParser\Node\Expr\StaticCall;
1413
use PhpParser\Node\Expr\Variable;
1514
use PhpParser\Node\VariadicPlaceholder;
16-
use PhpParser\NodeVisitor;
1715
use PHPStan\Analyser\Scope;
1816
use PHPStan\Reflection\ClassReflection;
1917
use PHPStan\Reflection\ReflectionProvider;
@@ -24,7 +22,6 @@
2422
use Rector\Rector\AbstractRector;
2523
use Rector\Reflection\ReflectionResolver;
2624
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
27-
use Rector\Symfony\NodeAnalyzer\SymfonyPhpClosureDetector;
2825
use Rector\ValueObject\PhpVersion;
2926
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
3027
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -40,7 +37,6 @@ public function __construct(
4037
private readonly ArrayCallableMethodMatcher $arrayCallableMethodMatcher,
4138
private readonly ReflectionProvider $reflectionProvider,
4239
private readonly ReflectionResolver $reflectionResolver,
43-
private readonly SymfonyPhpClosureDetector $symfonyPhpClosureDetector
4440
) {
4541
}
4642

@@ -85,20 +81,15 @@ public function name()
8581
*/
8682
public function getNodeTypes(): array
8783
{
88-
return [Array_::class, Closure::class];
84+
return [Array_::class];
8985
}
9086

9187
/**
92-
* @param Array_|Closure $node
93-
* @return StaticCall|MethodCall|null|NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN
88+
* @param Array_ $node
9489
*/
95-
public function refactor(Node $node): StaticCall|MethodCall|null|int
90+
public function refactor(Node $node): StaticCall|MethodCall|null
9691
{
97-
if ($node instanceof Closure) {
98-
if ($this->symfonyPhpClosureDetector->detect($node)) {
99-
return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
100-
}
101-
92+
if ($node->getAttribute(AttributeKey::IS_INSIDE_SYMFONY_PHP_CLOSURE)) {
10293
return null;
10394
}
10495

rules/Transform/Rector/ArrayDimFetch/ArrayDimFetchToMethodCallRector.php

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use PhpParser\Node\Expr;
1010
use PhpParser\Node\Expr\ArrayDimFetch;
1111
use PhpParser\Node\Expr\Assign;
12-
use PhpParser\Node\Expr\AssignOp;
1312
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
1413
use PhpParser\Node\Expr\Isset_;
1514
use PhpParser\Node\Expr\MethodCall;
@@ -61,20 +60,15 @@ public function getRuleDefinition(): RuleDefinition
6160

6261
public function getNodeTypes(): array
6362
{
64-
return [AssignOp::class, Assign::class, Isset_::class, Unset_::class, ArrayDimFetch::class];
63+
return [Assign::class, Isset_::class, Unset_::class, ArrayDimFetch::class];
6564
}
6665

6766
/**
68-
* @template TNode of ArrayDimFetch|Assign|Isset_|Unset_
69-
* @param TNode $node
67+
* @param ArrayDimFetch|Assign|Isset_|Unset_ $node
7068
* @return ($node is Unset_ ? Stmt[]|int : ($node is Isset_ ? Expr|int : MethodCall|int|null))
7169
*/
7270
public function refactor(Node $node): array|Expr|null|int
7371
{
74-
if ($node instanceof AssignOp) {
75-
return NodeVisitor::DONT_TRAVERSE_CHILDREN;
76-
}
77-
7872
if ($node instanceof Unset_) {
7973
return $this->handleUnset($node);
8074
}
@@ -96,6 +90,10 @@ public function refactor(Node $node): array|Expr|null|int
9690
return null;
9791
}
9892

93+
if ($node->getAttribute(AttributeKey::IS_ASSIGN_OP_VAR)) {
94+
return null;
95+
}
96+
9997
return $this->createExplicitMethodCall($node, 'get');
10098
}
10199

src/DependencyInjection/LazyContainerFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\NameNodeVisitor;
105105
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\PropertyOrClassConstDefaultNodeVisitor;
106106
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\StaticVariableNodeVisitor;
107+
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\SymfonyClosureNodeVisitor;
107108
use Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver;
108109
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider;
109110
use Rector\Php80\AttributeDecorator\DoctrineConverterAttributeDecorator;
@@ -238,6 +239,7 @@ final class LazyContainerFactory
238239
private const DECORATING_NODE_VISITOR_CLASSES = [
239240
ArgNodeVisitor::class,
240241
AssignedToNodeVisitor::class,
242+
SymfonyClosureNodeVisitor::class,
241243
ByRefReturnNodeVisitor::class,
242244
ByRefVariableNodeVisitor::class,
243245
ContextNodeVisitor::class,

src/NodeTypeResolver/Node/AttributeKey.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,6 @@ final class AttributeKey
290290
public const IS_DEFAULT_PROPERTY_VALUE = 'is_default_property_value';
291291

292292
public const IS_CLASS_CONST_VALUE = 'is_default_class_const_value';
293+
294+
public const IS_INSIDE_SYMFONY_PHP_CLOSURE = 'is_inside_symfony_php_closure';
293295
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\Closure;
9+
use PhpParser\NodeVisitorAbstract;
10+
use Rector\Contract\PhpParser\DecoratingNodeVisitorInterface;
11+
use Rector\NodeTypeResolver\Node\AttributeKey;
12+
use Rector\PhpParser\NodeTraverser\SimpleTraverser;
13+
use Rector\Symfony\NodeAnalyzer\SymfonyPhpClosureDetector;
14+
15+
final class SymfonyClosureNodeVisitor extends NodeVisitorAbstract implements DecoratingNodeVisitorInterface
16+
{
17+
public function __construct(
18+
private readonly SymfonyPhpClosureDetector $symfonyPhpClosureDetector
19+
) {
20+
}
21+
22+
public function enterNode(Node $node): ?Node
23+
{
24+
if (! $node instanceof Closure) {
25+
return null;
26+
}
27+
28+
if (! $this->symfonyPhpClosureDetector->detect($node)) {
29+
return null;
30+
}
31+
32+
SimpleTraverser::decorateWithTrueAttribute($node, AttributeKey::IS_INSIDE_SYMFONY_PHP_CLOSURE);
33+
34+
return null;
35+
}
36+
}

0 commit comments

Comments
 (0)