diff --git a/rules-tests/Php74/Rector/Closure/ClosureToArrowFunctionRector/Fixture/skip_use_compact.php.inc b/rules-tests/Php74/Rector/Closure/ClosureToArrowFunctionRector/Fixture/skip_use_compact.php.inc new file mode 100644 index 00000000000..97a9040bcd8 --- /dev/null +++ b/rules-tests/Php74/Rector/Closure/ClosureToArrowFunctionRector/Fixture/skip_use_compact.php.inc @@ -0,0 +1,22 @@ +myCallback( + function () use ($test) { + return compact('test'); + } + ); + } + + private function myCallback($callback) + { + $callback(); + } +} diff --git a/rules/Php74/NodeAnalyzer/ClosureArrowFunctionAnalyzer.php b/rules/Php74/NodeAnalyzer/ClosureArrowFunctionAnalyzer.php index 0a2fae15155..d6b4ea2c86c 100644 --- a/rules/Php74/NodeAnalyzer/ClosureArrowFunctionAnalyzer.php +++ b/rules/Php74/NodeAnalyzer/ClosureArrowFunctionAnalyzer.php @@ -8,12 +8,14 @@ use PhpParser\Node\ClosureUse; use PhpParser\Node\Expr; use PhpParser\Node\Expr\Closure; +use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\Return_; use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; use PHPStan\Type\MixedType; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; +use Rector\NodeAnalyzer\CompactFuncCallAnalyzer; use Rector\NodeTypeResolver\NodeTypeResolver; use Rector\PhpParser\Comparing\NodeComparator; use Rector\PhpParser\Node\BetterNodeFinder; @@ -26,7 +28,8 @@ public function __construct( private NodeComparator $nodeComparator, private ArrayChecker $arrayChecker, private PhpDocInfoFactory $phpDocInfoFactory, - private NodeTypeResolver $nodeTypeResolver + private NodeTypeResolver $nodeTypeResolver, + private CompactFuncCallAnalyzer $compactFuncCallAnalyzer ) { } @@ -51,6 +54,10 @@ public function matchArrowFunctionExpr(Closure $closure): ?Expr return null; } + if ($this->shouldSkipForUseVariableUsedByCompact($closure)) { + return null; + } + if ($this->shouldSkipMoreSpecificTypeWithVarDoc($return, $return->expr)) { return null; } @@ -58,6 +65,32 @@ public function matchArrowFunctionExpr(Closure $closure): ?Expr return $return->expr; } + private function shouldSkipForUseVariableUsedByCompact(Closure $closure): bool + { + $variables = array_map(fn (ClosureUse $use): Variable => $use->var, $closure->uses); + + if ($variables === []) { + return false; + } + + return (bool) $this->betterNodeFinder->findFirstInFunctionLikeScoped( + $closure, + function (Node $node) use ($variables): bool { + if (! $node instanceof FuncCall) { + return false; + } + + foreach ($variables as $variable) { + if ($this->compactFuncCallAnalyzer->isInCompact($node, $variable)) { + return true; + } + } + + return false; + } + ); + } + /** * Ensure @var doc usage with more specific type on purpose to be skipped */