Skip to content

Fields and constructors uses are not tracked through include #82

@fantazio

Description

@fantazio

Context

This is a pattern observed in Opam 2.5.1. 2 compilation units define the same type (uname), one in the .ml (here) and one in the .mli (here), the .ml of the latter includes the .ml of the former (here), components of the latter are used in another compilation unit (here, here, and here), while the former is never used.

This leads the analyzer to report the constructors and fields in the former module to be reported as unused although they are in the latter module.

This observation can be extended to uses of the former constructors and fields not being linked to the latter.
The types in the former and the later modules seem to behave independently although they are connected by the module inclusion.

Another observation was made in Opam 2.5.1 within a single compilation unit:
The .mli exported OPAM.t, while in the .ml, OPAM includes OPAMSyntax which defines type t. One of the fields (metadata_dir) is used within OPAMSyntax but the analyzer would report OPAM.t.metadata_dir as unused.

Example and reproduction

(* /tmp/incltype/intf.ml *)
type sum = UsedByIntf | UsedByImpl | UsedExternally | Unused

type product = {
  used_by_intf : unit;
  used_by_impl : unit;
  used_externally : unit;
  unused : unit
}

let _ = UsedByIntf
let _ = fun p -> p.used_by_intf
(* /tmp/incltype/impl.mli *)
type sum = UsedByIntf | UsedByImpl | UsedExternally | Unused

type product = {
  used_by_intf : unit;
  used_by_impl : unit;
  used_externally : unit;
  unused : unit
}
(* /tmp/incltype/impl.ml *)
include Intf

let _ = UsedByImpl
let _ = fun p -> p.used_by_impl
(* /tmp/incltype/use.ml *)
let _ = Impl.UsedExternally
let _ = fun p -> p.Impl.used_externally

The compilation units Intf and Impl define and export the same types. Intf is included in Impl's implementation.

$ ocamlopt -bin-annot intf.ml impl.mli impl.ml use.ml 
$ dead_code_analyzer --nothing -T all .
Scanning files...
 [DONE]

.> UNUSED CONSTRUCTORS/RECORD FIELDS:
====================================
/tmp/incltype/impl.mli:2: sum.UsedByIntf
/tmp/incltype/impl.mli:2: sum.UsedByImpl
/tmp/incltype/impl.mli:2: sum.Unused
/tmp/incltype/impl.mli:5: product.used_by_intf
/tmp/incltype/impl.mli:6: product.used_by_impl
/tmp/incltype/impl.mli:8: product.unused
/tmp/incltype/intf.ml:2: sum.UsedExternally
/tmp/incltype/intf.ml:2: sum.Unused
/tmp/incltype/intf.ml:7: product.used_externally
/tmp/incltype/intf.ml:8: product.unused

Nothing else to report in this section
--------------------------------------------------------------------------------

The Unused constructors and unused fields are correctly reported.
All the other reports are false positives because one cannot remove a reported constructor or field from a type (in Impl or in Intf) without removing it from its duplicate (resp. in Intf or in Impl).

Metadata

Metadata

Assignees

No one assigned

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions