diff --git a/check/classic/classic.exp b/check/classic/classic.exp index dd991654..68251b46 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -238,6 +238,14 @@ Nothing else to report in this section .> UNUSED CONSTRUCTORS/RECORD FIELDS: ==================================== +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:4: gadt.Float + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:4: t.Left +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:5: t.Right + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Right +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.left + ./examples/using_dune/preprocessed_lib/preprocessed.mli:14: constructors.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:19: constr_with_eq.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:23: record.unused diff --git a/check/classic/classic.ref b/check/classic/classic.ref index 093c0b1d..b837848f 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -243,6 +243,14 @@ Nothing else to report in this section .> UNUSED CONSTRUCTORS/RECORD FIELDS: ==================================== +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:4: gadt.Float + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:4: t.Left +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:5: t.Right + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Right +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.left + ./examples/using_dune/preprocessed_lib/preprocessed.mli:14: constructors.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:19: constr_with_eq.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:23: record.unused @@ -656,7 +664,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 557 -Success: 550 +Total: 562 +Success: 555 Failed: 7 -Ratio: 98.7432675045% +Ratio: 98.7544483986% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index e6137438..935927e4 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -193,6 +193,14 @@ Nothing else to report in this section .> UNUSED CONSTRUCTORS/RECORD FIELDS: ==================================== +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:4: gadt.Float + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:4: t.Left +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:5: t.Right + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Right +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.left + ./examples/using_dune/preprocessed_lib/preprocessed.mli:14: constructors.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:19: constr_with_eq.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:23: record.unused diff --git a/check/internal/internal.ref b/check/internal/internal.ref index 5ba89818..71bf3316 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -198,6 +198,14 @@ Nothing else to report in this section .> UNUSED CONSTRUCTORS/RECORD FIELDS: ==================================== +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:4: gadt.Float + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:4: t.Left +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:5: t.Right + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Right +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.left + ./examples/using_dune/preprocessed_lib/preprocessed.mli:14: constructors.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:19: constr_with_eq.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:23: record.unused @@ -611,7 +619,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 515 -Success: 508 +Total: 520 +Success: 513 Failed: 7 -Ratio: 98.640776699% +Ratio: 98.6538461538% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index a330fc91..921661fb 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -140,6 +140,14 @@ ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:2: hello ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:3: goodbye +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:6: gadt_of_int +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:8: float_opt_of_gadt + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:7: get_left_opt + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli:4: poly_of_int +./examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli:6: float_opt_of_poly + ./examples/docs/methods/code_constructs/class/class_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times @@ -542,6 +550,14 @@ Nothing else to report in this section .> UNUSED CONSTRUCTORS/RECORD FIELDS: ==================================== +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:4: gadt.Float + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:4: t.Left +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:5: t.Right + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Right +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.left + ./examples/using_dune/preprocessed_lib/preprocessed.mli:14: constructors.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:19: constr_with_eq.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:23: record.unused @@ -614,6 +630,13 @@ Nothing else to report in this section .>-> ALMOST UNUSED CONSTRUCTORS/RECORD FIELDS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:3: gadt.Int + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:3: t.Both + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Left +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.right + ./examples/using_dune/preprocessed_lib/preprocessed.mli:16: constructors.Internally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:17: constructors.Externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:25: record.internally_used diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index ce484c1c..19fda17c 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -145,6 +145,14 @@ ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:2: hello ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:3: goodbye +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:6: gadt_of_int +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:8: float_opt_of_gadt + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:7: get_left_opt + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli:4: poly_of_int +./examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli:6: float_opt_of_poly + ./examples/docs/methods/code_constructs/class/class_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times @@ -546,6 +554,14 @@ Nothing else to report in this section .> UNUSED CONSTRUCTORS/RECORD FIELDS: ==================================== +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:4: gadt.Float + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:4: t.Left +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:5: t.Right + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Right +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.left + ./examples/using_dune/preprocessed_lib/preprocessed.mli:14: constructors.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:19: constr_with_eq.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:23: record.unused @@ -618,6 +634,13 @@ Nothing else to report in this section .>-> ALMOST UNUSED CONSTRUCTORS/RECORD FIELDS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:3: gadt.Int + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:3: t.Both + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Left +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.right + ./examples/using_dune/preprocessed_lib/preprocessed.mli:16: constructors.Internally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:17: constructors.Externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:25: record.internally_used @@ -1033,7 +1056,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 875 -Success: 867 +Total: 889 +Success: 881 Failed: 8 -Ratio: 99.0857142857% +Ratio: 99.1001124859% diff --git a/check/threshold-3-0.5/threshold-3-0.5.exp b/check/threshold-3-0.5/threshold-3-0.5.exp index 8992101b..4775bdc0 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -140,6 +140,14 @@ ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:2: hello ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:3: goodbye +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:6: gadt_of_int +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:8: float_opt_of_gadt + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:7: get_left_opt + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli:4: poly_of_int +./examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli:6: float_opt_of_poly + ./examples/docs/methods/code_constructs/class/class_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times @@ -719,6 +727,14 @@ Nothing else to report in this section .> UNUSED CONSTRUCTORS/RECORD FIELDS: ==================================== +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:4: gadt.Float + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:4: t.Left +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:5: t.Right + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Right +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.left + ./examples/using_dune/preprocessed_lib/preprocessed.mli:14: constructors.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:19: constr_with_eq.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:23: record.unused @@ -791,6 +807,13 @@ Nothing else to report in this section .>-> ALMOST UNUSED CONSTRUCTORS/RECORD FIELDS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:3: gadt.Int + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:3: t.Both + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Left +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.right + ./examples/using_dune/preprocessed_lib/preprocessed.mli:16: constructors.Internally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:17: constructors.Externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:25: record.internally_used diff --git a/check/threshold-3-0.5/threshold-3-0.5.ref b/check/threshold-3-0.5/threshold-3-0.5.ref index ffdf5ab0..f8c1ffad 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -145,6 +145,14 @@ ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:2: hello ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:3: goodbye +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:6: gadt_of_int +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:8: float_opt_of_gadt + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:7: get_left_opt + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli:4: poly_of_int +./examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli:6: float_opt_of_poly + ./examples/docs/methods/code_constructs/class/class_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times @@ -723,6 +731,14 @@ Nothing else to report in this section .> UNUSED CONSTRUCTORS/RECORD FIELDS: ==================================== +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:4: gadt.Float + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:4: t.Left +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:5: t.Right + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Right +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.left + ./examples/using_dune/preprocessed_lib/preprocessed.mli:14: constructors.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:19: constr_with_eq.Unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:23: record.unused @@ -795,6 +811,13 @@ Nothing else to report in this section .>-> ALMOST UNUSED CONSTRUCTORS/RECORD FIELDS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:3: gadt.Int + +./examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:3: t.Both + +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Left +./examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.right + ./examples/using_dune/preprocessed_lib/preprocessed.mli:16: constructors.Internally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:17: constructors.Externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:25: record.internally_used @@ -1432,7 +1455,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1192 -Success: 1184 +Total: 1206 +Success: 1198 Failed: 8 -Ratio: 99.3288590604% +Ratio: 99.3366500829% diff --git a/docs/USER_DOC.md b/docs/USER_DOC.md index f1d813ff..cd104afd 100644 --- a/docs/USER_DOC.md +++ b/docs/USER_DOC.md @@ -55,6 +55,7 @@ This documentation is split accross different topics: - [Usage](USAGE.md) describes the usage of the `dead_code_analyzer` and its options. - [Exported Values](exported_values/EXPORTED_VALUES.md) describes the semantics and usage of the "unused exported values" report section, and provides examples. - [Methods](methods/METHODS.md) describes the semantics and usage of the "unused methods" report section, and provides examples. +- [Constructors/Record fields](fields_and_constructors/FIELDS_AND_CONSTRUCTORS.md) describes the semantics and usage of the "unused constructors/record fields" report section, and provides examples. ## Footnotes diff --git a/docs/fields_and_constructors/FIELDS_AND_CONSTRUCTORS.md b/docs/fields_and_constructors/FIELDS_AND_CONSTRUCTORS.md new file mode 100644 index 00000000..b3e7b733 --- /dev/null +++ b/docs/fields_and_constructors/FIELDS_AND_CONSTRUCTORS.md @@ -0,0 +1,212 @@ +# Table of contents + ++ [Fields and constructors](#fields-and-constructors) + + [Definitions](#definitions) + + [Compiler warnings](#compiler-warnings) + + [Warning 37: unused-constructor](#warning-37-unused-constructor) + + [Warning 69: unused-field](#warning-69-unused-field) + + [Usage](#usage) ++ [Examples](#examples) ++ [Limitations](#limitations) + + [Polymorphic variant](#polymorphic-variant) + +# Fields and constructors + +## Definitions + +A **constructor** is a named value of a variant type. + +A **field** is a named value inside a record type. + +An **exported** constructor or field is one that is is declared in its +compilation unit's signature. + +A **private** field or constructor is one in a private record or variant type. +A private type is declared using the `private` keyword. + +A **use** is either : +- Applying a constructor. + E.g. + ```OCaml + type side = Left | Right + + let make_left () = Left + ``` + The constructor `Left` is applied in `make_left`. +- Reading a field. + E.g. + ```OCaml + type point = {x : float; y : float} + + let get_x p = p.x + ``` + The field `point.x` is read in `get_x`. + +> [!IMPORTANT] +> A **use** is **not**: +> - De-structuring a constructor. +> E.g. +> ```OCaml +> type side = Left | Right +> +> let string_of_side = function +> | Left -> "Left" +> | Right -> "Right" +> ``` +> Constructors `Left` and `Right` are matched on but never applied. +> - Writing to a field. +> E.g. +> ```OCaml +> type point = {x : float; y : float} +> +> let make_point x y = {x; y} +> ``` +> The fields `point.x` and `point.y` are written but never read. + +## Compiler warnings + +The analyzer reports unused exported fields and constructors, while the compiler +reports unused unexported fields and constructors. They complement each other. +The compiler also warns on unused private constructors (but not private fields +since they can still be read). The analyzer's reports overlap with the compiler +on unused exported private constructors. + +> [!TIP] +> To obtain a list of available compiler warnings, use +> `ocamlopt -warn-help` + +The compiler warnings related to unused fields and constructors are the 37, and 69. +The first one is for unexported constructors, the second for unexported fields. + +### Warning 37: unused-constructor + +This warning is disabled by default. +It can be enabled by passing the `-w +37` to the compiler. + +Description: +``` +37 [unused-constructor] Unused constructor. (since 4.00) +``` + +Example +```OCaml +(* warning37.mli *) +``` +```OCaml +(* warning37.ml *) +type 'a opt = None | Some of 'a + +let is_some = function + | Some _ -> true + | _ -> false +``` +``` +$ ocamlopt -w +37 warning37.mli warning37.ml +File "warning37.ml", line 2, characters 14-18: +2 | type 'a opt = None | Some of 'a + ^^^^ +Warning 37 [unused-constructor]: unused constructor None. + +File "warning37.ml", line 2, characters 19-31: +2 | type 'a opt = None | Some of 'a + ^^^^^^^^^^^^ +Warning 37 [unused-constructor]: constructor Some is never used to build values. +(However, this constructor appears in patterns.) +``` + +### Warning 69: unused-field + +This warning is disabled by default. +It can be enabled by passing the `-w +69` to the compiler. + +Description: +``` +69 [unused-field] Unused record field. (since 4.13) +``` + +Example: +```OCaml +(* warning69.mli *) +``` +```OCaml +(* warning69.ml *) +type point = {x : float; y : float} + +let move_x p x = {p with x} +``` +``` +$ ocamlopt -w +69 warning69.mli warning69.ml +File "warning69.ml", line 2, characters 14-24: +2 | type point = {x : float; y : float} + ^^^^^^^^^^ +Warning 69 [unused-field]: record field x is never read. +(However, this field is used to build or mutate values.) + +File "warning69.ml", line 2, characters 25-34: +2 | type point = {x : float; y : float} + ^^^^^^^^^ +Warning 69 [unused-field]: unused record field y. +``` + +## Usage + +Unused exported fields and records are reported by default. +Their reports can be deactivated using the `--nothing` or `-T nothing` +command line arguments. +They can be reactivated by using the `--all` or `-T all` command line arguments. +For more details about the command line arguments see [the more general Usage +documentation](../USAGE.md). + +The report section looks like: +``` +.> UNUSED CONSTRUCTORS/RECORD FIELDS: +==================================== +filepath:line: type.value + +Nothing else to report in this section +-------------------------------------------------------------------------------- +``` +The report line format is `filepath:line: type.value` with `filepath` the absolute +path to the file (`.mli` if available, `.ml` otherwise) where `value` is +declared, `line` the line index in `filepath` at which `value` is declared, +`type` the path of the record or variant type within its compilation unit +(e.g. `M.t`) to which `value` belongs, and `value` the unused field or constructor. +There can be any number of such lines. + +The expected resolution for an unused exported field or constructor is to remove +it from its type's definition. + +The expected resolution for an unused exported value is to remove it from the +`.mli` if there is one, and the `.ml`. + +> [!IMPORTANT] +> Removing unused fields or constructors may lead to compilation errors, because +> one had to write all the fields when building a record, and potentially match +> on the constructors. + +# Examples + +- The [code constructs](./code_constructs) directory contains a collection of + examples dedicated to specific code constructs : + - [Polymorphic type](./code_constructs/POLYMORPHIC_TYPE.md) + - [Polymorphic variant](./code_constructs/POLYMORPHIC_VARIANT.md) + - [GADT](./code_constructs/GADT.md) + - [Inline record](./code_constructs/INLINE_RECORD.md) + +# Limitations + +## Polymorphic variant + +The analyzer does not keep track of polymorphic variants, as explained in the +[Polymorphic variant](./code_constructs/POLYMORPHIC_VARIANT.md) example. + +If you have a strong need/desire for this feature, please feel free to +[open an issue](https://github.com/LexiFi/dead_code_analyzer/issues/new) + +## Inline record + +The analyzer does not keep track of fields in inline records, as explained in +the [Inline record](./code_constructs/INLINE_RECORD.md) example + +If you have a strong need/desire for this feature, please feel free to +[open an issue](https://github.com/LexiFi/dead_code_analyzer/issues/new) diff --git a/docs/fields_and_constructors/code_constructs/GADT.md b/docs/fields_and_constructors/code_constructs/GADT.md new file mode 100644 index 00000000..925c5d18 --- /dev/null +++ b/docs/fields_and_constructors/code_constructs/GADT.md @@ -0,0 +1,187 @@ +The reference files for this example are in the +[gadt](../../../examples/docs/fields_and_constructors/code_constructs/gadt) directory. + +The reference takes place in `/tmp/docs/fields_and_constructors/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/fields_and_constructors/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C gadt build +``` + +The analysis command is : +``` +make -C gadt analyze +``` + +The compile + analyze command is : +``` +make -C gadt +``` + +## First run + +Code : +```OCaml +(* gadt_lib.mli *) +type _ gadt = + | Int : int -> int gadt + | Float : float -> float gadt + +val gadt_of_int : int -> int gadt + +val float_opt_of_gadt : 'a gadt -> float option +``` +```OCaml +(* gadt_lib.ml *) +type _ gadt = + | Int : int -> int gadt + | Float : float -> float gadt + +let gadt_of_int x = Int x + +let float_opt_of_gadt : type a . a gadt -> float option = function + | Float f -> Some f + | _ -> None +``` +```OCaml +(* gadt_bin.ml *) +let () = + let open Gadt_lib in + let x = 0 in + let gadt = gadt_of_int x in + let f = float_opt_of_gadt gadt in + assert (f = None) +``` + +Before looking at the analysis results, let's look at the code. + +The `Gadt_lib` defines one gadt `gadt` with 2 constructors : `Int` and `Float`. +The first one is used to construct values in `gadt_of_int`. The second one is +matched on in `float_opt_of_gadt`. +Following the classical variant constructor semantics, `Int` is used and `Float` is not. + +Compile and analyze : +``` +$ make -C gadt +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/gadt' +ocamlopt -w +37+69 -bin-annot gadt_lib.mli gadt_lib.ml gadt_bin.ml +dead_code_analyzer --nothing -T all . +Scanning files... + [DONE] + +.> UNUSED CONSTRUCTORS/RECORD FIELDS: +==================================== +/tmp/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli:4: gadt.Float + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/gadt' +``` + +As expected, the analyzer reports `gadt.Float` as unused. + +## Removing the unused constructor + +> [!TIP] +> Do not forget to remove `gadt.Float` from both the `.mli` **and** the `.ml`. +> Otherwise, the compiler will reject the code with a message like : +> ``` +> File "gadt_lib.ml", line 1: +> Error: The implementation gadt_lib.ml +> does not match the interface gadt_lib.mli: +> Type declarations do not match: +> type _ gadt = Int : int -> int gadt | Float : float -> float gadt +> is not included in +> type _ gadt = Int : int -> int gadt +> An extra constructor, Float, is provided in the first declaration. +> File "gadt_lib.mli", lines 2-3, characters 0-25: Expected declaration +> File "gadt_lib.ml", lines 2-4, characters 0-31: Actual declaration +> ``` + +After removing the unused constructor, the compiler will report errors at the +locations were it was de-structured. Fixing those errors is simply done by +removing the invalid pattern branches. + +Compile : +``` +$ make -C gadt build +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/gadt' +ocamlopt -w +37+69 -bin-annot gadt_lib.mli gadt_lib.ml gadt_bin.ml +File "gadt_lib.ml", line 8, characters 4-9: +8 | | Float f -> Some f + ^^^^^ +Error: This variant pattern is expected to have type a gadt + There is no constructor Float within type gadt +make: *** [Makefile:6: build] Error 2 +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/gadt' +``` +Fix and compile : +``` +$ make -C gadt build +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/gadt' +ocamlopt -w +37+69 -bin-annot gadt_lib.mli gadt_lib.ml gadt_bin.ml +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/gadt' +``` + +Compilation succeeds without error. Let's look at the code and analyze it. +```OCaml +(* gadt_lib.mli *) +type _ gadt = + | Int : int -> int gadt + +val gadt_of_int : int -> int gadt + +val float_opt_of_gadt : 'a gadt -> float option +``` +```OCaml +(* gadt_lib.ml *) +type _ gadt = + | Int : int -> int gadt + +let gadt_of_int x = Int x + +let float_opt_of_gadt : type a . a gadt -> float option = function + | _ -> None +``` +```OCaml +(* gadt_bin.ml *) +let () = + let open Gadt_lib in + let x = 0 in + let gadt = gadt_of_int x in + let f = float_opt_of_gadt gadt in + assert (f = None) +``` + +Analyze : +``` +$ make -C gadt analyze +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/gadt' +dead_code_analyzer --nothing -T all . +Scanning files... + [DONE] + +.> UNUSED CONSTRUCTORS/RECORD FIELDS: +==================================== + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/gadt' +``` + +Neither the compiler nor the analyzer reports any unused constructor. +Our work here is done. + +> [!NOTE] +> The clean-up focused on the reports and the warnings. Of course, in the +> context, the `float_opt_of_gadt` became meaningless because it always +> produces `None`. Thus a user could decide to simply remove it and fix the +> call-sites by either replacing the function call by `None` or any better +> suited improvement. diff --git a/docs/fields_and_constructors/code_constructs/INLINE_RECORD.md b/docs/fields_and_constructors/code_constructs/INLINE_RECORD.md new file mode 100644 index 00000000..9caf7f76 --- /dev/null +++ b/docs/fields_and_constructors/code_constructs/INLINE_RECORD.md @@ -0,0 +1,101 @@ +The reference files for this example are in the +[inline\_record](../../../examples/docs/fields_and_constructors/code_constructs/inline_record) directory. + +The reference takes place in `/tmp/docs/fields_and_constructors/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/fields_and_constructors/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C inline_record build +``` + +The analysis command is : +``` +make -C inline_record analyze +``` + +The compile + analyze command is : +``` +make -C inline_record +``` + +> [!IMPORTANT] +> **LIMITATION** +> +> The analyzer ignores fields in inline records. + +## First run + +Code : +```OCaml +(* inline_record_lib.mli *) +type ('a, 'b) t = + | Both of {left : 'a; right : 'b} + | Left of 'a + | Right of 'b + +val get_left_opt : ('a, 'b) t -> 'a option +``` +```OCaml +(* inline_record_lib.ml *) +type ('a, 'b) t = + | Both of {left : 'a; right : 'b} + | Left of 'a + | Right of 'b + +let get_left_opt = function + | Both {left; _} + | Left left -> Some left + | _ -> None +``` +```OCaml +(* inline_record_bin.ml *) +let () = + let open Inline_record_lib in + let both = Both {left = 1; right = "one"} in + match get_left_opt both with + | Some left -> assert (left = 1) + | _ -> assert false +``` + +Before looking at the analysis results, let's look at the code. + +The `Inline_record_lib` defines 1 variant type `t` with 3 constructors : `Both`, +`Left`, and `Right`. Only the first one is used, the 2 others are only matched +on in `get_left_opt`. Constructor `Both` has an inline record argument with 2 +fields : `left`, and `right`. Only the first one is used, the other one is only +written to. +Following the report semantics on constructors and fields, `Left`, `Right`, and +`right` should be reported unused. + +However, the analyzer does not report unused inline record fields. +The compiler also does not warn on unused inline record fields. + +Compile and analyze : +``` +$ make -C inline_record +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/inline_record' +ocamlopt -w +37+69 -bin-annot inline_record_lib.mli inline_record_lib.ml inline_record_bin.ml +dead_code_analyzer --nothing -T all . +Scanning files... + [DONE] + +.> UNUSED CONSTRUCTORS/RECORD FIELDS: +==================================== +/tmp/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:4: t.Left +/tmp/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli:5: t.Right + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/inline_record' +``` + +As expected, `t.Left`, and `t.Right` are reported unused by the analyzer. +As explained, the analyzer does not report inline record fields so `right` is +not reported. +Fixing the unused constructors is the same as in the +[Polymorphic type](./POLYMORPHIC_TYPE.md) example. Our work here is done. diff --git a/docs/fields_and_constructors/code_constructs/POLYMORPHIC_TYPE.md b/docs/fields_and_constructors/code_constructs/POLYMORPHIC_TYPE.md new file mode 100644 index 00000000..e35ee5c0 --- /dev/null +++ b/docs/fields_and_constructors/code_constructs/POLYMORPHIC_TYPE.md @@ -0,0 +1,291 @@ +The reference files for this example are in the +[polymorphic\_type](../../../examples/docs/fields_and_constructors/code_constructs/polymorphic_type) directory. + +The reference takes place in `/tmp/docs/fields_and_constructors/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/fields_and_constructors/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C polymorphic_type build +``` + +The analysis command is : +``` +make -C polymorphic_type analyze +``` + +The compile + analyze command is : +``` +make -C polymorphic_type +``` + +## First run + +Code: +```OCaml +(* polymorphic_type_lib.mli *) +type ('a, 'b) either = Left of 'a | Right of 'b +type ('a, 'b) both = {left : 'a; right : 'b} +``` +```OCaml +(* polymorphic_type_lib.ml *) +type ('a, 'b) either = Left of 'a | Right of 'b +type ('a, 'b) both = {left : 'a; right : 'b} +``` +```OCaml +(* polymorphic_type_bin.ml *) +let () = + let open Polymorphic_type_lib in + let left = Left 1 in + let both = {left = 1; right = "one"} in + match left with + | Right x -> assert (x = both.right) + | _ -> () +``` + +Before looking at the analysis results, let's look at the code. + +The `Polymorphic_type_lib` exports 1 variant type `either` with 2 constructors +`Left` and `Right, and 1 record `both` with 2 fields `left` and `right. + +The constructor `Left` is used to build the value stored in `left`. +The constructor `Right` is never built but matched upon. Thus, `Left` is used +while `Right` is not. +Both the fields `both.left` and `both.right` are written bu only the field +`both.right` is read. This leaves `both.left` as unused. + +Compiler and analyze : +``` +$ make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +ocamlopt -w +37+69 -bin-annot polymorphic_type_lib.mli polymorphic_type_lib.ml polymorphic_type_bin.ml +dead_code_analyzer --nothing -T all . +Scanning files... + [DONE] + +.> UNUSED CONSTRUCTORS/RECORD FIELDS: +==================================== +/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:2: either.Right +/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.left + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +``` + +As expected, constructor `either.Right` and field `both.left` are reported by +the analyzer. + +## Removing the unused constructor and field + +> [!TIP] +> Do not forget to remove `either.Right` from both the `.mli` **and** the `.ml`. +> Otherwise, the compiler will reject the code with a message like : +> ``` +> File "polymorphic_type_lib.ml", line 1: +> Error: The implementation polymorphic_type_lib.ml +> does not match the interface polymorphic_type_lib.mli: +> Type declarations do not match: +> type ('a, 'b) either = Left of 'a | Right of 'b +> is not included in +> type ('a, 'b) either = Left of 'a +> An extra constructor, Right, is provided in the first declaration. +> File "polymorphic_type_lib.mli", line 2, characters 0-33: +> Expected declaration +> File "polymorphic_type_lib.ml", line 2, characters 0-47: +> Actual declaration +> ``` + +> [!TIP] +> Do not forget to remove `both.left` from both the `.mli` **and** the `.ml`. +> Otherwise, the compiler will reject the code with a message like : +> ``` +> Error: The implementation polymorphic_type_lib.ml +> does not match the interface polymorphic_type_lib.mli: +> Type declarations do not match: +> type ('a, 'b) both = { left : 'a; right : 'b; } +> is not included in +> type ('a, 'b) both = { right : 'b; } +> An extra field, left, is provided in the first declaration. +> File "polymorphic_type_lib.mli", line 3, characters 0-33: +> Expected declaration +> File "polymorphic_type_lib.ml", line 3, characters 0-44: +> Actual declaration +> ``` + +After removing the unused constructor and field, the compiler will report errors +at the locations were they are de-structured and written respectively. +Fixing those errors is simply done by removing the invalid pattern branches and +writes. + +Compile : +``` +$ make -C polymorphic_type build +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +ocamlopt -w +37+69 -bin-annot polymorphic_type_lib.mli polymorphic_type_lib.ml polymorphic_type_bin.ml +File "polymorphic_type_bin.ml", line 5, characters 14-18: +5 | let both = {left = 1; right = "one"} in + ^^^^ +Error: Unbound record field left +make: *** [Makefile:6: build] Error 2 +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +``` +Fix and compile : +``` +$ make -C polymorphic_type build +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +ocamlopt -w +37+69 -bin-annot polymorphic_type_lib.mli polymorphic_type_lib.ml polymorphic_type_bin.ml +File "polymorphic_type_bin.ml", line 7, characters 4-9: +7 | | Right x -> assert (x = both.right) + ^^^^^ +Error: This variant pattern is expected to have type + (int, 'a) Polymorphic_type_lib.either + There is no constructor Right within type Polymorphic_type_lib.either +make: *** [Makefile:6: build] Error 2 +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +``` +Fix and compile : +``` +$ make -C polymorphic_type build +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +ocamlopt -w +37+69 -bin-annot polymorphic_type_lib.mli polymorphic_type_lib.ml polymorphic_type_bin.ml +File "polymorphic_type_bin.ml", line 5, characters 6-10: +5 | let both = {right = "one"} in + ^^^^ +Warning 26 [unused-var]: unused variable both. +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +``` + +Compilation succeeds without error. There is a warning on an unused variable. +This topic is discussed in the +[Exported values](../exported_values/EXPORTED_VALUES.md) section. + +Now we have removed the unused constructor and field, and fixed all the +compilation errors. Let's look at the code and analyze it. + +Code : +```OCaml +(* polymorphic_type_lib.mli *) +type ('a, 'b) either = Left of 'a +type ('a, 'b) both = {right : 'b} +``` +```OCaml +(* polymorphic_type_lib.ml *) +type ('a, 'b) either = Left of 'a +type ('a, 'b) both = {right : 'b} +``` +```OCaml +(* polymorphic_type_bin.ml *) +let () = + let open Polymorphic_type_lib in + let left = Left 1 in + let both = {right = "one"} in + match left with + | _ -> () +``` + +Analyze : +``` +$ make -C polymorphic_type analyze +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +dead_code_analyzer --nothing -T all . +Scanning files... + [DONE] + +.> UNUSED CONSTRUCTORS/RECORD FIELDS: +==================================== +/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli:3: both.right + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +``` + +The analyzer reports `both.right` as unused. This is coherent with the compiler +warning above saying that variable `both` is unused because it is the only +value of type `both`. + +Let's fix both the compiler warning and the analyzer's report. + +## Removing the unused value and field + +Because `right` is the only field in `both`, removing the field necessitates +either removing the type or making the type abstract. We will remove the type +from the `.mli` + +> [!NOTE] +> An empty record type is a syntax error : +> ``` +> File "polymorphic_type_lib.mli", line 3, characters 23-24: +> 3 | type ('a, 'b) both = { } +> ^ +> Error: Syntax error +> ``` + +Code : +```OCaml +(* polymorphic_type_lib.mli *) +type ('a, 'b) either = Left of 'a +``` +```OCaml +(* polymorphic_type_lib.ml *) +type ('a, 'b) either = Left of 'a +type ('a, 'b) both = {right : 'b} +``` +```OCaml +(* polymorphic_type_bin.ml *) +let () = + let open Polymorphic_type_lib in + let left = Left 1 in + match left with + | _ -> () +``` + +Compile and analyze : +``` +$ make -C polymorphic_type +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +ocamlopt -w +37+69 -bin-annot polymorphic_type_lib.mli polymorphic_type_lib.ml polymorphic_type_bin.ml +File "polymorphic_type_lib.ml", line 3, characters 22-32: +3 | type ('a, 'b) both = {right : 'b} + ^^^^^^^^^^ +Warning 69 [unused-field]: unused record field right. +dead_code_analyzer --nothing -T all . +Scanning files... + [DONE] + +.> UNUSED CONSTRUCTORS/RECORD FIELDS: +==================================== + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_type' +``` + +The compiler warns us that the unuexported field `right` is unused. +The analyzer does not report anything. + +Once again, the fix is to either make the type abstract or removing it from +the `.ml`. We can do the latter and neither the compiler nor the analyzer will +report any unused constructor or field. Our work here is done. + +> [!TIP] +> If we activated the compiler warning 34 `unused-type-declaration` +> (by passing the argument `-w +34`), and made `both` abstract in the `.ml`, +> then the compiler would have reported. +> ``` +> File "polymorphic_type_lib.ml", line 3, characters 0-18: +> 3 | type ('a, 'b) both +> ^^^^^^^^^^^^^^^^^^ +> Warning 34 [unused-type-declaration]: unused type both. +> ``` +> The analyzer does not have an unused exported type feature yet so making the +> type abstract in the `.mli` would not have lead to any unused exported type +> report. diff --git a/docs/fields_and_constructors/code_constructs/POLYMORPHIC_VARIANT.md b/docs/fields_and_constructors/code_constructs/POLYMORPHIC_VARIANT.md new file mode 100644 index 00000000..97948b67 --- /dev/null +++ b/docs/fields_and_constructors/code_constructs/POLYMORPHIC_VARIANT.md @@ -0,0 +1,96 @@ +The reference files for this example are in the +[polymorphic\_variant](../../../examples/docs/fields_and_constructors/code_constructs/polymorphic_variant) directory. + +The reference takes place in `/tmp/docs/fields_and_constructors/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/fields_and_constructors/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C polymorphic_variant build +``` + +The analysis command is : +``` +make -C polymorphic_variant analyze +``` + +The compile + analyze command is : +``` +make -C polymorphic_variant +``` + +> [!IMPORTANT] +> **LIMITATION** +> +> The analyzer ignores polymoprhic variant constructors. + +## First run + +Code : +```OCaml +(* polymorphic_variant_lib.mli *) +type poly = [`Int of int | `Float of float] + +val poly_of_int : int -> [> `Int of int] + +val float_opt_of_poly : poly -> float option +``` +```OCaml +(* polymorphic_variant_lib.ml *) +type poly = [`Int of int | `Float of float] + +let poly_of_int x = `Int x + +let float_opt_of_poly = function + | `Float f -> Some f + | _ -> None +``` +```OCaml +(* polymorphic_variant_bin.ml *) +let () = + let open Polymorphic_variant_lib in + let x = 0 in + let poly = poly_of_int x in + let f = float_opt_of_poly poly in + assert (f = None) +``` + +Before looking at the analysis results, let's look at the code. + +The `Polymorphic_variant_lib` uses 2 polymorphic variant constructors : `` `Int `` +and `` `Float ``. The first one is built in `poly_of_int`. The second one is +matched on in `float_opt_of_poly`. +Following the classical variant constructor semantics, `` `Int `` is used and +`` `Float `` is not. + + +One could expect the analyzer to report `` `Float `` as unused. However, the +analyzer does not report unused polymorphic variant constructors. +Unlike regular variant constructors, polymorphic variant constructors do not +belong to any specific type. That flexibility is their purpose. Currently, +reporting a constructor requires that it is associated with a single type. + +The compiler also does not warn on unused polymorphic variant constructors. + +Compile and analyze : +``` +$ make -C polymorphic_variant +make: Entering directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_variant' +ocamlopt -w +37+69 -bin-annot polymorphic_variant_lib.mli polymorphic_variant_lib.ml polymorphic_variant_bin.ml +dead_code_analyzer --nothing -T all . +Scanning files... + [DONE] + +.> UNUSED CONSTRUCTORS/RECORD FIELDS: +==================================== + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/fields_and_constructors/code_constructs/polymorphic_variant' +``` + +As explained, nothing is reported. Our work here is done. diff --git a/examples/docs/Makefile b/examples/docs/Makefile index 3c8cfe69..9fe4dca2 100644 --- a/examples/docs/Makefile +++ b/examples/docs/Makefile @@ -5,9 +5,11 @@ all: build build: make -C exported_values make -C methods + make -C fields_and_constructors clean: rm -f *~ *.cm* *.o *.obj make -C exported_values clean make -C methods clean + make -C fields_and_constructors clean diff --git a/examples/docs/fields_and_constructors/Makefile b/examples/docs/fields_and_constructors/Makefile new file mode 100644 index 00000000..ed0a10f4 --- /dev/null +++ b/examples/docs/fields_and_constructors/Makefile @@ -0,0 +1,10 @@ +.PHONY: clean build + +all: build + +build: + make -C code_constructs + +clean: + rm -f *~ *.cm* *.o *.obj + make -C code_constructs clean diff --git a/examples/docs/fields_and_constructors/code_constructs/Makefile b/examples/docs/fields_and_constructors/code_constructs/Makefile new file mode 100644 index 00000000..0c0acc36 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/Makefile @@ -0,0 +1,16 @@ +.PHONY: clean build + +all: build + +build: + make -C polymorphic_type build + make -C polymorphic_variant build + make -C gadt build + make -C inline_record build + +clean: + rm -f *~ *.cm* *.o *.obj + make -C polymorphic_type clean + make -C polymorphic_variant clean + make -C gadt clean + make -C inline_record clean diff --git a/examples/docs/fields_and_constructors/code_constructs/gadt/Makefile b/examples/docs/fields_and_constructors/code_constructs/gadt/Makefile new file mode 100644 index 00000000..d45f1c2d --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/gadt/Makefile @@ -0,0 +1,12 @@ +SRC:=gadt_lib.mli gadt_lib.ml gadt_bin.ml + +all: build analyze + +build: + ocamlopt -w +37+69 -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -T all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/fields_and_constructors/code_constructs/gadt/gadt_bin.ml b/examples/docs/fields_and_constructors/code_constructs/gadt/gadt_bin.ml new file mode 100644 index 00000000..ae5dc722 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/gadt/gadt_bin.ml @@ -0,0 +1,7 @@ +(* gadt_bin.ml *) +let () = + let open Gadt_lib in + let x = 0 in + let gadt = gadt_of_int x in + let f = float_opt_of_gadt gadt in + assert (f = None) diff --git a/examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.ml b/examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.ml new file mode 100644 index 00000000..061b4167 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.ml @@ -0,0 +1,10 @@ +(* gadt_lib.ml *) +type _ gadt = + | Int : int -> int gadt + | Float : float -> float gadt + +let gadt_of_int x = Int x + +let float_opt_of_gadt : type a . a gadt -> float option = function + | Float f -> Some f + | _ -> None diff --git a/examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli b/examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli new file mode 100644 index 00000000..51275888 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/gadt/gadt_lib.mli @@ -0,0 +1,8 @@ +(* gadt_lib.mli *) +type _ gadt = + | Int : int -> int gadt + | Float : float -> float gadt + +val gadt_of_int : int -> int gadt + +val float_opt_of_gadt : 'a gadt -> float option diff --git a/examples/docs/fields_and_constructors/code_constructs/inline_record/Makefile b/examples/docs/fields_and_constructors/code_constructs/inline_record/Makefile new file mode 100644 index 00000000..c3c14a63 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/inline_record/Makefile @@ -0,0 +1,12 @@ +SRC:=inline_record_lib.mli inline_record_lib.ml inline_record_bin.ml + +all: build analyze + +build: + ocamlopt -w +37+69 -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -T all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_bin.ml b/examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_bin.ml new file mode 100644 index 00000000..8482d674 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_bin.ml @@ -0,0 +1,7 @@ +(* inline_record_bin.ml *) +let () = + let open Inline_record_lib in + let both = Both {left = 1; right = "one"} in + match get_left_opt both with + | Some left -> assert (left = 1) + | _ -> assert false diff --git a/examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.ml b/examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.ml new file mode 100644 index 00000000..0ff1fa94 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.ml @@ -0,0 +1,10 @@ +(* inline_record_lib.ml *) +type ('a, 'b) t = + | Both of {left : 'a; right : 'b} + | Left of 'a + | Right of 'b + +let get_left_opt = function + | Both {left; _} + | Left left -> Some left + | _ -> None diff --git a/examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli b/examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli new file mode 100644 index 00000000..c6aaf671 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/inline_record/inline_record_lib.mli @@ -0,0 +1,7 @@ +(* inline_record_lib.mli *) +type ('a, 'b) t = + | Both of {left : 'a; right : 'b} + | Left of 'a + | Right of 'b + +val get_left_opt : ('a, 'b) t -> 'a option diff --git a/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/Makefile b/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/Makefile new file mode 100644 index 00000000..c7d445b0 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/Makefile @@ -0,0 +1,12 @@ +SRC:=polymorphic_type_lib.mli polymorphic_type_lib.ml polymorphic_type_bin.ml + +all: build analyze + +build: + ocamlopt -w +37+69 -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -T all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_bin.ml b/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_bin.ml new file mode 100644 index 00000000..04a27d2c --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_bin.ml @@ -0,0 +1,8 @@ +(* polymorphic_type_bin.ml *) +let () = + let open Polymorphic_type_lib in + let left = Left 1 in + let both = {left = 1; right = "one"} in + match left with + | Right x -> assert (x = both.right) + | _ -> () diff --git a/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.ml b/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.ml new file mode 100644 index 00000000..3fce24e8 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.ml @@ -0,0 +1,3 @@ +(* polymorphic_type_lib.ml *) +type ('a, 'b) either = Left of 'a | Right of 'b +type ('a, 'b) both = {left : 'a; right : 'b} diff --git a/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli b/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli new file mode 100644 index 00000000..199cbb8c --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/polymorphic_type/polymorphic_type_lib.mli @@ -0,0 +1,3 @@ +(* polymorphic_type_lib.mli *) +type ('a, 'b) either = Left of 'a | Right of 'b +type ('a, 'b) both = {left : 'a; right : 'b} diff --git a/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/Makefile b/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/Makefile new file mode 100644 index 00000000..948fe206 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/Makefile @@ -0,0 +1,12 @@ +SRC:=polymorphic_variant_lib.mli polymorphic_variant_lib.ml polymorphic_variant_bin.ml + +all: build analyze + +build: + ocamlopt -w +37+69 -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -T all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_bin.ml b/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_bin.ml new file mode 100644 index 00000000..d0a1265e --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_bin.ml @@ -0,0 +1,7 @@ +(* polymorphic_variant_bin.ml *) +let () = + let open Polymorphic_variant_lib in + let x = 0 in + let poly = poly_of_int x in + let f = float_opt_of_poly poly in + assert (f = None) diff --git a/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.ml b/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.ml new file mode 100644 index 00000000..5159d1fd --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.ml @@ -0,0 +1,8 @@ +(* polymorphic_variant_lib.ml *) +type poly = [`Int of int | `Float of float] + +let poly_of_int x = `Int x + +let float_opt_of_poly = function + | `Float f -> Some f + | _ -> None diff --git a/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli b/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli new file mode 100644 index 00000000..6a4159b6 --- /dev/null +++ b/examples/docs/fields_and_constructors/code_constructs/polymorphic_variant/polymorphic_variant_lib.mli @@ -0,0 +1,6 @@ +(* polymorphic_variant_lib.mli *) +type poly = [`Int of int | `Float of float] + +val poly_of_int : int -> [> `Int of int] + +val float_opt_of_poly : poly -> float option