diff --git a/rules-tests/Php70/Rector/Ternary/TernaryToNullCoalescingRector/Fixture/keep_inner_ternary_parentheses_in_concat.php.inc b/rules-tests/Php70/Rector/Ternary/TernaryToNullCoalescingRector/Fixture/keep_inner_ternary_parentheses_in_concat.php.inc new file mode 100644 index 00000000000..11db1a17da1 --- /dev/null +++ b/rules-tests/Php70/Rector/Ternary/TernaryToNullCoalescingRector/Fixture/keep_inner_ternary_parentheses_in_concat.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/src/PhpParser/Printer/BetterStandardPrinter.php b/src/PhpParser/Printer/BetterStandardPrinter.php index 73480d5460b..84d1368f8e8 100644 --- a/src/PhpParser/Printer/BetterStandardPrinter.php +++ b/src/PhpParser/Printer/BetterStandardPrinter.php @@ -544,15 +544,46 @@ private function wrapBinaryOpWithBrackets(Node $node): void if ($node->left instanceof BinaryOp && $node->left->getAttribute(AttributeKey::ORIGINAL_NODE) instanceof Node) { + $this->keepTernaryOperandParentheses($node->left); $node->left->setAttribute(AttributeKey::ORIGINAL_NODE, null); } if ($node->right instanceof BinaryOp && $node->right->getAttribute(AttributeKey::ORIGINAL_NODE) instanceof Node) { + $this->keepTernaryOperandParentheses($node->right); $node->right->setAttribute(AttributeKey::ORIGINAL_NODE, null); } } + /** + * The binary op is about to be reprinted, while its unchanged ternary operand is still format-preserved, + * which prints it without its original parentheses + * + * @see https://github.com/rectorphp/rector-src/issues/8910 + */ + private function keepTernaryOperandParentheses(BinaryOp $binaryOp): void + { + $originalBinaryOp = $binaryOp->getAttribute(AttributeKey::ORIGINAL_NODE); + if (! $originalBinaryOp instanceof BinaryOp || ! $this->origTokens instanceof TokenStream) { + return; + } + + foreach ([$binaryOp->left, $binaryOp->right] as $key => $operand) { + if (! $operand instanceof Ternary) { + continue; + } + + $originalOperand = $key === 0 ? $originalBinaryOp->left : $originalBinaryOp->right; + if ($operand->getAttribute(AttributeKey::ORIGINAL_NODE) !== $originalOperand) { + continue; + } + + if ($this->origTokens->haveParens($operand->getStartTokenPos(), $operand->getEndTokenPos())) { + $operand->setAttribute(AttributeKey::WRAPPED_IN_PARENTHESES, true); + } + } + } + /** * @see https://github.com/rectorphp/rector/issues/9800 */