Skip to content

Commit 945e5e1

Browse files
authored
Jump to declaration through aliases (#1563)
from voodoos/jump-to-declaration-through-aliases
2 parents 21ec4cf + 192ed6b commit 945e5e1

File tree

5 files changed

+78
-64
lines changed

5 files changed

+78
-64
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ unreleased
88
fixes #1564)
99
- Restore compatibility with some OCaml compiler's debug flags that were
1010
incorrectly rejected by Merlin. (#1556)
11+
- Traverse aliases when jumping to declaration. This matches
12+
jump-to-definition'q behavior (#1563)
1113

1214
merlin 4.7
1315
==========

src/analysis/locate.ml

Lines changed: 12 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,17 @@ let load_cmt ~config comp_unit ml_or_mli =
310310
Ok (source_file, cmt_infos)
311311
| None -> Error ()
312312

313+
let scrape_alias ~env ~fallback_uid path =
314+
let rec non_alias_declaration_uid ~fallback_uid path =
315+
match Env.find_module path env with
316+
| { md_type = Mty_alias path; md_uid = fallback_uid; _ } ->
317+
non_alias_declaration_uid ~fallback_uid path
318+
| { md_type = Mty_ident _ | Mty_signature _ | Mty_functor _ | Mty_for_hole;
319+
md_uid; _ }-> md_uid
320+
| exception Not_found -> fallback_uid
321+
in
322+
non_alias_declaration_uid ~fallback_uid path
323+
313324
let uid_of_path ~config ~env ~ml_or_mli ~decl_uid path ns =
314325
let module Shape_reduce =
315326
Shape.Make_reduce (struct
@@ -333,7 +344,7 @@ let uid_of_path ~config ~env ~ml_or_mli ~decl_uid path ns =
333344
end)
334345
in
335346
match ml_or_mli with
336-
| `MLI -> Some decl_uid
347+
| `MLI -> Some (scrape_alias ~fallback_uid:decl_uid ~env path)
337348
| `ML ->
338349
let shape = Env.shape_of_path ~namespace:ns env path in
339350
log ~title:"shape_of_path" "initial: %a"
@@ -343,48 +354,6 @@ let uid_of_path ~config ~env ~ml_or_mli ~decl_uid path ns =
343354
Logger.fmt (fun fmt -> Shape.print fmt r);
344355
r.uid
345356

346-
(** [module_aliasing] iterates on a typedtree to check if the provided uid
347-
corresponds to a module alias. If it does the function returns the uid of the
348-
aliased module. If not it returns None.
349-
The intended use of this function is to traverse dune-generated aliases. *)
350-
let module_aliasing ~(bin_annots : Cmt_format.binary_annots) uid =
351-
let exception Found of Path.t * Env.t in
352-
let iterator env = { Tast_iterator.default_iterator with
353-
module_binding = (fun sub mb ->
354-
begin match mb with
355-
| { mb_id = Some id; mb_expr = { mod_desc = Tmod_ident (path, _); _ }; _ }
356-
->
357-
let md = Env.find_module (Pident id) env in
358-
if Shape.Uid.equal uid md.md_uid then
359-
raise (Found (path, env))
360-
| _ -> () end;
361-
Tast_iterator.default_iterator.module_binding sub mb)
362-
}
363-
in
364-
try
365-
begin match bin_annots with
366-
| Interface s ->
367-
let sig_final_env = Envaux.env_of_only_summary s.sig_final_env in
368-
let iterator = iterator sig_final_env in
369-
iterator.signature iterator { s with sig_final_env }
370-
| Implementation str ->
371-
let str_final_env = Envaux.env_of_only_summary str.str_final_env in
372-
let iterator = iterator str_final_env in
373-
iterator.structure iterator { str with str_final_env }
374-
| _ -> () end;
375-
None
376-
with Found (path, env) ->
377-
let namespace = Shape.Sig_component_kind.Module in
378-
let shape = Env.shape_of_path ~namespace env path in
379-
log ~title:"locate" "Uid %a corresponds to an alias of %a
380-
which has the shape %a and the uid %a"
381-
Logger.fmt (fun fmt -> Shape.Uid.print fmt uid)
382-
Logger.fmt (fun fmt -> Path.print fmt path)
383-
Logger.fmt (fun fmt -> Shape.print fmt shape)
384-
Logger.fmt (fun fmt ->
385-
Format.pp_print_option Shape.Uid.print fmt shape.uid);
386-
Option.map ~f:(fun uid -> uid, path) shape.uid
387-
388357
let from_uid ~config ~ml_or_mli uid loc path =
389358
let loc_of_comp_unit comp_unit =
390359
match load_cmt ~config comp_unit ml_or_mli with
@@ -420,20 +389,6 @@ let from_uid ~config ~ml_or_mli uid loc path =
420389
log ~title "Shapes successfully loaded, looking for %a"
421390
Logger.fmt (fun fmt -> Shape.Uid.print fmt uid);
422391
begin match Shape.Uid.Tbl.find_opt cmt.cmt_uid_to_loc uid with
423-
| Some loc when
424-
String.ends_with ~suffix:"ml-gen" loc.loc_start.pos_fname ->
425-
log ~title "Found location in generated file: %a"
426-
Logger.fmt (fun fmt -> Location.print_loc fmt loc);
427-
(* This notably happens when using Dune. In that case we
428-
try to resolve the alias immediately. *)
429-
begin match module_aliasing ~bin_annots:cmt.cmt_annots uid with
430-
| Some (Shape.Uid.Compilation_unit comp_unit as uid, _path) ->
431-
log ~title
432-
"The alias points to another compilation unit %s" comp_unit;
433-
loc_of_comp_unit comp_unit
434-
|> Option.map ~f:(fun loc -> uid, loc)
435-
| _ -> Some (uid, loc)
436-
end
437392
| Some loc ->
438393
log ~title "Found location: %a"
439394
Logger.fmt (fun fmt -> Location.print_loc fmt loc);

tests/test-dirs/locate/dune

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
(cram
22
(applies_to looping-substitution mutually-recursive partial-cmt includes
33
issue802 issue845 issue1199 issue1524 sig-substs l-413-features
4-
module-aliases locate-constrs without-implem without-sig)
4+
module-aliases locate-constrs without-implem without-sig module-decl-aliases)
55
(enabled_if
66
(<> %{os_type} Win32)))
77

tests/test-dirs/locate/module-aliases.t/run.t

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,11 @@ Jump to an aliased module `A|.f`:
6565
}
6666

6767
Jump to the declaration of an aliased module `A|.f`.
68-
With the new shape implementation it is expected that we jump to the
69-
declaration of the alias and not to the aliased module itself.
68+
The alias is traversed.
7069
$ $MERLIN single locate -look-for mli -position 5:2 \
7170
> -filename ./main.ml < ./main.ml | jq '.value'
7271
{
73-
"file": "$TESTCASE_ROOT/main.ml",
72+
"file": "$TESTCASE_ROOT/anothermod.mli",
7473
"pos": {
7574
"line": 1,
7675
"col": 0
@@ -168,12 +167,11 @@ Jump to an aliased module `A|.f`:
168167
}
169168

170169
Jump to the declaration of an aliased module `A|.f`:
171-
With the new shape implementation it is expected that we jump to the
172-
declaration of the alias and not to the aliased module itself.
170+
The alias is traversed.
173171
$ $MERLIN single locate -look-for mli -position 5:2 \
174172
> -filename ./main.ml < ./main.ml | jq '.value'
175173
{
176-
"file": "$TESTCASE_ROOT/main.ml",
174+
"file": "$TESTCASE_ROOT/anothermod.mli",
177175
"pos": {
178176
"line": 1,
179177
"col": 0
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
$ cat >main.ml <<EOF
2+
> module Bar : sig
3+
> module Foo : sig
4+
> val v : int
5+
> end
6+
> end = struct
7+
> module Foo = struct
8+
> let v = 42
9+
> end
10+
> end
11+
> module Foo = Bar.Foo
12+
> let _ = Foo.v
13+
> EOF
14+
15+
$ cat>other.ml <<EOF
16+
> module Foo = Main.Bar.Foo
17+
> let _ = Foo.v
18+
> EOF
19+
20+
$ $OCAMLC -c -bin-annot main.ml other.ml
21+
22+
$ $MERLIN single locate -look-for ml -position 11:10 \
23+
> -filename ./main.ml < ./main.ml | jq '.value'
24+
{
25+
"file": "$TESTCASE_ROOT/main.ml",
26+
"pos": {
27+
"line": 6,
28+
"col": 2
29+
}
30+
}
31+
32+
$ $MERLIN single locate -look-for mli -position 11:10 \
33+
> -filename ./main.ml < ./main.ml | jq '.value'
34+
{
35+
"file": "$TESTCASE_ROOT/main.ml",
36+
"pos": {
37+
"line": 2,
38+
"col": 2
39+
}
40+
}
41+
$ $MERLIN single locate -look-for ml -position 2:10 \
42+
> -filename ./other.ml < ./other.ml | jq '.value'
43+
{
44+
"file": "$TESTCASE_ROOT/main.ml",
45+
"pos": {
46+
"line": 6,
47+
"col": 2
48+
}
49+
}
50+
51+
$ $MERLIN single locate -look-for mli -position 2:10 \
52+
> -filename ./other.ml < ./other.ml | jq '.value'
53+
{
54+
"file": "$TESTCASE_ROOT/main.ml",
55+
"pos": {
56+
"line": 2,
57+
"col": 2
58+
}
59+
}

0 commit comments

Comments
 (0)