Skip to content

Commit dca7513

Browse files
authored
Preserve comment placement after a then or else (ocaml-ppx#2589)
* Improve comment placement after a `then` or `else` Allow comments on the same line as `then` and `else`, as it was the case in 0.26.2. Also, make sure to avoid formatting any code after a comment in that position. This was broken since ocaml-ppx#2507. * Preserve placement of comments after a `then` or `else` To avoid generating a large number of diffs, the locations of then and else keywords are added to the AST. This new information is used to preserve different cases: if cond then (* attached to then *) expr; if cond then (* attached to expr *) expr; if cond then (* attached to expr *) expr;
1 parent 8229856 commit dca7513

30 files changed

+475
-114
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ profile. This started with version 0.26.0.
4343
- \* Force a break around comments following an infix operator (fix non-stabilizing comments) (#2478, @gpetiot)
4444
- \* Fix the indentation of tuples in attributes and extensions (#2488, @Julow)
4545
- Fix unstable comment around docked functor argument (#2506, @Julow)
46-
- \* Fix unwanted alignment after comment (#2507, @Julow)
46+
- \* Fix unwanted alignment after comment (#2507, #2589, @Julow)
4747
- \* Fix unwanted alignment in if-then-else (#2511, @Julow)
4848
- Fix position of comments around and within `(type ...)` function arguments (#2503, @gpetiot)
4949
- Fix missing parentheses around constraint expressions with attributes (#2513, @alanechang)

lib/Ast.ml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,7 +1424,7 @@ end = struct
14241424
| Pexp_ifthenelse (eN, e) ->
14251425
assert (
14261426
List.exists eN ~f:(fun x -> f x.if_cond || f x.if_body)
1427-
|| Option.exists e ~f )
1427+
|| Option.exists e ~f:(fun (x, _) -> f x) )
14281428
| Pexp_for (_, e1, e2, _, e3) ->
14291429
assert (e1 == exp || e2 == exp || e3 == exp)
14301430
| Pexp_override e1N -> assert (List.exists e1N ~f:snd_f) )
@@ -1991,7 +1991,7 @@ end = struct
19911991
| Pexp_assert e
19921992
|Pexp_construct (_, Some e)
19931993
|Pexp_function (_, _, Pfunction_body e)
1994-
|Pexp_ifthenelse (_, Some e)
1994+
|Pexp_ifthenelse (_, Some (e, _))
19951995
|Pexp_prefix (_, e)
19961996
|Pexp_infix (_, _, e)
19971997
|Pexp_lazy e
@@ -2066,7 +2066,7 @@ end = struct
20662066
match exp.pexp_desc with
20672067
| Pexp_assert e
20682068
|Pexp_construct (_, Some e)
2069-
|Pexp_ifthenelse (_, Some e)
2069+
|Pexp_ifthenelse (_, Some (e, _))
20702070
|Pexp_prefix (_, e)
20712071
|Pexp_infix (_, _, e)
20722072
|Pexp_lazy e
@@ -2204,7 +2204,7 @@ end = struct
22042204
&& List.exists eN ~f:(fun x -> x.if_body == exp)
22052205
&& ifthenelse pexp_desc ->
22062206
true
2207-
| Exp {pexp_desc= Pexp_ifthenelse (_, Some e); _}, {pexp_desc; _}
2207+
| Exp {pexp_desc= Pexp_ifthenelse (_, Some (e, _)); _}, {pexp_desc; _}
22082208
when !parens_ite && e == exp && ifthenelse pexp_desc ->
22092209
true
22102210
| ( Exp {pexp_desc= Pexp_infix (_, _, e1); _}
@@ -2294,7 +2294,8 @@ end = struct
22942294
| Pexp_ifthenelse (eN, _)
22952295
when List.exists eN ~f:(fun x -> x.if_body == exp) ->
22962296
exposed_right_exp ThenElse exp
2297-
| Pexp_ifthenelse (_, Some els) when els == exp -> Exp.is_sequence exp
2297+
| Pexp_ifthenelse (_, Some (els, _)) when els == exp ->
2298+
Exp.is_sequence exp
22982299
| Pexp_apply (({pexp_desc= Pexp_new _; _} as exp2), _) when exp2 == exp
22992300
->
23002301
false

lib/Fmt_ast.ml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,7 +2326,7 @@ and fmt_expression c ?(box = true) ?(pro = noop) ?eol ?parens
23262326
| Pexp_ifthenelse (if_branches, else_) ->
23272327
let last_loc =
23282328
match else_ with
2329-
| Some e -> e.pexp_loc
2329+
| Some (e, _) -> e.pexp_loc
23302330
| None -> (List.last_exn if_branches).if_body.pexp_loc
23312331
in
23322332
Cmts.relocate c.cmts ~src:pexp_loc ~before:pexp_loc ~after:last_loc ;
@@ -2335,25 +2335,36 @@ and fmt_expression c ?(box = true) ?(pro = noop) ?eol ?parens
23352335
let with_conds =
23362336
List.map if_branches ~f:(fun x ->
23372337
( Some (sub_exp ~ctx x.if_cond)
2338+
, x.if_loc_then
23382339
, sub_exp ~ctx x.if_body
23392340
, x.if_attrs ) )
23402341
in
23412342
match else_ with
2342-
| Some x ->
2343-
List.rev ((None, sub_exp ~ctx x, []) :: List.rev with_conds)
2343+
| Some (x, loc_else) ->
2344+
List.rev
2345+
((None, loc_else, sub_exp ~ctx x, []) :: List.rev with_conds)
23442346
| None -> with_conds
23452347
in
23462348
pro
23472349
$ hvbox 0
23482350
( Params.Exp.wrap c.conf ~parens:(parens || has_attr)
23492351
(hvbox 0
23502352
(list_fl cnd_exps
2351-
(fun ~first ~last (xcond, xbch, pexp_attributes) ->
2353+
(fun
2354+
~first
2355+
~last
2356+
(xcond, keyword_loc, xbch, pexp_attributes)
2357+
->
23522358
let symbol_parens = Exp.is_symbol xbch.ast in
23532359
let parens_bch =
23542360
parenze_exp xbch && not symbol_parens
23552361
in
2356-
let parens_exp = false in
2362+
let cmts_before_kw = Cmts.fmt_before c keyword_loc in
2363+
let cmts_after_kw =
2364+
if Cmts.has_after c.cmts keyword_loc then
2365+
Some (Cmts.fmt_after c keyword_loc)
2366+
else None
2367+
in
23572368
let p =
23582369
Params.get_if_then_else c.conf ~first ~last
23592370
~parens_bch ~parens_prev_bch:!parens_prev_bch
@@ -2364,6 +2375,7 @@ and fmt_expression c ?(box = true) ?(pro = noop) ?eol ?parens
23642375
~fmt_attributes:
23652376
(fmt_attributes c ~pre:Blank pexp_attributes)
23662377
~fmt_cond:(fmt_expression ~box:false c)
2378+
~cmts_before_kw ~cmts_after_kw
23672379
in
23682380
parens_prev_bch := parens_bch ;
23692381
p.box_branch
@@ -2372,7 +2384,7 @@ and fmt_expression c ?(box = true) ?(pro = noop) ?eol ?parens
23722384
( p.branch_pro
23732385
$ p.wrap_parens
23742386
( fmt_expression c ?box:p.box_expr
2375-
~parens:parens_exp ?pro:p.expr_pro
2387+
~parens:false ?pro:p.expr_pro
23762388
?eol:p.expr_eol p.branch_expr
23772389
$ p.break_end_branch ) ) )
23782390
$ fmt_if (not last) p.space_between_branches ) ) )
@@ -2924,8 +2936,7 @@ and fmt_class_signature c ~ctx ~pro ~epi ?ext self_ fields =
29242936
in
29252937
let ast x = Ctf x in
29262938
let cmts_within =
2927-
if List.is_empty fields then
2928-
(* Side effect order is important. *)
2939+
if List.is_empty fields then (* Side effect order is important. *)
29292940
Cmts.fmt_within ~pro:noop c (Ast.location ctx)
29302941
else noop
29312942
in

lib/Params.ml

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,8 @@ type if_then_else =
692692
; space_between_branches: Fmt.t }
693693

694694
let get_if_then_else (c : Conf.t) ~first ~last ~parens_bch ~parens_prev_bch
695-
~xcond ~xbch ~expr_loc ~fmt_extension_suffix ~fmt_attributes ~fmt_cond =
695+
~xcond ~xbch ~expr_loc ~fmt_extension_suffix ~fmt_attributes ~fmt_cond
696+
~cmts_before_kw ~cmts_after_kw =
696697
let imd = c.fmt_opts.indicate_multiline_delimiters.v in
697698
let beginend, branch_expr =
698699
let ast = xbch.Ast.ast in
@@ -721,22 +722,28 @@ let get_if_then_else (c : Conf.t) ~first ~last ~parens_bch ~parens_prev_bch
721722
let cond () =
722723
match xcond with
723724
| Some xcnd ->
724-
hvbox 0
725-
( hvbox 2
726-
( fmt_if (not first) (str "else ")
727-
$ str "if"
728-
$ fmt_if first (fmt_opt fmt_extension_suffix)
729-
$ fmt_attributes $ space_break $ fmt_cond xcnd )
730-
$ space_break $ str "then" )
731-
| None -> str "else"
725+
hvbox 2
726+
( hvbox 0
727+
( hvbox 2
728+
( fmt_if (not first) (str "else ")
729+
$ str "if"
730+
$ fmt_if first (fmt_opt fmt_extension_suffix)
731+
$ fmt_attributes $ space_break $ fmt_cond xcnd )
732+
$ space_break $ cmts_before_kw $ str "then" )
733+
$ opt cmts_after_kw Fn.id )
734+
| None -> cmts_before_kw $ hvbox 2 (str "else" $ opt cmts_after_kw Fn.id)
735+
in
736+
let branch_pro ?(indent = 2) () =
737+
if Option.is_some cmts_after_kw then break 1000 indent
738+
else if beginend || parens_bch then str " "
739+
else break 1 indent
732740
in
733-
let branch_pro = fmt_or (beginend || parens_bch) (str " ") (break 1 2) in
734741
match c.fmt_opts.if_then_else.v with
735742
| `Compact ->
736743
{ box_branch= hovbox ~name:"Params.get_if_then_else `Compact" 2
737744
; cond= cond ()
738745
; box_keyword_and_expr= Fn.id
739-
; branch_pro= fmt_or (beginend || parens_bch) (str " ") space_break
746+
; branch_pro= branch_pro ~indent:0 ()
740747
; wrap_parens=
741748
wrap_parens
742749
~wrap_breaks:
@@ -752,7 +759,7 @@ let get_if_then_else (c : Conf.t) ~first ~last ~parens_bch ~parens_prev_bch
752759
{ box_branch= Fn.id
753760
; cond= cond ()
754761
; box_keyword_and_expr= Fn.id
755-
; branch_pro
762+
; branch_pro= branch_pro ()
756763
; wrap_parens= wrap_parens ~wrap_breaks:(wrap (break 1000 2) noop)
757764
; box_expr= Some false
758765
; expr_pro= None
@@ -769,7 +776,7 @@ let get_if_then_else (c : Conf.t) ~first ~last ~parens_bch ~parens_prev_bch
769776
| _ -> 0 )
770777
; cond= cond ()
771778
; box_keyword_and_expr= Fn.id
772-
; branch_pro
779+
; branch_pro= branch_pro ()
773780
; wrap_parens=
774781
wrap_parens
775782
~wrap_breaks:
@@ -792,7 +799,7 @@ let get_if_then_else (c : Conf.t) ~first ~last ~parens_bch ~parens_prev_bch
792799
{ box_branch= Fn.id
793800
; cond= cond ()
794801
; box_keyword_and_expr= Fn.id
795-
; branch_pro
802+
; branch_pro= branch_pro ()
796803
; wrap_parens=
797804
wrap_parens
798805
~wrap_breaks:
@@ -808,20 +815,26 @@ let get_if_then_else (c : Conf.t) ~first ~last ~parens_bch ~parens_prev_bch
808815
| `Closing_on_separate_line when parens_bch -> str " "
809816
| _ -> space_break ) }
810817
| `Keyword_first ->
811-
{ box_branch= Fn.id
812-
; cond=
813-
opt xcond (fun xcnd ->
814-
hvbox 2
815-
( fmt_or first
816-
(str "if" $ fmt_opt fmt_extension_suffix)
817-
(str "else if")
818-
$ fmt_attributes $ space_break $ fmt_cond xcnd )
819-
$ space_break )
820-
; box_keyword_and_expr=
821-
(fun k ->
818+
let keyword =
819+
hvbox 2
820+
( fmt_or (Option.is_some xcond) (str "then") (str "else")
821+
$ opt cmts_after_kw Fn.id )
822+
and cond =
823+
match xcond with
824+
| Some xcond ->
822825
hvbox 2
823-
(fmt_or (Option.is_some xcond) (str "then") (str "else") $ k) )
824-
; branch_pro= fmt_or (beginend || parens_bch) (str " ") space_break
826+
( fmt_or first
827+
(str "if" $ fmt_opt fmt_extension_suffix)
828+
(str "else if")
829+
$ fmt_attributes $ space_break $ fmt_cond xcond
830+
$ cmts_before_kw )
831+
$ space_break
832+
| None -> cmts_before_kw
833+
in
834+
{ box_branch= Fn.id
835+
; cond
836+
; box_keyword_and_expr= (fun k -> hovbox 2 (keyword $ k))
837+
; branch_pro= branch_pro ~indent:0 ()
825838
; wrap_parens=
826839
wrap_parens
827840
~wrap_breaks:
@@ -884,8 +897,7 @@ module Align = struct
884897

885898
let module_pack (c : Conf.t) ~me =
886899
if not c.fmt_opts.ocp_indent_compat.v then false
887-
else
888-
(* Align when the constraint is not desugared. *)
900+
else (* Align when the constraint is not desugared. *)
889901
match me.pmod_desc with
890902
| Pmod_structure _ | Pmod_ident _ -> false
891903
| _ -> true

lib/Params.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ val get_if_then_else :
191191
-> fmt_extension_suffix:Fmt.t option
192192
-> fmt_attributes:Fmt.t
193193
-> fmt_cond:(expression Ast.xt -> Fmt.t)
194+
-> cmts_before_kw:Fmt.t
195+
-> cmts_after_kw:Fmt.t option
194196
-> if_then_else
195197

196198
val match_indent : ?default:int -> Conf.t -> parens:bool -> ctx:Ast.t -> int

lib/Translation_unit.ml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,7 @@ let format (type ext std) (ext_fg : ext Extended_ast.t)
370370
Error
371371
(Unstable {iteration= i; prev= prev_source; next= fmted; input_name}
372372
) )
373-
else
374-
(* All good, continue *)
373+
else (* All good, continue *)
375374
print_check ~i:(i + 1) ~conf ~prev_source:fmted ext_t_new std_t_new
376375
in
377376
try print_check ~i:1 ~conf ~prev_source ext_parsed std_parsed with
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
Warning: tests/break_string_literals.ml:4 exceeds the margin
2-
Warning: tests/break_string_literals.ml:7 exceeds the margin
3-
Warning: tests/break_string_literals.ml:11 exceeds the margin
4-
Warning: tests/break_string_literals.ml:48 exceeds the margin
5-
Warning: tests/break_string_literals.ml:51 exceeds the margin
6-
Warning: tests/break_string_literals.ml:63 exceeds the margin
7-
Warning: tests/break_string_literals.ml:68 exceeds the margin
1+
Warning: tests/break_string_literals.ml:3 exceeds the margin
2+
Warning: tests/break_string_literals.ml:6 exceeds the margin
3+
Warning: tests/break_string_literals.ml:10 exceeds the margin
4+
Warning: tests/break_string_literals.ml:47 exceeds the margin
5+
Warning: tests/break_string_literals.ml:50 exceeds the margin
6+
Warning: tests/break_string_literals.ml:62 exceeds the margin
7+
Warning: tests/break_string_literals.ml:67 exceeds the margin

test/passing/tests/break_string_literals-never.ml.ref

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
let () =
2-
if true then
3-
(* Shrinking the margin a bit *)
2+
if true then (* Shrinking the margin a bit *)
43
Format.printf
54
"@[<v 2>@{<warning>@{<title>Warning@}@}@,@,\ These are @{<warning>NOT@} the Droids you are looking for!@,@,\ Some more text. Just more letters and words.@,\ All this text is left-aligned because it's part of the UI.@,\ It'll be easier for the user to read this message.@]@\n@."
65

test/passing/tests/break_string_literals.ml.ref

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
let () =
2-
if true then
3-
(* Shrinking the margin a bit *)
2+
if true then (* Shrinking the margin a bit *)
43
Format.printf
54
"@[<v 2>@{<warning>@{<title>Warning@}@}@,\
65
@,\

test/passing/tests/ite-compact.ml.ref

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,15 @@ let foo =
119119
let foo = if cmp < 0 then (* foo *) a + b else (* foo *) a - b
120120

121121
let foo =
122-
if cmp < 0 then
123-
(* ast higher precedence than context: no parens *)
122+
if cmp < 0 then (* foo *)
123+
a + b
124+
else (* foo *)
125+
a - b
126+
127+
let foo =
128+
if cmp < 0 then (* ast higher precedence than context: no parens *)
124129
false
125-
else if cmp > 0 then
126-
(* context higher prec than ast: add parens *)
130+
else if cmp > 0 then (* context higher prec than ast: add parens *)
127131
true
128132
else if Poly.(assoc_of_prec prec_ast = which_child && which_child <> Non)
129133
then foo
@@ -157,3 +161,18 @@ let _ =
157161
bar
158162
then 1
159163
else 2
164+
165+
let compare s1 s2 =
166+
if String.equal s1 s2 then (* this simplifies the next two cases *)
167+
0
168+
else if String.equal s1 Cmdliner.Manpage.s_options then
169+
(* ensure OPTIONS section is last (hence first in the manual) *)
170+
1
171+
else if String.equal s2 Cmdliner.Manpage.s_options then (* same as above *)
172+
-1
173+
else (* reverse order *)
174+
String.compare s2 s1
175+
176+
let _ = if x then 42 (* dummy *) else y
177+
178+
let _ = if x then 42 (* dummy *) else if y then z else w

0 commit comments

Comments
 (0)