diff --git a/rules-tests/DeadCode/Rector/Assign/RemoveDoubleAssignRector/Fixture/skip_call_in_assign_target.php.inc b/rules-tests/DeadCode/Rector/Assign/RemoveDoubleAssignRector/Fixture/skip_call_in_assign_target.php.inc new file mode 100644 index 00000000000..f164499bc13 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Assign/RemoveDoubleAssignRector/Fixture/skip_call_in_assign_target.php.inc @@ -0,0 +1,13 @@ +get(SomeService::class)->enabled = true; + $container->get(SomeService::class)->enabled = true; + $container->get(SomeService::class)->enabled = true; + } +} diff --git a/rules/DeadCode/Rector/Assign/RemoveDoubleAssignRector.php b/rules/DeadCode/Rector/Assign/RemoveDoubleAssignRector.php index a9181c0417f..76534247fca 100644 --- a/rules/DeadCode/Rector/Assign/RemoveDoubleAssignRector.php +++ b/rules/DeadCode/Rector/Assign/RemoveDoubleAssignRector.php @@ -100,6 +100,15 @@ public function refactor(Node $node): ?Node continue; } + // the assignment target itself may contain a call with side effects, + // e.g. $object->getService()->property = 1; — removing the first assign would skip the call + if ($this->betterNodeFinder->findFirst( + $stmt->expr->var, + fn (Node $subNode): bool => $this->sideEffectNodeDetector->detectCallExpr($subNode) + ) instanceof Node) { + continue; + } + // next stmts can have side effect as well if (($nextAssign->var instanceof PropertyFetch || $nextAssign->var instanceof StaticPropertyFetch) && $this->sideEffectNodeDetector->detectCallExpr( $nextAssign->expr