From 3ad153a4dbc9e3b22c7a52b54236a271bc595db1 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 27 Oct 2025 14:56:37 +0100 Subject: [PATCH 1/2] avoid chain call transformation in PipeOperator, as less readable and rather verbose --- .../Fixture/nested_func.php.inc | 16 ---- .../Fixture/skip_nested_functions.php.inc | 11 +++ .../NestedToPipeOperatorRector.php | 92 +++++-------------- 3 files changed, 32 insertions(+), 87 deletions(-) delete mode 100644 rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/nested_func.php.inc create mode 100644 rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/skip_nested_functions.php.inc diff --git a/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/nested_func.php.inc b/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/nested_func.php.inc deleted file mode 100644 index 0dabf1c3548..00000000000 --- a/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/nested_func.php.inc +++ /dev/null @@ -1,16 +0,0 @@ - ------ - trim(...); - -?> diff --git a/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/skip_nested_functions.php.inc b/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/skip_nested_functions.php.inc new file mode 100644 index 00000000000..0a13e23f792 --- /dev/null +++ b/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/skip_nested_functions.php.inc @@ -0,0 +1,11 @@ + function3(...) + |> function1(...) |> function2(...) - |> function1(...); + |> function3(...); CODE_SAMPLE ), ] @@ -80,19 +81,25 @@ public function refactor(Node $node): ?Node $hasChanged = false; - // First, try to transform sequential assignments - $sequentialChanged = $this->transformSequentialAssignments($node); - if ($sequentialChanged) { - $hasChanged = true; + $statements = $node->stmts; + $totalStatements = count($statements) - 1; + + for ($i = 0; $i < $totalStatements; ++$i) { + $chain = $this->findAssignmentChain($statements, $i); + + if ($chain && count($chain) >= 2) { + $this->processAssignmentChain($node, $chain, $i); + $hasChanged = true; + // Skip processed statements + $i += count($chain) - 1; + } } - // Then, transform nested function calls - $nestedChanged = $this->transformNestedCalls($node); - if ($nestedChanged) { - $hasChanged = true; + if (! $hasChanged) { + return null; } - return $hasChanged ? $node : null; + return $node; } private function transformSequentialAssignments(StmtsAwareInterface $stmtsAware): bool @@ -243,63 +250,6 @@ private function processAssignmentChain(StmtsAwareInterface $stmtsAware, array $ $stmtsAware->stmts = $stmts; } - private function transformNestedCalls(StmtsAwareInterface $stmtsAware): bool - { - $hasChanged = false; - - foreach ($stmtsAware->stmts as $stmt) { - if (! $stmt instanceof Expression) { - continue; - } - - $expr = $stmt->expr; - - if ($expr instanceof Assign) { - $assignedValue = $expr->expr; - $processedValue = $this->processNestedCalls($assignedValue); - - if ($processedValue instanceof Expr && $processedValue !== $assignedValue) { - $expr->expr = $processedValue; - $hasChanged = true; - } - } elseif ($expr instanceof FuncCall) { - $processedValue = $this->processNestedCalls($expr); - - if ($processedValue instanceof Expr && $processedValue !== $expr) { - $stmt->expr = $processedValue; - $hasChanged = true; - } - } - } - - return $hasChanged; - } - - private function processNestedCalls(Node $node): ?Expr - { - if (! $node instanceof FuncCall) { - return null; - } - - // Check if any argument is a function call - foreach ($node->args as $arg) { - if (! $arg instanceof Arg) { - return null; - } - - if ($arg->value instanceof FuncCall) { - return $this->buildPipeExpression($node, $arg->value); - } - } - - return null; - } - - private function buildPipeExpression(FuncCall $outerCall, FuncCall $innerCall): Pipe - { - return new Pipe($innerCall, $this->createPlaceholderCall($outerCall)); - } - private function createPlaceholderCall(FuncCall $funcCall): FuncCall { return new FuncCall($funcCall->name, [new VariadicPlaceholder()]); From bad8f37d588585b27d11d963e7196bf5fdc814d5 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 27 Oct 2025 14:57:47 +0100 Subject: [PATCH 2/2] rename NestedToPipeOeratorRector to SequentialAssignmentsToPipeOperatorRector --- phpstan.neon | 2 +- .../Fixture/skip_single_call.php.inc | 6 ----- .../config/configured_rule.php | 10 -------- .../Fixture/basic.php.inc | 4 +-- .../Fixture/inside_class_method.php.inc | 4 +-- .../Fixture/skip_if_used_elsewhere.php.inc | 2 +- .../Fixture/skip_nested_functions.php.inc | 2 +- .../Fixture/skip_single_call.php.inc | 6 +++++ ...alAssignmentsToPipeOperatorRectorTest.php} | 4 +-- .../config/configured_rule.php | 10 ++++++++ ...entialAssignmentsToPipeOperatorRector.php} | 25 ++----------------- 11 files changed, 27 insertions(+), 48 deletions(-) delete mode 100644 rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/skip_single_call.php.inc delete mode 100644 rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/config/configured_rule.php rename rules-tests/Php85/Rector/StmtsAwareInterface/{NestedToPipeOperatorRector => SequentialAssignmentsToPipeOperatorRector}/Fixture/basic.php.inc (54%) rename rules-tests/Php85/Rector/StmtsAwareInterface/{NestedToPipeOperatorRector => SequentialAssignmentsToPipeOperatorRector}/Fixture/inside_class_method.php.inc (68%) rename rules-tests/Php85/Rector/StmtsAwareInterface/{NestedToPipeOperatorRector => SequentialAssignmentsToPipeOperatorRector}/Fixture/skip_if_used_elsewhere.php.inc (53%) rename rules-tests/Php85/Rector/StmtsAwareInterface/{NestedToPipeOperatorRector => SequentialAssignmentsToPipeOperatorRector}/Fixture/skip_nested_functions.php.inc (55%) create mode 100644 rules-tests/Php85/Rector/StmtsAwareInterface/SequentialAssignmentsToPipeOperatorRector/Fixture/skip_single_call.php.inc rename rules-tests/Php85/Rector/StmtsAwareInterface/{NestedToPipeOperatorRector/NestedToPipeOperatorRectorTest.php => SequentialAssignmentsToPipeOperatorRector/SequentialAssignmentsToPipeOperatorRectorTest.php} (74%) create mode 100644 rules-tests/Php85/Rector/StmtsAwareInterface/SequentialAssignmentsToPipeOperatorRector/config/configured_rule.php rename rules/Php85/Rector/StmtsAwareInterface/{NestedToPipeOperatorRector.php => SequentialAssignmentsToPipeOperatorRector.php} (88%) diff --git a/phpstan.neon b/phpstan.neon index d5b1a3404f6..98f6c4fccf8 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -222,7 +222,7 @@ parameters: - '#Register "Rector\\Php80\\Rector\\NotIdentical\\MbStrContainsRector" service to "php80\.php" config set#' - - '#Register "Rector\\Php85\\Rector\\StmtsAwareInterface\\NestedToPipeOperatorRector" service to "php85\.php" config set#' + - '#Register "Rector\\Php85\\Rector\\StmtsAwareInterface\\SequentialAssignmentsToPipeOperatorRector" service to "php85\.php" config set#' # closure detailed - '#Method Rector\\Config\\RectorConfig\:\:singleton\(\) has parameter \$concrete with no signature specified for Closure#' diff --git a/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/skip_single_call.php.inc b/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/skip_single_call.php.inc deleted file mode 100644 index 575964d5b07..00000000000 --- a/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/skip_single_call.php.inc +++ /dev/null @@ -1,6 +0,0 @@ -rule(NestedToPipeOperatorRector::class); -}; diff --git a/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/basic.php.inc b/rules-tests/Php85/Rector/StmtsAwareInterface/SequentialAssignmentsToPipeOperatorRector/Fixture/basic.php.inc similarity index 54% rename from rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/basic.php.inc rename to rules-tests/Php85/Rector/StmtsAwareInterface/SequentialAssignmentsToPipeOperatorRector/Fixture/basic.php.inc index 35a5992d32e..4b03f35742b 100644 --- a/rules-tests/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector/Fixture/basic.php.inc +++ b/rules-tests/Php85/Rector/StmtsAwareInterface/SequentialAssignmentsToPipeOperatorRector/Fixture/basic.php.inc @@ -1,6 +1,6 @@ rule(SequentialAssignmentsToPipeOperatorRector::class); +}; diff --git a/rules/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector.php b/rules/Php85/Rector/StmtsAwareInterface/SequentialAssignmentsToPipeOperatorRector.php similarity index 88% rename from rules/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector.php rename to rules/Php85/Rector/StmtsAwareInterface/SequentialAssignmentsToPipeOperatorRector.php index e285fbdf428..2fcb3454293 100644 --- a/rules/Php85/Rector/StmtsAwareInterface/NestedToPipeOperatorRector.php +++ b/rules/Php85/Rector/StmtsAwareInterface/SequentialAssignmentsToPipeOperatorRector.php @@ -24,9 +24,9 @@ /** * @see https://wiki.php.net/rfc/pipe-operator-v3 - * @see \Rector\Tests\Php85\Rector\StmtsAwareInterface\NestedToPipeOperatorRector\NestedToPipeOperatorRectorTest + * @see \Rector\Tests\Php85\Rector\StmtsAwareInterface\SequentialAssignmentsToPipeOperatorRector\SequentialAssignmentsToPipeOperatorRectorTest */ -final class NestedToPipeOperatorRector extends AbstractRector implements MinPhpVersionInterface +final class SequentialAssignmentsToPipeOperatorRector extends AbstractRector implements MinPhpVersionInterface { public function __construct( private readonly ExprAnalyzer $exprAnalyzer @@ -102,27 +102,6 @@ public function refactor(Node $node): ?Node return $node; } - private function transformSequentialAssignments(StmtsAwareInterface $stmtsAware): bool - { - $hasChanged = false; - - $statements = $stmtsAware->stmts; - $totalStatements = count($statements) - 1; - - for ($i = 0; $i < $totalStatements; ++$i) { - $chain = $this->findAssignmentChain($statements, $i); - - if ($chain && count($chain) >= 2) { - $this->processAssignmentChain($stmtsAware, $chain, $i); - $hasChanged = true; - // Skip processed statements - $i += count($chain) - 1; - } - } - - return $hasChanged; - } - /** * @param array $statements * @return array|null