diff --git a/phpstan.neon b/phpstan.neon index 3172a1b7504..240dca14b41 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -392,5 +392,4 @@ parameters: - identifier: rector.noIntegerRefactorReturn paths: - - rules/Php80/Rector/Switch_/ChangeSwitchToMatchRector.php - tests/Issues/InfiniteLoop/Rector/MethodCall/InfinityLoopRector.php diff --git a/rules/Php80/Rector/Switch_/ChangeSwitchToMatchRector.php b/rules/Php80/Rector/Switch_/ChangeSwitchToMatchRector.php index c52d784dff7..56d5e8283ad 100644 --- a/rules/Php80/Rector/Switch_/ChangeSwitchToMatchRector.php +++ b/rules/Php80/Rector/Switch_/ChangeSwitchToMatchRector.php @@ -11,13 +11,12 @@ use PhpParser\Node\Expr\Cast\Int_; use PhpParser\Node\Expr\Cast\String_; use PhpParser\Node\Expr\Match_; -use PhpParser\Node\FunctionLike; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Return_; use PhpParser\Node\Stmt\Switch_; -use PhpParser\NodeVisitor; use PHPStan\Type\ObjectType; use Rector\NodeAnalyzer\ExprAnalyzer; +use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Php80\NodeAnalyzer\MatchSwitchAnalyzer; use Rector\Php80\NodeFactory\MatchFactory; use Rector\Php80\NodeResolver\SwitchExprsResolver; @@ -83,18 +82,13 @@ public function getNodeTypes(): array /** * @param StmtsAware $node - * @return null|Node|NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN */ - public function refactor(Node $node): null|Node|int + public function refactor(Node $node): null|Node { if (! is_array($node->stmts)) { return null; } - if ($node instanceof FunctionLike && $node->returnsByRef()) { - return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN; - } - $hasChanged = false; foreach ($node->stmts as $key => $stmt) { @@ -102,6 +96,11 @@ public function refactor(Node $node): null|Node|int continue; } + // possible reference override, where match + if ($stmt->getAttribute(AttributeKey::IS_INSIDE_BYREF_FUNCTION_LIKE)) { + continue; + } + $nextStmt = $node->stmts[$key + 1] ?? null; $condAndExprs = $this->switchExprsResolver->resolve($stmt); diff --git a/src/NodeTypeResolver/Node/AttributeKey.php b/src/NodeTypeResolver/Node/AttributeKey.php index 4a71b90f77b..10cee8859d6 100644 --- a/src/NodeTypeResolver/Node/AttributeKey.php +++ b/src/NodeTypeResolver/Node/AttributeKey.php @@ -292,4 +292,6 @@ final class AttributeKey public const IS_CLASS_CONST_VALUE = 'is_default_class_const_value'; public const IS_INSIDE_SYMFONY_PHP_CLOSURE = 'is_inside_symfony_php_closure'; + + public const IS_INSIDE_BYREF_FUNCTION_LIKE = 'is_inside_byref_function_like'; } diff --git a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefReturnNodeVisitor.php b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefReturnNodeVisitor.php index 6950ee01d2f..c77293cd376 100644 --- a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefReturnNodeVisitor.php +++ b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefReturnNodeVisitor.php @@ -13,6 +13,7 @@ use Rector\Contract\PhpParser\DecoratingNodeVisitorInterface; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser; +use Rector\PhpParser\NodeTraverser\SimpleNodeTraverser; final class ByRefReturnNodeVisitor extends NodeVisitorAbstract implements DecoratingNodeVisitorInterface { @@ -36,9 +37,12 @@ public function enterNode(Node $node): ?Node return null; } + SimpleNodeTraverser::decorateWithAttributeValue($stmts, AttributeKey::IS_INSIDE_BYREF_FUNCTION_LIKE, true); + $this->simpleCallableNodeTraverser->traverseNodesWithCallable( $stmts, static function (Node $node): int|null|Node { + // avoid nested functions or classes if ($node instanceof Class_ || $node instanceof FunctionLike) { return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN; } diff --git a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/PropertyOrClassConstDefaultNodeVisitor.php b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/PropertyOrClassConstDefaultNodeVisitor.php index 85e953d57b2..4ac38b7dccc 100644 --- a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/PropertyOrClassConstDefaultNodeVisitor.php +++ b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/PropertyOrClassConstDefaultNodeVisitor.php @@ -11,7 +11,7 @@ use PhpParser\NodeVisitorAbstract; use Rector\Contract\PhpParser\DecoratingNodeVisitorInterface; use Rector\NodeTypeResolver\Node\AttributeKey; -use Rector\PhpParser\NodeTraverser\SimpleTraverser; +use Rector\PhpParser\NodeTraverser\SimpleNodeTraverser; final class PropertyOrClassConstDefaultNodeVisitor extends NodeVisitorAbstract implements DecoratingNodeVisitorInterface { @@ -24,13 +24,21 @@ public function enterNode(Node $node): ?Node continue; } - SimpleTraverser::decorateWithTrueAttribute($default, AttributeKey::IS_DEFAULT_PROPERTY_VALUE); + SimpleNodeTraverser::decorateWithAttributeValue( + $default, + AttributeKey::IS_DEFAULT_PROPERTY_VALUE, + true + ); } } if ($node instanceof ClassConst) { foreach ($node->consts as $const) { - SimpleTraverser::decorateWithTrueAttribute($const->value, AttributeKey::IS_CLASS_CONST_VALUE); + SimpleNodeTraverser::decorateWithAttributeValue( + $const->value, + AttributeKey::IS_CLASS_CONST_VALUE, + true + ); } } diff --git a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/SymfonyClosureNodeVisitor.php b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/SymfonyClosureNodeVisitor.php index 9d5aea7e5c1..28c417e5c4e 100644 --- a/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/SymfonyClosureNodeVisitor.php +++ b/src/NodeTypeResolver/PHPStan/Scope/NodeVisitor/SymfonyClosureNodeVisitor.php @@ -9,7 +9,7 @@ use PhpParser\NodeVisitorAbstract; use Rector\Contract\PhpParser\DecoratingNodeVisitorInterface; use Rector\NodeTypeResolver\Node\AttributeKey; -use Rector\PhpParser\NodeTraverser\SimpleTraverser; +use Rector\PhpParser\NodeTraverser\SimpleNodeTraverser; use Rector\Symfony\NodeAnalyzer\SymfonyPhpClosureDetector; final class SymfonyClosureNodeVisitor extends NodeVisitorAbstract implements DecoratingNodeVisitorInterface @@ -29,7 +29,11 @@ public function enterNode(Node $node): ?Node return null; } - SimpleTraverser::decorateWithTrueAttribute($node, AttributeKey::IS_INSIDE_SYMFONY_PHP_CLOSURE); + SimpleNodeTraverser::decorateWithAttributeValue( + (array) $node->stmts, + AttributeKey::IS_INSIDE_SYMFONY_PHP_CLOSURE, + true + ); return null; } diff --git a/src/PhpParser/NodeTraverser/SimpleNodeTraverser.php b/src/PhpParser/NodeTraverser/SimpleNodeTraverser.php new file mode 100644 index 00000000000..13d841678ec --- /dev/null +++ b/src/PhpParser/NodeTraverser/SimpleNodeTraverser.php @@ -0,0 +1,47 @@ +setAttribute($this->attributeKey, $this->value); + return null; + } + }; + + $nodeTraverser = new NodeTraverser($callableNodeVisitor); + + $nodes = $nodesOrNode instanceof Node ? [$nodesOrNode] : $nodesOrNode; + $nodeTraverser->traverse($nodes); + } +} diff --git a/src/PhpParser/NodeTraverser/SimpleTraverser.php b/src/PhpParser/NodeTraverser/SimpleTraverser.php deleted file mode 100644 index 4456a79d554..00000000000 --- a/src/PhpParser/NodeTraverser/SimpleTraverser.php +++ /dev/null @@ -1,38 +0,0 @@ -setAttribute($this->attributeKey, true); - return null; - } - }; - - $nodeTraverser = new NodeTraverser($callableNodeVisitor); - - $nodes = $nodesOrNode instanceof Node ? [$nodesOrNode] : $nodesOrNode; - $nodeTraverser->traverse($nodes); - } -}