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

Code actions for marking & removing unused code #502

Merged
merged 1 commit into from
Oct 14, 2021

Conversation

jfeser
Copy link
Collaborator

@jfeser jfeser commented Sep 3, 2021

Adds code actions for marking unused code (i.e. by prepending '_' to variable names) and for removing unused code. Currently it can remove unused types, modules, opens, constructors, and variables.

@rgrinberg rgrinberg force-pushed the action-mark-unused-value branch from d689c60 to 44a1316 Compare September 4, 2021 04:31
Copy link
Member

@rgrinberg rgrinberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. A few small tweaks and it should be good to go.

Copy link
Collaborator

@ulugbekna ulugbekna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code actions don't work for me since the error messages have the form (after rebasing to the latest master):

image

I guess we could search for a substring but pessimistic about such solution's performance. Wdyt?

There are a couple more changes that I have in mind before merging the PR, which I'll add tomorrow hopefully

@jfeser
Copy link
Collaborator Author

jfeser commented Sep 7, 2021

This still needs some changes to pick up the right error messages.

How does ocamllsp decide which diagnostics to show? I have a test project with all warnings turned on, but I only see a subset of them in my editor. When I build with dune I see all of the warnings.

@ulugbekna
Copy link
Collaborator

ulugbekna commented Sep 7, 2021 via email

@jfeser
Copy link
Collaborator Author

jfeser commented Sep 7, 2021

My understanding is that merlin gets configs from dune (through dune ocaml-merlin?). So I'm not sure why it's not picking up my dune file config.

@jfeser
Copy link
Collaborator Author

jfeser commented Sep 7, 2021

It seems that merlin is in fact seeing my config. However, it doesn't support most of the "unused X" warnings.

Supported: 26, 27
Unsupported: 32-37, 60, 66

Not sure how hard it would be to get support for 32-37 into merlin.

@rgrinberg
Copy link
Member

Can you upload the project where you're testing this stuff? AFAIK, merlin doesn't special case any warnings and just reads the warning config from dune.

@jfeser
Copy link
Collaborator Author

jfeser commented Sep 7, 2021

https://github.com/jfeser/warnings-test

Merlin doesn't special case warnings, but I think they only hook into certain parts of the compiler (ocaml/merlin#343). They also do some filtering (ocaml/merlin#419).

@rgrinberg
Copy link
Member

In that case what you have is fine. Soon, some diagnostics will come directly from the dune build so your code actions will be picked up from there.

@jfeser
Copy link
Collaborator Author

jfeser commented Sep 8, 2021

That's good to hear.

@ulugbekna Have another look. The code actions should work now.

Copy link
Collaborator

@ulugbekna ulugbekna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the code looks much better and works like a charm! :-)

Importantly, I think that these two code actions are activated in a very similar setting & should be combined to avoid duplicate work of filtering diagnostics.

Regarding testing, ideally, we would pass code to ocaml-lsp, get diagnostics for the code, and use those real diagnostics to test the code. Thus, we would catch if the diag messages for warnings 26 and 27 are changed.

I also left some suggestions inline.

ocaml-lsp-server/src/code_actions/action_mark_unused.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/code_actions/action_mark_unused.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/code_actions/action_remove_unused.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/code_actions/diagnostic_util.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/document.ml Outdated Show resolved Hide resolved
@ulugbekna ulugbekna force-pushed the action-mark-unused-value branch from 1704923 to 5360fcb Compare September 10, 2021 12:35
@ulugbekna
Copy link
Collaborator

ulugbekna commented Sep 10, 2021

We should better handle patterns.

  1. We should make sure that mark as unused for fields in a record have a different edit, ie { a; b = _ }. Currently, we propose an edit that results in an error.

image

We need to inspect the context in which we propose the code action. Ideally, we should do that in the same pattern match as enclosing_value_binding_range.

  1. Optionally, removing unused record fields also seems plausible: we should check whether the pattern for the record is closed or not, based on that we can simply remove the field or remove the field and put ; _ after the last field. This doesn't have to happen in this PR though.

  2. Optionally, we could also offer removing unused vars from patterns, eg (a, b, c) -> (a, b). More challenging than the rest of course.


Importantly, I think we don't need to handle structure_items in enclosing_value_binding_range, because the following will not trigger a diagnostic in merlin as of now:

(* foo.ml *) 
let a = 1 (* [a] is not used, but no warning *)

Only on build we get a warning 32 about unused val declaration.


I think there is also a dangling file action_remove_unused.ml or something?

@rgrinberg rgrinberg requested review from rgrinberg and removed request for rgrinberg October 4, 2021 01:24
@jfeser
Copy link
Collaborator Author

jfeser commented Oct 8, 2021

  1. We should make sure that mark as unused for fields in a record have a different edit, ie { a; b = _ }. Currently, we
    propose an edit that results in an error.

Good catch. I think that should be fixed now.

  1. Optionally, removing unused record fields also seems plausible: we should check whether the pattern for the record is closed or not, based on that we can simply remove the field or remove the field and put ; _ after the last field. This doesn't have to happen in this PR though.

Yep, this would be a nice addition.

  1. Optionally, we could also offer removing unused vars from patterns, eg (a, b, c) -> (a, b). More challenging than the rest of course.

Would this be (a,b,c) -> (a,b,_)?

Importantly, I think we don't need to handle structure_items in enclosing_value_binding_range, because the following will not trigger a diagnostic in merlin as of now:
I think there is also a dangling file action_remove_unused.ml or something?

Yep, removed.

@jfeser jfeser force-pushed the action-mark-unused-value branch from 263fb86 to aa8b52d Compare October 11, 2021 17:56
values, types, modules, opens
@rgrinberg rgrinberg force-pushed the action-mark-unused-value branch from aa8b52d to 6286a66 Compare October 14, 2021 18:44
@rgrinberg rgrinberg merged commit 91c855a into ocaml:master Oct 14, 2021
@rgrinberg
Copy link
Member

merging to avoid making the author resolve more merge conflicts. if any other improvements are necessary, please continue them in separate PR's.

rgrinberg added a commit to rgrinberg/opam-repository that referenced this pull request Nov 21, 2021
CHANGES:

## Fixes

- Ppx processes are now executed correctly (ocaml/ocaml-lsp#513)

## Breaking Change

- ocamllsp drops support for `.merlin` files, and as a consequence no longer
  depends on dot-merlin-reader. (ocaml/ocaml-lsp#523)

## Features

- New code action to automatically remove values, types, opens (ocaml/ocaml-lsp#502)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants