From 03af32074453b07a8efd81b4659526b7760141b4 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 14 Jul 2026 10:07:51 +0200 Subject: [PATCH] [CodeQuality] Parenthesize assignments nested under unary/binary operators in LogicalToBooleanRector (#9807, #9808) --- .../Fixture/binary_compound_assign.php.inc | 13 +++++++ ...ry_compound_assign_existing_parens.php.inc | 13 +++++++ .../Fixture/cast_assign.php.inc | 13 +++++++ .../unary_minus_compound_assign.php.inc | 13 +++++++ .../Fixture/unary_not_assign.php.inc | 13 +++++++ .../LogicalAnd/LogicalToBooleanRector.php | 34 +++++++++++++++++++ 6 files changed, 99 insertions(+) create mode 100644 rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/binary_compound_assign.php.inc create mode 100644 rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/binary_compound_assign_existing_parens.php.inc create mode 100644 rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/cast_assign.php.inc create mode 100644 rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/unary_minus_compound_assign.php.inc create mode 100644 rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/unary_not_assign.php.inc diff --git a/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/binary_compound_assign.php.inc b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/binary_compound_assign.php.inc new file mode 100644 index 00000000000..c394d5b8ce3 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/binary_compound_assign.php.inc @@ -0,0 +1,13 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/binary_compound_assign_existing_parens.php.inc b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/binary_compound_assign_existing_parens.php.inc new file mode 100644 index 00000000000..764ada81422 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/binary_compound_assign_existing_parens.php.inc @@ -0,0 +1,13 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/cast_assign.php.inc b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/cast_assign.php.inc new file mode 100644 index 00000000000..6b33555fa88 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/cast_assign.php.inc @@ -0,0 +1,13 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/unary_minus_compound_assign.php.inc b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/unary_minus_compound_assign.php.inc new file mode 100644 index 00000000000..681f7531886 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/unary_minus_compound_assign.php.inc @@ -0,0 +1,13 @@ + +----- + diff --git a/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/unary_not_assign.php.inc b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/unary_not_assign.php.inc new file mode 100644 index 00000000000..436f0fd627e --- /dev/null +++ b/rules-tests/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector/Fixture/unary_not_assign.php.inc @@ -0,0 +1,13 @@ + +----- + diff --git a/rules/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector.php b/rules/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector.php index 46be40f26b6..2cc78c277e2 100644 --- a/rules/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector.php +++ b/rules/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector.php @@ -5,11 +5,22 @@ namespace Rector\CodeQuality\Rector\LogicalAnd; use PhpParser\Node; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\Assign; +use PhpParser\Node\Expr\AssignOp; +use PhpParser\Node\Expr\AssignRef; +use PhpParser\Node\Expr\BinaryOp; use PhpParser\Node\Expr\BinaryOp\BooleanAnd; use PhpParser\Node\Expr\BinaryOp\BooleanOr; use PhpParser\Node\Expr\BinaryOp\LogicalAnd; use PhpParser\Node\Expr\BinaryOp\LogicalOr; +use PhpParser\Node\Expr\BitwiseNot; +use PhpParser\Node\Expr\BooleanNot; +use PhpParser\Node\Expr\Cast; +use PhpParser\Node\Expr\ErrorSuppress; +use PhpParser\Node\Expr\UnaryMinus; +use PhpParser\Node\Expr\UnaryPlus; +use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Rector\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -74,10 +85,33 @@ private function refactorLogicalToBoolean(LogicalOr|LogicalAnd $node): BooleanAn $node->right = $this->refactorLogicalToBoolean($node->right); } + // "and"/"or" bind looser than "="/"+="; once they become "&&"/"||" the assignment must be + // re-printed so the pretty-printer re-adds the parentheses that keep the original semantics + $this->reprintNestedAssign($node->left); + $this->reprintNestedAssign($node->right); + if ($node instanceof LogicalOr) { return new BooleanOr($node->left, $node->right); } return new BooleanAnd($node->left, $node->right); } + + private function reprintNestedAssign(Expr $expr): void + { + if ($expr instanceof Assign || $expr instanceof AssignOp || $expr instanceof AssignRef) { + $expr->setAttribute(AttributeKey::ORIGINAL_NODE, null); + return; + } + + if ($expr instanceof BooleanNot || $expr instanceof BitwiseNot || $expr instanceof UnaryMinus || $expr instanceof UnaryPlus || $expr instanceof ErrorSuppress || $expr instanceof Cast) { + $this->reprintNestedAssign($expr->expr); + return; + } + + if ($expr instanceof BinaryOp) { + $this->reprintNestedAssign($expr->left); + $this->reprintNestedAssign($expr->right); + } + } }