Skip to content

Commit d9cf285

Browse files
authored
Enforce parens when formatting on more operators (#13711)
* On bitwise operators * On right precedence operators which are semantically non-associative (such as -- and potentially ---)
1 parent 18bbfed commit d9cf285

File tree

3 files changed

+27
-16
lines changed

3 files changed

+27
-16
lines changed

lib/elixir/lib/code/formatter.ex

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,39 @@ defmodule Code.Formatter do
3131
@right_new_line_before_binary_operators [:|, :when]
3232

3333
# Operators that are logical cannot be mixed without parens
34-
@required_parens_logical_binary_operands [:||, :|||, :or, :&&, :&&&, :and]
34+
@required_parens_logical_binary_operands [:||, :or, :&&, :and]
3535

3636
# Operators with next break fits
3737
@next_break_fits_operators [:<-, :==, :!=, :=~, :===, :!==, :<, :>, :<=, :>=, :=, :"::"]
3838

39-
# Operators that always require parens on operands when they are the parent
39+
# Operators that always require parens even
40+
# when they are their own parents as they are not semantically associative
41+
@required_parens_even_when_parent [:--, :---]
42+
43+
# Operators that always require parens on operands
44+
# when they are the parent of another operator with a difference precedence
45+
# Most operators are listed, except comparison, arithmetic, and low precedence
4046
@required_parens_on_binary_operands [
41-
:|>,
47+
:|||,
48+
:&&&,
4249
:<<<,
4350
:>>>,
51+
:|>,
4452
:<~,
4553
:~>,
4654
:<<~,
4755
:~>>,
4856
:<~>,
4957
:"<|>",
50-
:"^^^",
51-
:+++,
52-
:---,
5358
:in,
59+
:"^^^",
60+
:"//",
5461
:++,
5562
:--,
56-
:..,
57-
:<>
63+
:+++,
64+
:---,
65+
:<>,
66+
:..
5867
]
5968

6069
@locals_without_parens [
@@ -785,14 +794,13 @@ defmodule Code.Formatter do
785794
op_string = Atom.to_string(op)
786795

787796
cond do
788-
# If the operator has the same precedence as the parent and is on
789-
# the correct side, we respect the nesting rule to avoid multiple
790-
# nestings. This only applies for left associativity or same operator.
791-
parent_prec == prec and parent_assoc == side and (side == :left or op == parent_op) ->
797+
# If we have the same operator and it is in the correct side,
798+
# we don't add parens unless it is explicitly required.
799+
parent_assoc == side and op == parent_op and op not in @required_parens_even_when_parent ->
792800
binary_op_to_algebra(op, op_string, meta, left, right, context, state, nesting)
793801

794-
# If the parent requires parens or the precedence is inverted or
795-
# it is in the wrong side, then we *need* parenthesis.
802+
# If the operator requires parens (most of them do) or we are mixing logical operators
803+
# or the precedence is inverted or it is in the wrong side, then we *need* parenthesis.
796804
(parent_op in @required_parens_on_binary_operands and op not in @no_space_binary_operators) or
797805
(op in @required_parens_logical_binary_operands and
798806
parent_op in @required_parens_logical_binary_operands) or parent_prec > prec or

lib/elixir/src/elixir_parser.yrl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Left 120 or_op_eol. %% ||, |||, or
7171
Left 130 and_op_eol. %% &&, &&&, and
7272
Left 140 comp_op_eol. %% ==, !=, =~, ===, !==
7373
Left 150 rel_op_eol. %% <, >, <=, >=
74-
Left 160 arrow_op_eol. %% |>, <<<, >>>, <<~, ~>>, <~, ~>, <~>, <|>
74+
Left 160 arrow_op_eol. %% <<<, >>>, |>, <<~, ~>>, <~, ~>, <~>, <|>
7575
Left 170 in_op_eol. %% in, not in
7676
Left 180 xor_op_eol. %% ^^^
7777
Right 190 ternary_op_eol. %% //

lib/elixir/test/elixir/code_formatter/operators_test.exs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ defmodule Code.Formatter.OperatorsTest do
170170
end
171171

172172
test "bitwise precedence" do
173-
assert_format "(crc >>> 8) ||| byte", "crc >>> 8 ||| byte"
173+
assert_same "(crc >>> 8) ||| byte"
174174
assert_same "crc >>> (8 ||| byte)"
175175
end
176176
end
@@ -423,6 +423,9 @@ defmodule Code.Formatter.OperatorsTest do
423423

424424
test "with multiple of the same entry and right associative" do
425425
assert_same "foo ++ bar ++ baz"
426+
assert_format "foo -- bar -- baz", "foo -- (bar -- baz)"
427+
assert_same "foo +++ bar +++ baz"
428+
assert_format "foo --- bar --- baz", "foo --- (bar --- baz)"
426429

427430
bad = "a ++ b ++ c"
428431

0 commit comments

Comments
 (0)