jfmengels / elm-review-unused

Provides elm-review rules to detect unused elements in your Elm project
https://package.elm-lang.org/packages/jfmengels/elm-review-unused/latest/
BSD 3-Clause "New" or "Revised" License
23 stars 12 forks source link

New rule: No unused record fields #15

Open jfmengels opened 4 years ago

jfmengels commented 4 years ago

What the rule should do:

Report unused fields in records, records defined in type aliases and in records that are arguments to custom types constructors.

What problems does it solve:

It will help remove and uncover more unused code.

Example of things the rule would report:

In the following example, the unused field is not used and should be reported.

someOperation : { x : Int, unused : Int } -> Int
--           reported here ^^^^^^
someOperation record =
  record.x

The advice would be to use { a | x : Int } or to remove the unused field.

In the following example, the unused field is not used in any places where we declare Record to be used

type alias Record = { w : Int, x : Int, y : Int, z : Int, unused : Int }
--                                          reported here ^^^^^^
someOperation : Record -> Int
someOperation ({x} as record) = 
  let
    {y} = record
  in
  .w record + x + y + record.z

The same result should appear if the record was wrapped in a custom type constructor.

type Record = Record { x : Int, y : Int, z : Int, unused : Int }
--                                  reported here ^^^^^^
someOperation : Record -> Int
someOperation ((Record {x}) as fullRecord) = 
  let
    (Record record) = fullRecord
    {y} = record
  in
  x + y + record.z

Example of things the rule would not report:

Notes:

I think this can be quite a tricky rule to implement, and it will likely require many, many iterations to get rid of all false positives and false negatives. If we have to choose between one, we should choose false negatives, as that will avoid putting unnecessary annoyances on the user (especially since we can't disable rules locally).

I imagine we could potentially have a more aggressive version of the rule, under a different name or with a configuration flag, that is more aggressive. That would allow people to do some more manual removals when they fancy to, and allow us to experiment and improve the rule.

Things start to get tricky when you pass in records to other functions, because you will have to dig more into whether something is used or not.

I am looking for:

I think the first step for writing this rule would be handling the first example, and then seeing what false positives come out of that and fix them. We can deal with record aliases and ones in custom types later.

I don't know how things will work when type annotations are missing, so let's skip the annotated values for the initial phase.

jfmengels commented 1 year ago

I haven't made any recent progress. but I have pushed a branch unused-record-fields, which I haven't touched it in a while, and I honestly don't remember where it's at very much.

Should someone want to look into this, I guess you can run the rule from that branch on a codebase and see what it's reporting and shouldn't, and start from there (if you want to start from what I did). There seems to be tests that I've skipped but that should be handled.

Also, in the long run (in a thought that came after the creation of my branch), I think we should merge this rule with NoUnused.CustomTypeConstructorArgs as described in #74.