|
5 | 5 | namespace Rector\CodingStyle\Rector\Closure; |
6 | 6 |
|
7 | 7 | use PhpParser\Node; |
| 8 | +use PhpParser\Node\Expr\CallLike; |
8 | 9 | use PhpParser\Node\Expr\Closure; |
9 | 10 | use Rector\CodingStyle\Guard\StaticGuard; |
| 11 | +use Rector\NodeAnalyzer\CallLikeExpectsThisBindedClosureArgsAnalyzer; |
10 | 12 | use Rector\Rector\AbstractRector; |
11 | 13 | use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; |
12 | 14 | use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; |
|
16 | 18 | */ |
17 | 19 | final class StaticClosureRector extends AbstractRector |
18 | 20 | { |
| 21 | + private const CLOSURE_USES_THIS = 'has_this_closure'; |
| 22 | + |
19 | 23 | public function __construct( |
20 | | - private readonly StaticGuard $staticGuard |
| 24 | + private readonly StaticGuard $staticGuard, |
| 25 | + private readonly CallLikeExpectsThisBindedClosureArgsAnalyzer $callLikeExpectsThisBindedClosureArgsAnalyzer |
21 | 26 | ) { |
22 | 27 | } |
23 | 28 |
|
@@ -59,11 +64,51 @@ public function getNodeTypes(): array |
59 | 64 | return [Closure::class]; |
60 | 65 | } |
61 | 66 |
|
| 67 | + #[Override] |
| 68 | + public function beforeTraverse(array $nodes): array |
| 69 | + { |
| 70 | + parent::beforeTraverse($nodes); |
| 71 | + |
| 72 | + $this->traverseNodesWithCallable($nodes, function (Node $node): ?CallLike { |
| 73 | + if ( |
| 74 | + ! $node instanceof Node\Expr\MethodCall |
| 75 | + && ! $node instanceof Node\Expr\StaticCall |
| 76 | + && ! $node instanceof Node\Expr\FuncCall |
| 77 | + ) { |
| 78 | + return null; |
| 79 | + } |
| 80 | + |
| 81 | + if ($node->isFirstClassCallable()) { |
| 82 | + return null; |
| 83 | + } |
| 84 | + |
| 85 | + $args = $this->callLikeExpectsThisBindedClosureArgsAnalyzer->getArgsUsingThisBindedClosure($node); |
| 86 | + |
| 87 | + if ($args === []) { |
| 88 | + return null; |
| 89 | + } |
| 90 | + |
| 91 | + foreach ($args as $arg) { |
| 92 | + if ($arg->value instanceof Closure && ! $arg->hasAttribute(self::CLOSURE_USES_THIS)) { |
| 93 | + $arg->value->setAttribute(self::CLOSURE_USES_THIS, true); |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + return $node; |
| 98 | + }); |
| 99 | + |
| 100 | + return $nodes; |
| 101 | + } |
| 102 | + |
62 | 103 | /** |
63 | 104 | * @param Closure $node |
64 | 105 | */ |
65 | 106 | public function refactor(Node $node): ?Node |
66 | 107 | { |
| 108 | + if ($node->hasAttribute(self::CLOSURE_USES_THIS)) { |
| 109 | + return null; |
| 110 | + } |
| 111 | + |
67 | 112 | if (! $this->staticGuard->isLegal($node)) { |
68 | 113 | return null; |
69 | 114 | } |
|
0 commit comments