diff --git a/CHANGES.md b/CHANGES.md index 26b274947..f171f3835 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,8 @@ UNRELEASED - Perform incremental indexation of the buffer when typing. (#1777) - `merlin-lib.commands`: Add a `find_command_opt`` alternative to `find_command` that does not raise (#1778) + - Prevent uid clashes by not returning PWO for defs located in the current + interface file (#1781) + editor modes - emacs: add basic support for project-wide occurrences (#1766) - vim: add basic support for project-wide occurrences (#1767, @Julow) diff --git a/src/analysis/occurrences.ml b/src/analysis/occurrences.ml index 1a7aad559..9e3458476 100644 --- a/src/analysis/occurrences.ml +++ b/src/analysis/occurrences.ml @@ -117,6 +117,11 @@ let get_buffer_locs result uid = (Mtyper.get_index result) Lid_set.empty +let is_in_interface (config : Mconfig.t) (loc : Warnings.loc) = + let extension = Filename.extension loc.loc_start.pos_fname in + List.exists config.merlin.suffixes + ~f:(fun (_impl, intf) -> String.equal extension intf) + let locs_of ~config ~env ~typer_result ~pos ~scope path = log ~title:"occurrences" "Looking for occurences of %s (pos: %s)" path @@ -135,10 +140,31 @@ let locs_of ~config ~env ~typer_result ~pos ~scope path = (* We are on a definition / declaration so we look for the node's uid *) let browse = Mbrowse.of_typedtree local_defs in let env, node = Mbrowse.leaf_node (Mbrowse.enclosing pos [browse]) in - uid_and_loc_of_node env node, scope + let node_uid_loc = uid_and_loc_of_node env node in + let scope = + match node_uid_loc with + | Some (_, l) when is_in_interface config l -> + (* There is no way to distinguish uids from interfaces from uids of + implementations. We fallback on buffer occurrences in that case. + TODO: we should be able to improve on that situation when we will be + able to distinguish between impl/intf uids and know which declaration + are actually linked. *) + `Buffer + | _ -> scope + in + node_uid_loc, scope | `Found { uid; location; approximated = false; _ } -> log ~title:"locs_of" "Found definition uid using locate: %a " Logger.fmt (fun fmt -> Shape.Uid.print fmt uid); + (* There is no way to distinguish uids from interfaces from uids of + implementations. We fallback on buffer occurrences in that case. + TODO: we should be able to improve on that situation when we will be + able to distinguish between impl/intf uids and know which declaration + are actually linked. *) + let scope = + if is_in_interface config location then `Buffer + else scope + in Some (uid, location), scope | `Found { decl_uid; location; approximated = true; _ } -> log ~title:"locs_of" "Approx. definition: %a " @@ -178,7 +204,12 @@ let locs_of ~config ~env ~typer_result ~pos ~scope path = Lid_set.filter (fun {loc; _} -> (* We ignore external results that concern the current buffer *) let file = loc.Location.loc_start.Lexing.pos_fname in - if String.equal file current_buffer_path then false + let file, buf = + match config.merlin.source_root with + | Some root -> Filename.concat root file, current_buffer_path + | None -> file, config.query.filename + in + if String.equal file buf then false else begin (* We ignore external results if their source was modified *) let check = Stat_check.check stats ~file in diff --git a/tests/test-dirs/occurrences/project-wide/mli-vs-ml.t b/tests/test-dirs/occurrences/project-wide/mli-vs-ml.t new file mode 100644 index 000000000..12e0926dc --- /dev/null +++ b/tests/test-dirs/occurrences/project-wide/mli-vs-ml.t @@ -0,0 +1,86 @@ + $ cat >main.mli <<'EOF' + > type t = unit + > val x : t + > EOF + + $ cat >main.ml <<'EOF' + > let x = () + > type t = unit + > EOF + + $ ocamlc -bin-annot -bin-annot-occurrences -c main.mli main.ml + + $ ocaml-index aggregate main.cmti main.cmt + +The indexer should not mixup uids from mli and ml files: + $ ocaml-index dump project.ocaml-index + 2 uids: + {uid: Main.0; locs: "x": File "main.ml", line 1, characters 4-5 + uid: Main.1; locs: "t": File "main.ml", line 2, characters 5-6 }, + 0 approx shapes: {}, and shapes for CUS . + +Merlin should not mixup uids from mli and ml files: + $ $MERLIN single occurrences -scope project -identifier-at 2:8 \ + > -index-file project.ocaml-index \ + > -filename main.mli -index-file project.ocaml-index \ + > -filename main.mli