Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not return PWO for defs in the current interface file #1781

Merged
merged 4 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
35 changes: 33 additions & 2 deletions src/analysis/occurrences.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 "
Expand Down Expand Up @@ -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
Expand Down
86 changes: 86 additions & 0 deletions tests/test-dirs/occurrences/project-wide/mli-vs-ml.t
Original file line number Diff line number Diff line change
@@ -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 <main.mli
{
"class": "return",
"value": [
{
"file": "$TESTCASE_ROOT/main.mli",
"start": {
"line": 1,
"col": 5
},
"end": {
"line": 1,
"col": 6
}
},
{
"file": "$TESTCASE_ROOT/main.mli",
"start": {
"line": 2,
"col": 8
},
"end": {
"line": 2,
"col": 9
}
}
],
"notifications": []
}

Same when the cursor is at the origin:
$ $MERLIN single occurrences -scope project -identifier-at 1:5 \
> -index-file project.ocaml-index \
> -filename main.mli <main.mli
{
"class": "return",
"value": [
{
"file": "$TESTCASE_ROOT/main.mli",
"start": {
"line": 1,
"col": 5
},
"end": {
"line": 1,
"col": 6
}
},
{
"file": "$TESTCASE_ROOT/main.mli",
"start": {
"line": 2,
"col": 8
},
"end": {
"line": 2,
"col": 9
}
}
],
"notifications": []
}
Loading