From 2cd032628e9d7fee244cd56003dbb53444aade92 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Tue, 17 Mar 2026 16:16:52 +0100 Subject: [PATCH 01/13] [docs][methods][1/n] initial documentation Provide defintions, related compiler warnings, and basic usage information about unused methods. --- docs/USER_DOC.md | 1 + docs/methods/METHODS.md | 132 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 docs/methods/METHODS.md diff --git a/docs/USER_DOC.md b/docs/USER_DOC.md index 0fff3c01..f1d813ff 100644 --- a/docs/USER_DOC.md +++ b/docs/USER_DOC.md @@ -54,6 +54,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. ## Footnotes diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md new file mode 100644 index 00000000..95be4558 --- /dev/null +++ b/docs/methods/METHODS.md @@ -0,0 +1,132 @@ +# Table of contents + ++ [Methods](#methods) + + [Definitions](#definitions) + + [Compiler warnings](#compiler-warnings) + + [Warning 26: unused-ancestor](#warning-36-unused-ancestor) + + [Usage](#usage) + +# Methods + +## Definitions + +A **method** is declared using the `method` keyword in the definition of a class +or an immediate object, or as a field of an object type. + +An **instance variable** is declared using the `val` keyword in the definition +of a class or an immediate object. It does not appear in object types. + +A **public** method is not a private method. +A **private** method is one declared with the `private` keyword. + +An **exported** method is one that exists in its compilation unit's signature + +A **use** is either : +- An explicit reference. + E.g. + ```OCaml + let o = object method answer = 42 end + let () = print_int o#answer + ``` + The method `answer` is explicitly referenced in `o#answer`. +- A requirement for that method to exist. + E.g. + ```OCaml + let print_answer param = print_int param#answer + let o = object method answer = 42 end + let () = print_answer o + ``` + The type of `print_answer` is `< answer : int; .. > -> unit`, meaning that its + arguments are required to at least provide a method named `answer`. Therefore, + `o#answer` is used by requirement in `print_answer o`. If `o` did not provide + method `answer`, then the compilation would fail with an error like : + ``` + File "requirement.ml", line 4, characters 22-23: + 4 | let () = print_answer o + ^ + Error: This expression has type < > but an expression was expected of type + < answer : int; .. > + The first object type has no method answer + ``` + +## Compiler warnings + +The analyzer reports unused exported public methods. The compiler does not +report unused methods (private or public, exported or not, from a class, an +immediate, or an object type), not instance vraiables. Thus, the 2 tools do not +complement each other. + +> [!WARNING] +> Only a portion of the unused object-related code can be reported using the +> compiler and the analyzer : unused exported public methods. Unused private or +> unexported methods, as well as unused instance variables will remain +> undetected. + +> [!IMPORTANT] +> Exported values of object or class types belong to the +> [Exported values](../exported_values/EXPORTED_VALUES.md) section. + +Although the compiler does not report unused methods or instance variables, it +still has a few object-related warnings, of which one is related to unused code +constructs : warning 36. + +### Warning 36: unused-ancestor + +This warning is disabled by default. +I can be enabled by passing the `-w +36` to the compiler. + +Description: +``` +36 [unused-ancestor] Unused ancestor variable. (since 4.00) +``` + +Example: +```OCaml +(* warning36.ml *) +class c1 = object end +class c2 = object + inherit c1 as super +end +``` +``` +$ ocamlopt -w +36 warning36.ml +File "warning36.ml", line 4, characters 3-22: +4 | inherit c1 as super + ^^^^^^^^^^^^^^^^^^^ +Warning 36 [unused-ancestor]: unused ancestor variable super. +``` + +## Usage + +Unused exported public methods are reported by default. +Their reports can be deactivated by using the `--nothing` or `-M nothing` +command line arguments. +They can be reactivated by using the `--all` or `-M 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 METHODS: +================= +filepath:line: source#method + +Nothing else to report in this section +-------------------------------------------------------------------------------- +``` +The report line format is `filepath:line: value` with `filepath` the absolute +path to the file (`.mli` if available, `.ml` otherwise) where `source` is +declared, `line` the line index in `filepath` at which `source` is declared, +`source` the path of the object/class within its compilation unit (e.g. `M.c`) +which declares `method`, and `method` the unused method. +There can be any number of such lines. + +The expected resolution for an unused exported public method is to remove it +from the `.mli` if there is one and the `.ml`. + +> [!IMPORTANT] +> Removing unused methods or values from the codebase may trigger the detection +> of new unused methods, or remove some for values of object types. +> Consequently, it is expected that a user might need to compile and analyze +> their code multiple times when cleaning up their codebase. From 7261c0d8a45635f2aeb672741839f886687d2495 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Thu, 19 Mar 2026 18:30:53 +0100 Subject: [PATCH 02/13] [docs][methods][2/n] add immediate object example This demonstrates the use by explicit references and use by requirements. It also shows that unused methods can coexist with unused values. --- check/classic/classic.exp | 5 + check/classic/classic.ref | 11 +- check/internal/internal.exp | 5 + check/internal/internal.ref | 11 +- check/threshold-1/threshold-1.exp | 11 + check/threshold-1/threshold-1.ref | 17 +- check/threshold-3-0.5/threshold-3-0.5.exp | 13 + check/threshold-3-0.5/threshold-3-0.5.ref | 19 +- docs/methods/METHODS.md | 13 + .../code_constructs/IMMEDIATE_OBJECT.md | 232 ++++++++++++++++++ examples/docs/Makefile | 2 + examples/docs/methods/Makefile | 11 + .../docs/methods/code_constructs/Makefile | 11 + .../code_constructs/immediate_object/Makefile | 12 + .../immediate_object/immediate_object_bin.ml | 15 ++ .../immediate_object/immediate_object_lib.ml | 15 ++ .../immediate_object/immediate_object_lib.mli | 7 + 17 files changed, 398 insertions(+), 12 deletions(-) create mode 100644 docs/methods/code_constructs/IMMEDIATE_OBJECT.md create mode 100644 examples/docs/methods/Makefile create mode 100644 examples/docs/methods/code_constructs/Makefile create mode 100644 examples/docs/methods/code_constructs/immediate_object/Makefile create mode 100644 examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml create mode 100644 examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.ml create mode 100644 examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli diff --git a/check/classic/classic.exp b/check/classic/classic.exp index efc07a67..0a34fb69 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -25,6 +25,8 @@ ./examples/docs/exported_values/hello_world/hello_world_with_intf.mli:3: goodbye ./examples/docs/exported_values/hello_world/hello_world_with_intf.mli:4: world +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:3: internally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:38: internally_used_f @@ -146,6 +148,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused diff --git a/check/classic/classic.ref b/check/classic/classic.ref index ba7997bf..76205e73 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -30,6 +30,8 @@ ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:40: new_method: Should not be detected ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:41: public_method_label: Should not be detected ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:3: internally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:38: internally_used_f @@ -151,6 +153,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -623,7 +628,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 536 -Success: 531 +Total: 539 +Success: 534 Failed: 5 -Ratio: 99.0671641791% +Ratio: 99.0723562152% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index 0b9dfad1..fc687bfc 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -15,6 +15,8 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -101,6 +103,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused diff --git a/check/internal/internal.ref b/check/internal/internal.ref index 9c869823..1232a32b 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -20,6 +20,8 @@ ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:40: new_method: Should not be detected ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:41: public_method_label: Should not be detected ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -106,6 +108,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -578,7 +583,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 494 -Success: 489 +Total: 497 +Success: 492 Failed: 5 -Ratio: 98.987854251% +Ratio: 98.9939637827% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index 7f8b44f8..6449ed82 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -15,6 +15,8 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -133,6 +135,8 @@ ./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/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -338,6 +342,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -398,6 +405,10 @@ Nothing else to report in this section .>-> ALMOST UNUSED METHODS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_used diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 0f3a3f17..bd16858a 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -20,6 +20,8 @@ ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:40: new_method: Should not be detected ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:41: public_method_label: Should not be detected ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -138,6 +140,8 @@ ./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/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -343,6 +347,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -403,6 +410,10 @@ Nothing else to report in this section .>-> ALMOST UNUSED METHODS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_used @@ -955,7 +966,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 825 -Success: 820 +Total: 832 +Success: 827 Failed: 5 -Ratio: 99.3939393939% +Ratio: 99.3990384615% 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 13143ef3..0a23073f 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -15,6 +15,8 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -133,6 +135,8 @@ ./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/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -445,6 +449,8 @@ .>-> ALMOST UNUSED EXPORTED VALUES: Called 3 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack + ./examples/using_dune/unwrapped_lib/values/values_no_intf.ml:19: aliased_fun ./examples/using_dune/wrapped_lib/values/values_no_intf.ml:19: aliased_fun @@ -466,6 +472,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -526,6 +535,10 @@ Nothing else to report in this section .>-> ALMOST UNUSED METHODS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_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 518f3410..2bb604cd 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -20,6 +20,8 @@ ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:40: new_method: Should not be detected ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:41: public_method_label: Should not be detected ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -138,6 +140,8 @@ ./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/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -450,6 +454,8 @@ .>-> ALMOST UNUSED EXPORTED VALUES: Called 3 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack + ./examples/using_dune/unwrapped_lib/values/values_no_intf.ml:19: aliased_fun ./examples/using_dune/wrapped_lib/values/values_no_intf.ml:19: aliased_fun @@ -471,6 +477,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -531,6 +540,10 @@ Nothing else to report in this section .>-> ALMOST UNUSED METHODS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_used @@ -1344,7 +1357,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1137 -Success: 1132 +Total: 1145 +Success: 1140 Failed: 5 -Ratio: 99.5602462621% +Ratio: 99.5633187773% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index 95be4558..34b459da 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -5,6 +5,7 @@ + [Compiler warnings](#compiler-warnings) + [Warning 26: unused-ancestor](#warning-36-unused-ancestor) + [Usage](#usage) ++ [Examples](#examples) # Methods @@ -130,3 +131,15 @@ from the `.mli` if there is one and the `.ml`. > of new unused methods, or remove some for values of object types. > Consequently, it is expected that a user might need to compile and analyze > their code multiple times when cleaning up their codebase. + +# Examples + +- The [code constructs](./code_constructs) directory contains a collection of + examples dedicated to specific code constructs : + - [Immediate object](./code_constructs/IMMEDIATE_OBJECT.md) + +[TODO]: # ( + - [Class](./code_constructs/CLASS.md) + - [Class type](./code_constructs/CLASS_TYPE.md) + - [Inheritance](./code_constructs/INHERITANCE.md) + ) diff --git a/docs/methods/code_constructs/IMMEDIATE_OBJECT.md b/docs/methods/code_constructs/IMMEDIATE_OBJECT.md new file mode 100644 index 00000000..b7185e0c --- /dev/null +++ b/docs/methods/code_constructs/IMMEDIATE_OBJECT.md @@ -0,0 +1,232 @@ +The reference files for this example are in the +[immediate\_object](../../../examples/docs/methods/code_constructs/immediate_object) directory. + +The reference takes place in `/tmp/docs/methods/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/methods/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C immediate_object build +``` + +The analysis command is : +``` +make -C immediate_object analyze +``` + +The compile + analyze command is : +``` +make -C immediate_object +``` + +## First run + +Code: +```OCaml +(* immediate_object_lib.mli *) +val int_stack : + < push : int -> unit + ; pop : unit + ; peek : int option + ; reset : unit + > +``` +```OCaml +(* immediate_object_lib.ml *) +let int_stack = + object + val mutable l = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end +``` +```OCaml +(* immediate_object_bin.ml *) +let unused_obj = object method unused_method = () end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let open Immediate_object_lib in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done +``` + +Before looking at the analysis results, let's look at the code. + +The `Imm_obj_lib` declares and exports 1 object : `int_stack`, which is used by +`Imm_obj_bin`. `Imm_obj_bin` declares and exports 1 object : `unused_obj`, which +is unused. All of the methods are public, so they are tracked by the analyzer. + +2 methods are explicitly referenced : `int_stack#peek`, and `int_stack#pop`. +1 method is used by requirement : `int_stack#push`, required by the call +`push_n_times n int_stack`. + +This leaves only 2 unused methods : `int_stack#reset` and +`unused_obj#unused_method`. + +Compile and analyze: +``` +$ make -C immediate_object +make: Entering directory '/tmp/docs/methods/code_constructs/immediate_object' +ocamlopt -bin-annot immediate_object_lib.mli immediate_object_lib.ml immediate_object_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= +/tmp/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method +/tmp/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_constructs/immediate_object' +``` + +As expected, 2 methods are reported unused : `unused_obj#unused_method`, and +`int_stack#reset`. These can be removed from the object definitions at the +reported locations. + +> [!IMPORTANT] +> The reported locations are those of the objects to which the methods belong. + +In addition to these unused methods, there is the unused exported value +`unused_obj` which is not reported because we disabled the analysis of unused +values when passing `--nothing` to the analyzer. Let's update the Makefile and +pass `-E all` to the analyzer to enable that analysis. + +``` +SRC:=immediate_object_lib.mli immediate_object_lib.ml immediate_object_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -E all -M all . + +clean: + rm -f *.cm* *.o a.out +``` + +## Removing the unused methods + +> [!TIP] +> Do not forget to remove `int_stack#reset` from both the `.mli` **and** the `.ml`. +> Otherwise, the compiler will reject the code with a message like : +> ``` +> File "immediate_object_lib.ml", line 1: +> Error: The implementation immediate_object_lib.ml +> does not match the interface immediate_object_lib.mli: +> Values do not match: +> val int_stack : +> < peek : '_weak1 option; pop : unit; push : '_weak1 -> unit; +> reset : unit > +> is not included in +> val int_stack : +> < peek : int option; pop : unit; push : int -> unit > +> The type +> < peek : '_weak1 option; pop : unit; push : '_weak1 -> unit; +> reset : unit > +> is not compatible with the type +> < peek : int option; pop : unit; push : int -> unit > +> The second object type has no method reset +> File "immediate_object_lib.mli", lines 2-6, characters 0-3: +> Expected declaration +> File "immediate_object_lib.ml", line 2, characters 4-13: +> Actual declaration +> ``` + +Code: +```OCaml +(* immediate_object_lib.mli *) +val int_stack : + < push : int -> unit + ; pop : unit + ; peek : int option + > +``` +```OCaml +(* immediate_object_lib.ml *) +let int_stack = + object + val mutable l = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + end +``` +```OCaml +(* immediate_object_bin.ml *) +let unused_obj = object end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let open Immediate_object_lib in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done +``` + +Compile and analyze: +``` +$ make -C immediate_object +make: Entering directory '/tmp/docs/methods/code_constructs/immediate_object' +ocamlopt -bin-annot immediate_object_lib.mli immediate_object_lib.ml immediate_object_bin.ml +dead_code_analyzer --nothing -E all -M all . +Scanning files... + [DONE] + +.> UNUSED EXPORTED VALUES: +========================= +/tmp/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +.> UNUSED METHODS: +================= + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_constructs/immediate_object' +``` + +There is no more unused method. The unused exported value can be removed as +explained in the [Exported values](../../exported_values/EXPORTED_VALUES.md) documentation. +Our work here is done diff --git a/examples/docs/Makefile b/examples/docs/Makefile index ae38a077..3c8cfe69 100644 --- a/examples/docs/Makefile +++ b/examples/docs/Makefile @@ -4,8 +4,10 @@ all: build build: make -C exported_values + make -C methods clean: rm -f *~ *.cm* *.o *.obj make -C exported_values clean + make -C methods clean diff --git a/examples/docs/methods/Makefile b/examples/docs/methods/Makefile new file mode 100644 index 00000000..838d97ec --- /dev/null +++ b/examples/docs/methods/Makefile @@ -0,0 +1,11 @@ +.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/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile new file mode 100644 index 00000000..21d3c404 --- /dev/null +++ b/examples/docs/methods/code_constructs/Makefile @@ -0,0 +1,11 @@ +.PHONY: clean build + +all: build + +build: + make -C immediate_object build + +clean: + rm -f *~ *.cm* *.o *.obj + make -C immediate_object clean + diff --git a/examples/docs/methods/code_constructs/immediate_object/Makefile b/examples/docs/methods/code_constructs/immediate_object/Makefile new file mode 100644 index 00000000..fdb7811a --- /dev/null +++ b/examples/docs/methods/code_constructs/immediate_object/Makefile @@ -0,0 +1,12 @@ +SRC:=immediate_object_lib.mli immediate_object_lib.ml immediate_object_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml b/examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml new file mode 100644 index 00000000..b6b71d3f --- /dev/null +++ b/examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml @@ -0,0 +1,15 @@ +(* immediate_object_bin.ml *) +let unused_obj = object method unused_method = () end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let open Immediate_object_lib in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done diff --git a/examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.ml b/examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.ml new file mode 100644 index 00000000..46646150 --- /dev/null +++ b/examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.ml @@ -0,0 +1,15 @@ +(* immediate_object_lib.ml *) +let int_stack = + object + val mutable l = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end diff --git a/examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli b/examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli new file mode 100644 index 00000000..9220599f --- /dev/null +++ b/examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli @@ -0,0 +1,7 @@ +(* immediate_object_lib.mli *) +val int_stack : + < push : int -> unit + ; pop : unit + ; peek : int option + ; reset : unit + > From b747780b5539235890facf33aa8fda09c991fda5 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Fri, 20 Mar 2026 16:18:16 +0100 Subject: [PATCH 03/13] [docs][methods][3/n] add class example This demonstrates the use by explict references and use by requirements. --- check/classic/classic.exp | 3 + check/classic/classic.ref | 9 +- check/internal/internal.exp | 3 + check/internal/internal.ref | 9 +- check/threshold-1/threshold-1.exp | 9 + check/threshold-1/threshold-1.ref | 15 +- check/threshold-3-0.5/threshold-3-0.5.exp | 9 + check/threshold-3-0.5/threshold-3-0.5.ref | 15 +- docs/methods/METHODS.md | 2 +- docs/methods/code_constructs/CLASS.md | 218 ++++++++++++++++++ .../docs/methods/code_constructs/Makefile | 2 + .../methods/code_constructs/class/Makefile | 12 + .../code_constructs/class/class_bin.ml | 15 ++ .../code_constructs/class/class_lib.ml | 15 ++ .../code_constructs/class/class_lib.mli | 8 + 15 files changed, 331 insertions(+), 13 deletions(-) create mode 100644 docs/methods/code_constructs/CLASS.md create mode 100644 examples/docs/methods/code_constructs/class/Makefile create mode 100644 examples/docs/methods/code_constructs/class/class_bin.ml create mode 100644 examples/docs/methods/code_constructs/class/class_lib.ml create mode 100644 examples/docs/methods/code_constructs/class/class_lib.mli diff --git a/check/classic/classic.exp b/check/classic/classic.exp index 0a34fb69..f52310e8 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -148,6 +148,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset diff --git a/check/classic/classic.ref b/check/classic/classic.ref index 76205e73..cdd8843d 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -153,6 +153,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -628,7 +631,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 539 -Success: 534 +Total: 541 +Success: 536 Failed: 5 -Ratio: 99.0723562152% +Ratio: 99.0757855823% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index fc687bfc..b6b3d3a7 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -103,6 +103,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset diff --git a/check/internal/internal.ref b/check/internal/internal.ref index 1232a32b..4a92f28d 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -108,6 +108,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -583,7 +586,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 497 -Success: 492 +Total: 499 +Success: 494 Failed: 5 -Ratio: 98.9939637827% +Ratio: 98.997995992% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index 6449ed82..bfa94017 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -135,6 +135,8 @@ ./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/methods/code_constructs/class/class_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -342,6 +344,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -405,6 +410,10 @@ Nothing else to report in this section .>-> ALMOST UNUSED METHODS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index bd16858a..7f2b20f8 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -140,6 +140,8 @@ ./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/methods/code_constructs/class/class_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -347,6 +349,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -410,6 +415,10 @@ Nothing else to report in this section .>-> ALMOST UNUSED METHODS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push @@ -966,7 +975,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 832 -Success: 827 +Total: 838 +Success: 833 Failed: 5 -Ratio: 99.3990384615% +Ratio: 99.4033412888% 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 0a23073f..dd273844 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -135,6 +135,8 @@ ./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/methods/code_constructs/class/class_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -472,6 +474,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -535,6 +540,10 @@ Nothing else to report in this section .>-> ALMOST UNUSED METHODS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push 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 2bb604cd..2b770084 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -140,6 +140,8 @@ ./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/methods/code_constructs/class/class_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -477,6 +479,9 @@ Nothing else to report in this section .> UNUSED METHODS: ================= +./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -540,6 +545,10 @@ Nothing else to report in this section .>-> ALMOST UNUSED METHODS: Called 1 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push @@ -1357,7 +1366,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1145 -Success: 1140 +Total: 1151 +Success: 1146 Failed: 5 -Ratio: 99.5633187773% +Ratio: 99.5655951347% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index 34b459da..dc283389 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -137,9 +137,9 @@ from the `.mli` if there is one and the `.ml`. - The [code constructs](./code_constructs) directory contains a collection of examples dedicated to specific code constructs : - [Immediate object](./code_constructs/IMMEDIATE_OBJECT.md) + - [Class](./code_constructs/CLASS.md) [TODO]: # ( - - [Class](./code_constructs/CLASS.md) - [Class type](./code_constructs/CLASS_TYPE.md) - [Inheritance](./code_constructs/INHERITANCE.md) ) diff --git a/docs/methods/code_constructs/CLASS.md b/docs/methods/code_constructs/CLASS.md new file mode 100644 index 00000000..f2586903 --- /dev/null +++ b/docs/methods/code_constructs/CLASS.md @@ -0,0 +1,218 @@ +The reference files for this example are in the +[class](../../../examples/docs/methods/code_constructs/class) directory. + +The reference takes place in `/tmp/docs/methods/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/methods/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C class build +``` + +The analysis command is : +``` +make -C class analyze +``` + +The compile + analyze command is : +``` +make -C class +``` + +## First run + +Code: +```OCaml +(* class_lib.mli *) +class int_stack : + object + method push : int -> unit + method pop : unit + method peek : int option + method reset : unit + end +``` +```OCaml +(* class_lib.ml *) +class int_stack = + object + val mutable l : int list = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end +``` +```OCaml +(* class_bin.ml *) +class unused_class = object method unused_method = () end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let int_stack = new Class_lib.int_stack in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done +``` + +Before looking at the analysis results, let's look at the code. + +The `Class_lib` declares and exports 1 class : `int_stack`. An instance of this +class is used in `Class_bin`. +`Class_bin` declares and exports 1 class : `unused_class`, which is unused. +All of the methods are public, so they are tracked by the analyzer. + +2 methods are explicitly referenced : `int_stack#peek`, and `int_stack#pop`. +1 method is used by requirement : `int_stack#push`, required by the call +`push_n_times n int_stack`. + +This leaves only 2 unused methods : `int_stack#reset` and +`unused_obj#unused_method`. + +Compile and analyze: +``` +$ make -C class +make: Entering directory '/tmp/docs/methods/code_constructs/class' +ocamlopt -bin-annot class_lib.mli class_lib.ml class_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= +/tmp/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method +/tmp/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_constructs/class' +``` + +As expected, 2 methods are reported unused : `unused_class#unused_method`, and +`int_stack#reset`. These can be removed from the class definitions at the +reported locations. + +> [!IMPORTANT] +> The reported locations are those of the classes to which the methods belong. + +> [!NOTE] +> The objects manipulated in this example are instances of classes. Thus, their +> methods are those of their classes. +> If the analyzer reported unused methods for each instance, a user would need +> to explicit the signature of each object rather than simply rely on the +> (possibly inferred) defined class type. This is a non-trivial resolution +> of unused methods, effectively losing the benefits of using class types. +> Consequently, the analyzer does not report unused methods of instances but +> only of the classes they belong to. + +In addition to these unused methods, there is the unused exported class +`unused_class` which is currently not reportable by the analyzer. + +## Removing the unused methods + +> [!TIP] +> Do not forget to remove `int_stack#reset` from both the `.mli` **and** the `.ml`. +> Otherwise, the compiler will reject the code with a message like : +> ``` +> File "class_lib.ml", line 1: +> Error: The implementation class_lib.ml +> does not match the interface class_lib.mli: +> Class declarations do not match: +> class int_stack : +> object +> val mutable l : int list +> method peek : int option +> method pop : unit +> method push : int -> unit +> method reset : unit +> end +> does not match +> class int_stack : +> object +> method peek : int option +> method pop : unit +> method push : int -> unit +> end +> The public method reset cannot be hidden +> ``` + +Code: +```OCaml +(* class_lib.mli *) +class int_stack : + object + method push : int -> unit + method pop : unit + method peek : int option + end +``` +```OCaml +(* class_lib.ml *) +class int_stack = + object + val mutable l : int list = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + end +``` +```OCaml +(* class_bin.ml *) +class unused_class = object end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let int_stack = new Class_lib.int_stack in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done +``` + +Compile and analyze: +``` +$ make -C class +make: Entering directory '/tmp/docs/methods/code_constructs/class' +ocamlopt -bin-annot class_lib.mli class_lib.ml class_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_constructs/class' +``` + +There is no more unused method. Our work here is done. diff --git a/examples/docs/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile index 21d3c404..0e4d922b 100644 --- a/examples/docs/methods/code_constructs/Makefile +++ b/examples/docs/methods/code_constructs/Makefile @@ -4,8 +4,10 @@ all: build build: make -C immediate_object build + make -C class build clean: rm -f *~ *.cm* *.o *.obj make -C immediate_object clean + make -C class clean diff --git a/examples/docs/methods/code_constructs/class/Makefile b/examples/docs/methods/code_constructs/class/Makefile new file mode 100644 index 00000000..7b8a068e --- /dev/null +++ b/examples/docs/methods/code_constructs/class/Makefile @@ -0,0 +1,12 @@ +SRC:=class_lib.mli class_lib.ml class_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/code_constructs/class/class_bin.ml b/examples/docs/methods/code_constructs/class/class_bin.ml new file mode 100644 index 00000000..335070dd --- /dev/null +++ b/examples/docs/methods/code_constructs/class/class_bin.ml @@ -0,0 +1,15 @@ +(* class_bin.ml *) +class unused_class = object method unused_method = () end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let int_stack = new Class_lib.int_stack in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done diff --git a/examples/docs/methods/code_constructs/class/class_lib.ml b/examples/docs/methods/code_constructs/class/class_lib.ml new file mode 100644 index 00000000..518fc97a --- /dev/null +++ b/examples/docs/methods/code_constructs/class/class_lib.ml @@ -0,0 +1,15 @@ +(* class_lib.ml *) +class int_stack = + object + val mutable l : int list = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end diff --git a/examples/docs/methods/code_constructs/class/class_lib.mli b/examples/docs/methods/code_constructs/class/class_lib.mli new file mode 100644 index 00000000..67f815e1 --- /dev/null +++ b/examples/docs/methods/code_constructs/class/class_lib.mli @@ -0,0 +1,8 @@ +(* class_lib.mli *) +class int_stack : + object + method push : int -> unit + method pop : unit + method peek : int option + method reset : unit + end From 95dc65fc35a670a82b342a990f246101bd5cf293 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Fri, 20 Mar 2026 17:57:24 +0100 Subject: [PATCH 04/13] [docs][methods][4/n] add class type example This demonstrates the current silencing of class types. --- check/threshold-1/threshold-1.exp | 2 + check/threshold-1/threshold-1.ref | 8 +- check/threshold-3-0.5/threshold-3-0.5.exp | 4 + check/threshold-3-0.5/threshold-3-0.5.ref | 10 +- docs/methods/METHODS.md | 2 +- docs/methods/code_constructs/CLASS_TYPE.md | 113 ++++++++++++++++++ .../docs/methods/code_constructs/Makefile | 2 + .../code_constructs/class_type/Makefile | 12 ++ .../class_type/class_type_bin.ml | 15 +++ .../class_type/class_type_lib.ml | 23 ++++ .../class_type/class_type_lib.mli | 10 ++ 11 files changed, 194 insertions(+), 7 deletions(-) create mode 100644 docs/methods/code_constructs/CLASS_TYPE.md create mode 100644 examples/docs/methods/code_constructs/class_type/Makefile create mode 100644 examples/docs/methods/code_constructs/class_type/class_type_bin.ml create mode 100644 examples/docs/methods/code_constructs/class_type/class_type_lib.ml create mode 100644 examples/docs/methods/code_constructs/class_type/class_type_lib.mli diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index bfa94017..df5b8a1c 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -137,6 +137,8 @@ ./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 + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 7f2b20f8..7be34092 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -142,6 +142,8 @@ ./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 + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -975,7 +977,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 838 -Success: 833 +Total: 839 +Success: 834 Failed: 5 -Ratio: 99.4033412888% +Ratio: 99.4040524434% 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 dd273844..d327842c 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -137,6 +137,8 @@ ./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 + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -451,6 +453,8 @@ .>-> ALMOST UNUSED EXPORTED VALUES: Called 3 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/class_type/class_type_lib.mli:10: int_stack + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack ./examples/using_dune/unwrapped_lib/values/values_no_intf.ml:19: aliased_fun 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 2b770084..1c5085d3 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -142,6 +142,8 @@ ./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 + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -456,6 +458,8 @@ .>-> ALMOST UNUSED EXPORTED VALUES: Called 3 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +./examples/docs/methods/code_constructs/class_type/class_type_lib.mli:10: int_stack + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack ./examples/using_dune/unwrapped_lib/values/values_no_intf.ml:19: aliased_fun @@ -1366,7 +1370,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1151 -Success: 1146 +Total: 1153 +Success: 1148 Failed: 5 -Ratio: 99.5655951347% +Ratio: 99.5663486557% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index dc283389..1caea337 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -138,8 +138,8 @@ from the `.mli` if there is one and the `.ml`. examples dedicated to specific code constructs : - [Immediate object](./code_constructs/IMMEDIATE_OBJECT.md) - [Class](./code_constructs/CLASS.md) + - [Class type](./code_constructs/CLASS_TYPE.md) [TODO]: # ( - - [Class type](./code_constructs/CLASS_TYPE.md) - [Inheritance](./code_constructs/INHERITANCE.md) ) diff --git a/docs/methods/code_constructs/CLASS_TYPE.md b/docs/methods/code_constructs/CLASS_TYPE.md new file mode 100644 index 00000000..263cb84a --- /dev/null +++ b/docs/methods/code_constructs/CLASS_TYPE.md @@ -0,0 +1,113 @@ +The reference files for this example are in the +[class\_type](../../../examples/docs/methods/code_constructs/class_type) directory. + +The reference takes place in `/tmp/docs/methods/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/methods/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C class_type build +``` + +The analysis command is : +``` +make -C class_type analyze +``` + +The compile + analyze command is : +``` +make -C class_type +``` + +> [!IMPORTANT] +> **LIMITATION** +> +> Methods declared in class types definition (different from class signatures) +> are currently ignored by the analyzer. + +## First run + +Code: +```OCaml +(* class_type_lib.mli *) +class type int_stack = + object + method push : int -> unit + method pop : unit + method peek : int option + method reset : unit + end + +val int_stack : int_stack +``` +```OCaml +(* class_type_lib.ml *) +class type int_stack = + object + method push : int -> unit + method pop : unit + method peek : int option + method reset : unit + end + +let int_stack = + object + val mutable l : int list = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end +``` +```OCaml +(* class_type_bin.ml *) +class type unused_class_type = object method unused_method : unit end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let open Class_type_lib in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done +``` + +By looking at the code, we could make the same observation as in the +[Class](./CLASS.md) example. + +However, because of the current limitation on class types, nothing is expected +to reported. + +Code and analyze: +``` +$ make -C class_type +make: Entering directory '/tmp/docs/methods/code_construct/class_type' +ocamlopt -bin-annot class_type_lib.mli class_type_lib.ml class_type_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_construct/class_type' +``` + +Nothing is reported. Our work here is done. diff --git a/examples/docs/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile index 0e4d922b..f302fa0c 100644 --- a/examples/docs/methods/code_constructs/Makefile +++ b/examples/docs/methods/code_constructs/Makefile @@ -5,9 +5,11 @@ all: build build: make -C immediate_object build make -C class build + make -C class_type build clean: rm -f *~ *.cm* *.o *.obj make -C immediate_object clean make -C class clean + make -C class_type clean diff --git a/examples/docs/methods/code_constructs/class_type/Makefile b/examples/docs/methods/code_constructs/class_type/Makefile new file mode 100644 index 00000000..46bc7680 --- /dev/null +++ b/examples/docs/methods/code_constructs/class_type/Makefile @@ -0,0 +1,12 @@ +SRC:=class_type_lib.mli class_type_lib.ml class_type_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/code_constructs/class_type/class_type_bin.ml b/examples/docs/methods/code_constructs/class_type/class_type_bin.ml new file mode 100644 index 00000000..d759e973 --- /dev/null +++ b/examples/docs/methods/code_constructs/class_type/class_type_bin.ml @@ -0,0 +1,15 @@ +(* class_type_bin.ml *) +class type unused_class_type = object method unused_method : unit end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let open Class_type_lib in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done diff --git a/examples/docs/methods/code_constructs/class_type/class_type_lib.ml b/examples/docs/methods/code_constructs/class_type/class_type_lib.ml new file mode 100644 index 00000000..1dafd2a4 --- /dev/null +++ b/examples/docs/methods/code_constructs/class_type/class_type_lib.ml @@ -0,0 +1,23 @@ +(* class_type_lib.ml *) +class type int_stack = + object + method push : int -> unit + method pop : unit + method peek : int option + method reset : unit + end + +let int_stack = + object + val mutable l : int list = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end diff --git a/examples/docs/methods/code_constructs/class_type/class_type_lib.mli b/examples/docs/methods/code_constructs/class_type/class_type_lib.mli new file mode 100644 index 00000000..7d016c4f --- /dev/null +++ b/examples/docs/methods/code_constructs/class_type/class_type_lib.mli @@ -0,0 +1,10 @@ +(* class_type_lib.mli *) +class type int_stack = + object + method push : int -> unit + method pop : unit + method peek : int option + method reset : unit + end + +val int_stack : int_stack From 79cfe49dd982d22d3fd499c45c55b087bdac8ce8 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 23 Mar 2026 13:38:13 +0100 Subject: [PATCH 05/13] [docs][methods][5/n] add inheritance example This demonstrates the "unification" onf re-exported methods. --- check/classic/classic.exp | 2 + check/classic/classic.ref | 8 +- check/internal/internal.exp | 2 + check/internal/internal.ref | 8 +- check/threshold-1/threshold-1.exp | 5 + check/threshold-1/threshold-1.ref | 11 +- check/threshold-3-0.5/threshold-3-0.5.exp | 5 + check/threshold-3-0.5/threshold-3-0.5.ref | 11 +- docs/methods/METHODS.md | 3 - docs/methods/code_constructs/INHERITANCE.md | 105 ++++++++++++++++++ .../docs/methods/code_constructs/Makefile | 2 + .../code_constructs/inheritance/Makefile | 12 ++ .../inheritance/inheritance_bin.ml | 6 + .../inheritance/inheritance_lib.ml | 12 ++ .../inheritance/inheritance_lib.mli | 12 ++ 15 files changed, 189 insertions(+), 15 deletions(-) create mode 100644 docs/methods/code_constructs/INHERITANCE.md create mode 100644 examples/docs/methods/code_constructs/inheritance/Makefile create mode 100644 examples/docs/methods/code_constructs/inheritance/inheritance_bin.ml create mode 100644 examples/docs/methods/code_constructs/inheritance/inheritance_lib.ml create mode 100644 examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli diff --git a/check/classic/classic.exp b/check/classic/classic.exp index f52310e8..20129c04 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -154,6 +154,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused diff --git a/check/classic/classic.ref b/check/classic/classic.ref index cdd8843d..d4cb7a0d 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -159,6 +159,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -631,7 +633,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 541 -Success: 536 +Total: 542 +Success: 537 Failed: 5 -Ratio: 99.0757855823% +Ratio: 99.0774907749% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index b6b3d3a7..a1f707be 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -109,6 +109,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused diff --git a/check/internal/internal.ref b/check/internal/internal.ref index 4a92f28d..c2c2789d 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -114,6 +114,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -586,7 +588,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 499 -Success: 494 +Total: 500 +Success: 495 Failed: 5 -Ratio: 98.997995992% +Ratio: 99.% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index df5b8a1c..c0edf702 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -352,6 +352,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -420,6 +422,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_used diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 7be34092..4a419cb5 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -357,6 +357,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -425,6 +427,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_used @@ -977,7 +982,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 839 -Success: 834 +Total: 842 +Success: 837 Failed: 5 -Ratio: 99.4040524434% +Ratio: 99.406175772% 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 d327842c..edbb8d21 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -484,6 +484,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -552,6 +554,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_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 1c5085d3..02cf28da 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -489,6 +489,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -557,6 +559,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used +./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_used @@ -1370,7 +1375,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1153 -Success: 1148 +Total: 1156 +Success: 1151 Failed: 5 -Ratio: 99.5663486557% +Ratio: 99.5674740484% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index 1caea337..b7455a79 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -139,7 +139,4 @@ from the `.mli` if there is one and the `.ml`. - [Immediate object](./code_constructs/IMMEDIATE_OBJECT.md) - [Class](./code_constructs/CLASS.md) - [Class type](./code_constructs/CLASS_TYPE.md) - -[TODO]: # ( - [Inheritance](./code_constructs/INHERITANCE.md) - ) diff --git a/docs/methods/code_constructs/INHERITANCE.md b/docs/methods/code_constructs/INHERITANCE.md new file mode 100644 index 00000000..5e3eb7ab --- /dev/null +++ b/docs/methods/code_constructs/INHERITANCE.md @@ -0,0 +1,105 @@ +The reference files for this example are in the +[inheritance](../../../examples/docs/methods/code_constructs/inheritance) directory. + +The reference takes place in `/tmp/docs/methods/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/methods/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C inheritance build +``` + +The analysis command is : +``` +make -C inheritance analyze +``` + +The compile + analyze command is : +``` +make -C inheritance +``` + +## First run + +Code: +```OCaml +(* inheritance_lib.mli *) +class parent : + object + method unused : unit + method used : unit + method used_by_child : unit + end + +class child : + object + inherit parent + end +``` +```OCaml +(* inheritance_lib.ml *) +class parent = + object + method unused = () + method used = () + method used_by_child = () + end + +class child = + object + inherit parent + end +``` +```OCaml +(* inheritance_bin.ml *) +let () = + let p = new Inheritance_lib.parent in + let c = new Inheritance_lib.child in + p#used; + c#used_by_child +``` + +The code is pretty straightforward. `Inheritance_lib` defines 2 classes : +- `parent`, which defines 3 methods; +- `child`, which only inherits `parent`. + +CLass inheritance is semantically equivalent to module inclusion from the +analyzer's point of view : the `parent` class is the actual "owner" of the +methods, and `child` only re-exposes them. This, has 2 consequences : +- inherited methods in `child` are not analyzed individually; +- using a method from `child` that is inherited from `parent` is the same as + using the method from `parent`. + +Now if we look at the uses, 2 methods are referenced explicitly : +- `p#used`, which is `parent#used` +- `c#used_by_child`, which is `child#used_by_child`, which is + `parent#used_by_child` + +This leaves `parent#unused` as the only unused method. + +Compile and analyze: +``` +$ make -C inheritance +make: Entering directory '/tmp/docs/methods/code_constructs/inheritance' +ocamlopt -bin-annot inheritance_lib.mli inheritance_lib.ml inheritance_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= +/tmp/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_constructs/inheritance' +``` + +As expected, the analyzer reports `parent#unused` as unused. It can be removed +from `inheritance_lib.mli` and `inheritance_lib.ml`. +Neither the compiler nor the analyzer will report unused methods anymore. +Our work here is done. diff --git a/examples/docs/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile index f302fa0c..1e1e02c8 100644 --- a/examples/docs/methods/code_constructs/Makefile +++ b/examples/docs/methods/code_constructs/Makefile @@ -6,10 +6,12 @@ build: make -C immediate_object build make -C class build make -C class_type build + make -C inheritance build clean: rm -f *~ *.cm* *.o *.obj make -C immediate_object clean make -C class clean make -C class_type clean + make -C inheritance clean diff --git a/examples/docs/methods/code_constructs/inheritance/Makefile b/examples/docs/methods/code_constructs/inheritance/Makefile new file mode 100644 index 00000000..a8db8764 --- /dev/null +++ b/examples/docs/methods/code_constructs/inheritance/Makefile @@ -0,0 +1,12 @@ +SRC:=inheritance_lib.mli inheritance_lib.ml inheritance_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/code_constructs/inheritance/inheritance_bin.ml b/examples/docs/methods/code_constructs/inheritance/inheritance_bin.ml new file mode 100644 index 00000000..532093f4 --- /dev/null +++ b/examples/docs/methods/code_constructs/inheritance/inheritance_bin.ml @@ -0,0 +1,6 @@ +(* inheritance_bin.ml *) +let () = + let p = new Inheritance_lib.parent in + let c = new Inheritance_lib.child in + p#used; + c#used_by_child diff --git a/examples/docs/methods/code_constructs/inheritance/inheritance_lib.ml b/examples/docs/methods/code_constructs/inheritance/inheritance_lib.ml new file mode 100644 index 00000000..8eb8b34c --- /dev/null +++ b/examples/docs/methods/code_constructs/inheritance/inheritance_lib.ml @@ -0,0 +1,12 @@ +(* inheritance_lib.ml *) +class parent = + object + method unused = () + method used = () + method used_by_child = () + end + +class child = + object + inherit parent + end diff --git a/examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli b/examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli new file mode 100644 index 00000000..1873ad9e --- /dev/null +++ b/examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli @@ -0,0 +1,12 @@ +(* inheritance_lib.mli *) +class parent : + object + method unused : unit + method used : unit + method used_by_child : unit + end + +class child : + object + inherit parent + end From ce2dfce97be9b7f96eeaeb8f8e0d50adeacfe184 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 23 Mar 2026 13:48:55 +0100 Subject: [PATCH 06/13] [docs][methods][6/n] add limitations section list the class type limitation --- docs/methods/METHODS.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index b7455a79..781cfbd6 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -6,6 +6,8 @@ + [Warning 26: unused-ancestor](#warning-36-unused-ancestor) + [Usage](#usage) + [Examples](#examples) ++ [Limitations](#limitations) + +[Class type](#class-type) # Methods @@ -140,3 +142,11 @@ from the `.mli` if there is one and the `.ml`. - [Class](./code_constructs/CLASS.md) - [Class type](./code_constructs/CLASS_TYPE.md) - [Inheritance](./code_constructs/INHERITANCE.md) + +# Limitations + +## Class type + +As explained in the [Class type](./code_constructs/CLASS_TYPE.md) example, the +analyzer is currently restricted to not reporting methods declared in class +type definitions. From b23171fdce7f6ffe6ae19513b6174e8f41c917f9 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:02:03 +0100 Subject: [PATCH 07/13] [docs][methods][7/n] add object type example This is the same as the class type example. This demonstrates the current silencing of object types. --- check/threshold-1/threshold-1.exp | 2 + check/threshold-1/threshold-1.ref | 8 +- check/threshold-3-0.5/threshold-3-0.5.exp | 4 + check/threshold-3-0.5/threshold-3-0.5.ref | 10 +- docs/methods/METHODS.md | 8 ++ docs/methods/code_constructs/OBJECT_TYPE.md | 108 ++++++++++++++++++ .../docs/methods/code_constructs/Makefile | 2 + .../code_constructs/object_type/Makefile | 12 ++ .../object_type/object_type_bin.ml | 15 +++ .../object_type/object_type_lib.ml | 22 ++++ .../object_type/object_type_lib.mli | 9 ++ 11 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 docs/methods/code_constructs/OBJECT_TYPE.md create mode 100644 examples/docs/methods/code_constructs/object_type/Makefile create mode 100644 examples/docs/methods/code_constructs/object_type/object_type_bin.ml create mode 100644 examples/docs/methods/code_constructs/object_type/object_type_lib.ml create mode 100644 examples/docs/methods/code_constructs/object_type/object_type_lib.mli diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index c0edf702..b294cc98 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -141,6 +141,8 @@ ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 4a419cb5..f791d0e4 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -146,6 +146,8 @@ ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -982,7 +984,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 842 -Success: 837 +Total: 843 +Success: 838 Failed: 5 -Ratio: 99.406175772% +Ratio: 99.4068801898% 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 edbb8d21..ab3f29b0 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -141,6 +141,8 @@ ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -457,6 +459,8 @@ ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack +./examples/docs/methods/code_constructs/object_type/object_type_lib.mli:9: int_stack + ./examples/using_dune/unwrapped_lib/values/values_no_intf.ml:19: aliased_fun ./examples/using_dune/wrapped_lib/values/values_no_intf.ml:19: aliased_fun 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 02cf28da..0a8b185e 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -146,6 +146,8 @@ ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -462,6 +464,8 @@ ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack +./examples/docs/methods/code_constructs/object_type/object_type_lib.mli:9: int_stack + ./examples/using_dune/unwrapped_lib/values/values_no_intf.ml:19: aliased_fun ./examples/using_dune/wrapped_lib/values/values_no_intf.ml:19: aliased_fun @@ -1375,7 +1379,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1156 -Success: 1151 +Total: 1158 +Success: 1153 Failed: 5 -Ratio: 99.5674740484% +Ratio: 99.5682210708% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index 781cfbd6..59c148e7 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -8,6 +8,7 @@ + [Examples](#examples) + [Limitations](#limitations) +[Class type](#class-type) + +[Object type](#object-type) # Methods @@ -142,6 +143,7 @@ from the `.mli` if there is one and the `.ml`. - [Class](./code_constructs/CLASS.md) - [Class type](./code_constructs/CLASS_TYPE.md) - [Inheritance](./code_constructs/INHERITANCE.md) + - [Object type](./code_constructs/OBJECT_TYPE.md) # Limitations @@ -150,3 +152,9 @@ from the `.mli` if there is one and the `.ml`. As explained in the [Class type](./code_constructs/CLASS_TYPE.md) example, the analyzer is currently restricted to not reporting methods declared in class type definitions. + +## Object type + +As explained in the [Object type](./code_constructs/OBJECT_TYPE.md) example, the +analyzer is currently restricted to not reporting methods declared in object +types. diff --git a/docs/methods/code_constructs/OBJECT_TYPE.md b/docs/methods/code_constructs/OBJECT_TYPE.md new file mode 100644 index 00000000..8bcd8b66 --- /dev/null +++ b/docs/methods/code_constructs/OBJECT_TYPE.md @@ -0,0 +1,108 @@ +The reference files for this example are in the +[object\_type](../../../examples/docs/methods/code_constructs/object_type) directory. + +The reference takes place in `/tmp/docs/methods/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/methods/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C object_type build +``` + +The analysis command is : +``` +make -C object_type analyze +``` + +The compile + analyze command is : +``` +make -C object_type +``` + +> [!IMPORTANT] +> **LIMITATION** +> +> Methods declared in object types are currently ignored by the analyzer. + +## First run + +Code: +```OCaml +(* object_type_lib.mli *) +type int_stack = + < push : int -> unit + ; pop : unit + ; peek : int option + ; reset : unit + > + +val int_stack : int_stack +``` +```OCaml +(* object_type_lib.ml *) +type int_stack = + < push : int -> unit + ; pop : unit + ; peek : int option + ; reset : unit + > + +let int_stack = + object + val mutable l : int list = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end +``` +```OCaml +(* object_type_bin.ml *) +type unused_t = < unused_method : unit > + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let open Object_type_lib in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done +``` + +By looking at the code, we could make the same observation as in the +[Class type](./CLASS_TYPE.md) example. The analyzer's semantics are equivalent +so the results are the same as well. + +Code and analyze: +``` +$ make -C object_type +make: Entering directory '/tmp/docs/methods/code_construct/object_type' +ocamlopt -bin-annot object_type_lib.mli object_type_lib.ml object_type_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_construct/object_type' +``` + +Nothing is reported. Our work here is done. diff --git a/examples/docs/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile index 1e1e02c8..09b69841 100644 --- a/examples/docs/methods/code_constructs/Makefile +++ b/examples/docs/methods/code_constructs/Makefile @@ -7,6 +7,7 @@ build: make -C class build make -C class_type build make -C inheritance build + make -C object_type build clean: rm -f *~ *.cm* *.o *.obj @@ -14,4 +15,5 @@ clean: make -C class clean make -C class_type clean make -C inheritance clean + make -C object_type clean diff --git a/examples/docs/methods/code_constructs/object_type/Makefile b/examples/docs/methods/code_constructs/object_type/Makefile new file mode 100644 index 00000000..ee407925 --- /dev/null +++ b/examples/docs/methods/code_constructs/object_type/Makefile @@ -0,0 +1,12 @@ +SRC:=object_type_lib.mli object_type_lib.ml object_type_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/code_constructs/object_type/object_type_bin.ml b/examples/docs/methods/code_constructs/object_type/object_type_bin.ml new file mode 100644 index 00000000..83ea1a17 --- /dev/null +++ b/examples/docs/methods/code_constructs/object_type/object_type_bin.ml @@ -0,0 +1,15 @@ +(* object_type_bin.ml *) +type unused_t = < unused_method : unit > + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let open Object_type_lib in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done diff --git a/examples/docs/methods/code_constructs/object_type/object_type_lib.ml b/examples/docs/methods/code_constructs/object_type/object_type_lib.ml new file mode 100644 index 00000000..8985da89 --- /dev/null +++ b/examples/docs/methods/code_constructs/object_type/object_type_lib.ml @@ -0,0 +1,22 @@ +(* object_type_lib.ml *) +type int_stack = + < push : int -> unit + ; pop : unit + ; peek : int option + ; reset : unit + > + +let int_stack = + object + val mutable l : int list = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end diff --git a/examples/docs/methods/code_constructs/object_type/object_type_lib.mli b/examples/docs/methods/code_constructs/object_type/object_type_lib.mli new file mode 100644 index 00000000..03f65b42 --- /dev/null +++ b/examples/docs/methods/code_constructs/object_type/object_type_lib.mli @@ -0,0 +1,9 @@ +(* object_type_lib.mli *) +type int_stack = + < push : int -> unit + ; pop : unit + ; peek : int option + ; reset : unit + > + +val int_stack : int_stack From 78fd8612cf3012eb03fb329e534dc80f9f821311 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:33:31 +0100 Subject: [PATCH 08/13] [docs][methods][8/n] add constructor example This is the same as the class example with extra initialisers. --- check/classic/classic.exp | 3 + check/classic/classic.ref | 9 +- check/internal/internal.exp | 3 + check/internal/internal.ref | 9 +- check/threshold-1/threshold-1.exp | 9 ++ check/threshold-1/threshold-1.ref | 15 ++- check/threshold-3-0.5/threshold-3-0.5.exp | 9 ++ check/threshold-3-0.5/threshold-3-0.5.ref | 15 ++- docs/methods/METHODS.md | 1 + docs/methods/code_constructs/CONSTRUCTOR.md | 101 ++++++++++++++++++ .../docs/methods/code_constructs/Makefile | 2 + .../code_constructs/constructor/Makefile | 12 +++ .../constructor/constructor_bin.ml | 15 +++ .../constructor/constructor_lib.ml | 15 +++ .../constructor/constructor_lib.mli | 9 ++ 15 files changed, 215 insertions(+), 12 deletions(-) create mode 100644 docs/methods/code_constructs/CONSTRUCTOR.md create mode 100644 examples/docs/methods/code_constructs/constructor/Makefile create mode 100644 examples/docs/methods/code_constructs/constructor/constructor_bin.ml create mode 100644 examples/docs/methods/code_constructs/constructor/constructor_lib.ml create mode 100644 examples/docs/methods/code_constructs/constructor/constructor_lib.mli diff --git a/check/classic/classic.exp b/check/classic/classic.exp index 20129c04..c29db881 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -151,6 +151,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset diff --git a/check/classic/classic.ref b/check/classic/classic.ref index d4cb7a0d..7dbd2e99 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -156,6 +156,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -633,7 +636,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 542 -Success: 537 +Total: 544 +Success: 539 Failed: 5 -Ratio: 99.0774907749% +Ratio: 99.0808823529% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index a1f707be..505e2332 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -106,6 +106,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset diff --git a/check/internal/internal.ref b/check/internal/internal.ref index c2c2789d..a3cae0d7 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -111,6 +111,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -588,7 +591,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 500 -Success: 495 +Total: 502 +Success: 497 Failed: 5 -Ratio: 99.% +Ratio: 99.0039840637% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index b294cc98..1d5bc2ea 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -139,6 +139,8 @@ ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times @@ -351,6 +353,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -420,6 +425,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index f791d0e4..f325d0d5 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -144,6 +144,8 @@ ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times @@ -356,6 +358,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -425,6 +430,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push @@ -984,7 +993,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 843 -Success: 838 +Total: 849 +Success: 844 Failed: 5 -Ratio: 99.4068801898% +Ratio: 99.4110718492% 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 ab3f29b0..b69b7c47 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -139,6 +139,8 @@ ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times @@ -485,6 +487,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -554,6 +559,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push 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 0a8b185e..0f62755d 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -144,6 +144,8 @@ ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times @@ -490,6 +492,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -559,6 +564,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#peek +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop +./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push @@ -1379,7 +1388,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1158 -Success: 1153 +Total: 1164 +Success: 1159 Failed: 5 -Ratio: 99.5682210708% +Ratio: 99.5704467354% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index 59c148e7..2381fc13 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -144,6 +144,7 @@ from the `.mli` if there is one and the `.ml`. - [Class type](./code_constructs/CLASS_TYPE.md) - [Inheritance](./code_constructs/INHERITANCE.md) - [Object type](./code_constructs/OBJECT_TYPE.md) + - [Constructor](./code_constructs/CONSTRUCTOR.md) # Limitations diff --git a/docs/methods/code_constructs/CONSTRUCTOR.md b/docs/methods/code_constructs/CONSTRUCTOR.md new file mode 100644 index 00000000..a604d81c --- /dev/null +++ b/docs/methods/code_constructs/CONSTRUCTOR.md @@ -0,0 +1,101 @@ +The reference files for this example are in the +[constructor](../../../examples/docs/methods/code_constructs/constructor) directory. + +The reference takes place in `/tmp/docs/methods/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/methods/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C constructor build +``` + +The analysis command is : +``` +make -C constructor analyze +``` + +The compile + analyze command is : +``` +make -C constructor +``` + +## First run + +Code: +```OCaml +(* constructor_lib.mli *) +class int_stack : + int list -> + object + method push : int -> unit + method pop : unit + method peek : int option + method reset : unit + end +``` +```OCaml +(* constructor_lib.ml *) +class int_stack init = + object + val mutable l : int list = init + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end +``` +```OCaml +(* constructor_bin.ml *) +class unused_class _ = object method unused_method = () end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let int_stack = new Constructor_lib.int_stack [] in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done +``` + +The code is very similar to the one of the [Class](./CLASS.md) example, with a +small twist : the classes have initialisers. Because the analyzer does not track +each instance' methods uses individually but unified whith the defining class, +the presence of initialisers should not make a difference and the expected +results are the same as in the [Class](./CLASS.md) example. + +Compile and analyze: +``` +$ make -C constructor +make: Entering directory '/tmp/docs/methods/code_constructs/constructor' +ocamlopt -bin-annot constructor_lib.mli constructor_lib.ml constructor_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= +/tmp/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method +/tmp/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_constructs/constructor' +``` + +The results are the same as expected. The resolution is already detailed in the +[Class](./CLASS.md) example. Our work here is done. diff --git a/examples/docs/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile index 09b69841..69103034 100644 --- a/examples/docs/methods/code_constructs/Makefile +++ b/examples/docs/methods/code_constructs/Makefile @@ -8,6 +8,7 @@ build: make -C class_type build make -C inheritance build make -C object_type build + make -C constructor build clean: rm -f *~ *.cm* *.o *.obj @@ -16,4 +17,5 @@ clean: make -C class_type clean make -C inheritance clean make -C object_type clean + make -C constructor clean diff --git a/examples/docs/methods/code_constructs/constructor/Makefile b/examples/docs/methods/code_constructs/constructor/Makefile new file mode 100644 index 00000000..8b7ea530 --- /dev/null +++ b/examples/docs/methods/code_constructs/constructor/Makefile @@ -0,0 +1,12 @@ +SRC:=constructor_lib.mli constructor_lib.ml constructor_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/code_constructs/constructor/constructor_bin.ml b/examples/docs/methods/code_constructs/constructor/constructor_bin.ml new file mode 100644 index 00000000..31c9fb5a --- /dev/null +++ b/examples/docs/methods/code_constructs/constructor/constructor_bin.ml @@ -0,0 +1,15 @@ +(* constructor_bin.ml *) +class unused_class _ = object method unused_method = () end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let int_stack = new Constructor_lib.int_stack [] in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done diff --git a/examples/docs/methods/code_constructs/constructor/constructor_lib.ml b/examples/docs/methods/code_constructs/constructor/constructor_lib.ml new file mode 100644 index 00000000..db48de6f --- /dev/null +++ b/examples/docs/methods/code_constructs/constructor/constructor_lib.ml @@ -0,0 +1,15 @@ +(* constructor_lib.ml *) +class int_stack init = + object + val mutable l : int list = init + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end diff --git a/examples/docs/methods/code_constructs/constructor/constructor_lib.mli b/examples/docs/methods/code_constructs/constructor/constructor_lib.mli new file mode 100644 index 00000000..723aa6a5 --- /dev/null +++ b/examples/docs/methods/code_constructs/constructor/constructor_lib.mli @@ -0,0 +1,9 @@ +(* constructor_lib.mli *) +class int_stack : + int list -> + object + method push : int -> unit + method pop : unit + method peek : int option + method reset : unit + end From 50b0bc6f8ff8383de37bc4f0bc5842d24c412ec1 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:44:02 +0100 Subject: [PATCH 09/13] [docs][methods][9/n] reorder examples --- docs/methods/METHODS.md | 4 ++-- examples/docs/methods/code_constructs/Makefile | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index 2381fc13..7320e3d2 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -139,12 +139,12 @@ from the `.mli` if there is one and the `.ml`. - The [code constructs](./code_constructs) directory contains a collection of examples dedicated to specific code constructs : - - [Immediate object](./code_constructs/IMMEDIATE_OBJECT.md) - [Class](./code_constructs/CLASS.md) + - [Constructor](./code_constructs/CONSTRUCTOR.md) - [Class type](./code_constructs/CLASS_TYPE.md) - [Inheritance](./code_constructs/INHERITANCE.md) + - [Immediate object](./code_constructs/IMMEDIATE_OBJECT.md) - [Object type](./code_constructs/OBJECT_TYPE.md) - - [Constructor](./code_constructs/CONSTRUCTOR.md) # Limitations diff --git a/examples/docs/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile index 69103034..31ecc8fb 100644 --- a/examples/docs/methods/code_constructs/Makefile +++ b/examples/docs/methods/code_constructs/Makefile @@ -3,19 +3,19 @@ all: build build: - make -C immediate_object build make -C class build + make -C constructor build make -C class_type build make -C inheritance build + make -C immediate_object build make -C object_type build - make -C constructor build clean: rm -f *~ *.cm* *.o *.obj - make -C immediate_object clean make -C class clean + make -C constructor clean make -C class_type clean make -C inheritance clean + make -C immediate_object clean make -C object_type clean - make -C constructor clean From 64a432491d6fb34224b2c3dc003728525cd2e3cc Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:00:35 +0100 Subject: [PATCH 10/13] [docs][methods][10/n] add alias limitation This shows that in the presence of aliases, the analyzer avoid duplicate reports but also fails to properly track uses through aliases, resulting in false positives. --- check/classic/classic.exp | 2 + check/classic/classic.ref | 10 +- check/internal/internal.exp | 2 + check/internal/internal.ref | 10 +- check/threshold-1/threshold-1.exp | 7 ++ check/threshold-1/threshold-1.ref | 14 ++- check/threshold-3-0.5/threshold-3-0.5.exp | 9 ++ check/threshold-3-0.5/threshold-3-0.5.ref | 16 +++- docs/methods/METHODS.md | 95 +++++++++++++++++++ examples/docs/methods/Makefile | 2 + examples/docs/methods/limitations/Makefile | 11 +++ .../docs/methods/limitations/alias/Makefile | 12 +++ .../methods/limitations/alias/alias_bin.ml | 6 ++ .../methods/limitations/alias/alias_lib.ml | 9 ++ .../methods/limitations/alias/alias_lib.mli | 12 +++ 15 files changed, 201 insertions(+), 16 deletions(-) create mode 100644 examples/docs/methods/limitations/Makefile create mode 100644 examples/docs/methods/limitations/alias/Makefile create mode 100644 examples/docs/methods/limitations/alias/alias_bin.ml create mode 100644 examples/docs/methods/limitations/alias/alias_lib.ml create mode 100644 examples/docs/methods/limitations/alias/alias_lib.mli diff --git a/check/classic/classic.exp b/check/classic/classic.exp index c29db881..68ea3c27 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -159,6 +159,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused diff --git a/check/classic/classic.ref b/check/classic/classic.ref index 7dbd2e99..88b0bd7d 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -164,6 +164,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -636,7 +638,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 544 -Success: 539 -Failed: 5 -Ratio: 99.0808823529% +Total: 546 +Success: 540 +Failed: 6 +Ratio: 98.9010989011% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index 505e2332..74a705c7 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -114,6 +114,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused diff --git a/check/internal/internal.ref b/check/internal/internal.ref index a3cae0d7..ecb43999 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -119,6 +119,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -591,7 +593,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 502 -Success: 497 -Failed: 5 -Ratio: 99.0039840637% +Total: 504 +Success: 498 +Failed: 6 +Ratio: 98.8095238095% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index 1d5bc2ea..21f016e2 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -145,6 +145,8 @@ ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times +./examples/docs/methods/limitations/alias/alias_lib.mli:8: alias + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -361,6 +363,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -436,6 +440,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_used diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index f325d0d5..7aa063f0 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -150,6 +150,8 @@ ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times +./examples/docs/methods/limitations/alias/alias_lib.mli:8: alias + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -366,6 +368,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -441,6 +445,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Not detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_used @@ -993,7 +999,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 849 -Success: 844 -Failed: 5 -Ratio: 99.4110718492% +Total: 854 +Success: 847 +Failed: 7 +Ratio: 99.1803278689% 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 b69b7c47..f6dd6e74 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -145,6 +145,8 @@ ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times +./examples/docs/methods/limitations/alias/alias_lib.mli:8: alias + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -352,6 +354,8 @@ ./examples/docs/exported_values/hello_world/hello_world_with_intf.mli:4: world ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:4: world +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original + ./examples/using_dune/preprocessed_lib/preprocessed.mli:2: used ./examples/using_dune/preprocessed_lib/preprocessed.mli:31: exported_f ./examples/using_dune/preprocessed_lib/preprocessed.mli:38: internally_used_f @@ -495,6 +499,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -570,6 +576,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_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 0f62755d..1b89f061 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -150,6 +150,8 @@ ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times +./examples/docs/methods/limitations/alias/alias_lib.mli:8: alias + ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_lib.mli:1: mark_used ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed_no_intf.mli:1: mark_used @@ -357,6 +359,8 @@ ./examples/docs/exported_values/hello_world/hello_world_with_intf.mli:4: world ./examples/docs/exported_values/hello_world/hello_world_without_intf.ml:4: world +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original + ./examples/using_dune/preprocessed_lib/preprocessed.mli:2: used ./examples/using_dune/preprocessed_lib/preprocessed.mli:31: exported_f ./examples/using_dune/preprocessed_lib/preprocessed.mli:38: internally_used_f @@ -500,6 +504,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -575,6 +581,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used +./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Not detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#internally_used ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#externally_used @@ -1388,7 +1396,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1164 -Success: 1159 -Failed: 5 -Ratio: 99.5704467354% +Total: 1170 +Success: 1163 +Failed: 7 +Ratio: 99.4017094017% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index 7320e3d2..13ddfc03 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -9,6 +9,7 @@ + [Limitations](#limitations) +[Class type](#class-type) +[Object type](#object-type) + +[Alias](#alias) # Methods @@ -159,3 +160,97 @@ type definitions. As explained in the [Object type](./code_constructs/OBJECT_TYPE.md) example, the analyzer is currently restricted to not reporting methods declared in object types. + +## Alias + +Related issue : +[issue #66](https://github.com/LexiFi/dead_code_analyzer/issues/66). + +In the presence of multiple bindings to the same object, the analyzer corrctly +avoids tracking their methods individually. However, it fails at unifying them +and only keeps track of the methods used through the original binding, where the +methods are defined. This leads to **false positives**. + +### Example + +The reference files for this example are in the +[alias](../../examples/docs/methods/limitations/alias) directory. + +The reference takes place in `/tmp/docs/methods/limitations`, which +is a copy of the [limitations](../../../examples/docs/methods/limitations) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C alias build +``` + +The analysis command is : +``` +make -C alias analyze +``` + +The compile + analyze command is : +``` +make -C alias +``` + +Code: +```OCaml +(* alias_lib.mli *) +val original : + < used : unit + ; used_by_alias : unit + ; unused : unit + > + +val alias : + < used : unit + ; used_by_alias : unit + ; unused : unit + > +``` +```OCaml +(* alias_lib.ml *) +let original = + object + method used = () + method used_by_alias = () + method unused = () + end + +let alias = original +``` +```OCaml +(* alias_bin.ml *) +open Alias_lib + +let () = + original#used; + alias#used_by_alias +``` + +Compile and analyze: +``` +$ make -C alias +make: Entering directory '/tmp/docs/methods/limitations/alias' +ocamlopt -bin-annot alias_lib.mli alias_lib.ml alias_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= +/tmp/docs/methods/limitations/alias/alias_lib.mli:2: original#unused +/tmp/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/limitations/alias' +``` + +The analyzer reports `original#used_by_alias` although it is used by +`alias#used_by_alias`. diff --git a/examples/docs/methods/Makefile b/examples/docs/methods/Makefile index 838d97ec..da62ef35 100644 --- a/examples/docs/methods/Makefile +++ b/examples/docs/methods/Makefile @@ -4,8 +4,10 @@ all: build build: make -C code_constructs + make -C limitations clean: rm -f *~ *.cm* *.o *.obj make -C code_constructs clean + make -C limitations clean diff --git a/examples/docs/methods/limitations/Makefile b/examples/docs/methods/limitations/Makefile new file mode 100644 index 00000000..e0b60d24 --- /dev/null +++ b/examples/docs/methods/limitations/Makefile @@ -0,0 +1,11 @@ +.PHONY: clean build + +all: build + +build: + make -C alias build + +clean: + rm -f *~ *.cm* *.o *.obj + make -C alias clean + diff --git a/examples/docs/methods/limitations/alias/Makefile b/examples/docs/methods/limitations/alias/Makefile new file mode 100644 index 00000000..d2d83742 --- /dev/null +++ b/examples/docs/methods/limitations/alias/Makefile @@ -0,0 +1,12 @@ +SRC:=alias_lib.mli alias_lib.ml alias_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/limitations/alias/alias_bin.ml b/examples/docs/methods/limitations/alias/alias_bin.ml new file mode 100644 index 00000000..9effa51b --- /dev/null +++ b/examples/docs/methods/limitations/alias/alias_bin.ml @@ -0,0 +1,6 @@ +(* alias_bin.ml *) +open Alias_lib + +let () = + original#used; + alias#used_by_alias diff --git a/examples/docs/methods/limitations/alias/alias_lib.ml b/examples/docs/methods/limitations/alias/alias_lib.ml new file mode 100644 index 00000000..830c0ee8 --- /dev/null +++ b/examples/docs/methods/limitations/alias/alias_lib.ml @@ -0,0 +1,9 @@ +(* alias_lib.ml *) +let original = + object + method used = () + method used_by_alias = () + method unused = () + end + +let alias = original diff --git a/examples/docs/methods/limitations/alias/alias_lib.mli b/examples/docs/methods/limitations/alias/alias_lib.mli new file mode 100644 index 00000000..569ad584 --- /dev/null +++ b/examples/docs/methods/limitations/alias/alias_lib.mli @@ -0,0 +1,12 @@ +(* alias_lib.mli *) +val original : + < used : unit + ; used_by_alias : unit + ; unused : unit + > + +val alias : + < used : unit + ; used_by_alias : unit + ; unused : unit + > From 065cbebdcebcddf263f383a44fd24e9ca80cfe32 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:21:18 +0100 Subject: [PATCH 11/13] [docs][methods][11/n] add coercion example This shows that coercing an object implies use by requirements. --- check/classic/classic.exp | 2 + check/classic/classic.ref | 8 +- check/internal/internal.exp | 2 + check/internal/internal.ref | 8 +- check/threshold-1/threshold-1.exp | 6 ++ check/threshold-1/threshold-1.ref | 12 ++- check/threshold-3-0.5/threshold-3-0.5.exp | 6 ++ check/threshold-3-0.5/threshold-3-0.5.ref | 12 ++- docs/methods/METHODS.md | 1 + docs/methods/code_constructs/COERCION.md | 82 +++++++++++++++++++ .../docs/methods/code_constructs/Makefile | 2 + .../methods/code_constructs/coercion/Makefile | 12 +++ .../code_constructs/coercion/coercion_bin.ml | 6 ++ .../code_constructs/coercion/coercion_lib.ml | 6 ++ .../code_constructs/coercion/coercion_lib.mli | 5 ++ 15 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 docs/methods/code_constructs/COERCION.md create mode 100644 examples/docs/methods/code_constructs/coercion/Makefile create mode 100644 examples/docs/methods/code_constructs/coercion/coercion_bin.ml create mode 100644 examples/docs/methods/code_constructs/coercion/coercion_lib.ml create mode 100644 examples/docs/methods/code_constructs/coercion/coercion_lib.mli diff --git a/check/classic/classic.exp b/check/classic/classic.exp index 68ea3c27..a58e920e 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -151,6 +151,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#unused + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset diff --git a/check/classic/classic.ref b/check/classic/classic.ref index 88b0bd7d..e633c81e 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -156,6 +156,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#unused + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset @@ -638,7 +640,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 546 -Success: 540 +Total: 547 +Success: 541 Failed: 6 -Ratio: 98.9010989011% +Ratio: 98.9031078611% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index 74a705c7..56ffb3fc 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -106,6 +106,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#unused + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset diff --git a/check/internal/internal.ref b/check/internal/internal.ref index ecb43999..18a3e7b4 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -111,6 +111,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#unused + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset @@ -593,7 +595,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 504 -Success: 498 +Total: 505 +Success: 499 Failed: 6 -Ratio: 98.8095238095% +Ratio: 98.8118811881% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index 21f016e2..2382dec9 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -139,6 +139,8 @@ ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times @@ -355,6 +357,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#unused + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset @@ -429,6 +433,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#used_by_requirement + ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 7aa063f0..ffbe7229 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -144,6 +144,8 @@ ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times @@ -360,6 +362,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#unused + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset @@ -434,6 +438,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#used_by_requirement + ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push @@ -999,7 +1005,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 854 -Success: 847 +Total: 857 +Success: 850 Failed: 7 -Ratio: 99.1803278689% +Ratio: 99.1831971995% 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 f6dd6e74..6692f275 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -139,6 +139,8 @@ ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times @@ -491,6 +493,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#unused + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset @@ -565,6 +569,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#used_by_requirement + ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push 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 1b89f061..2d3168f1 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -144,6 +144,8 @@ ./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times @@ -496,6 +498,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#unused + ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset @@ -570,6 +574,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/class/class_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#used_by_requirement + ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push @@ -1396,7 +1402,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1170 -Success: 1163 +Total: 1173 +Success: 1166 Failed: 7 -Ratio: 99.4017094017% +Ratio: 99.4032395567% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index 13ddfc03..bb79f3bd 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -146,6 +146,7 @@ from the `.mli` if there is one and the `.ml`. - [Inheritance](./code_constructs/INHERITANCE.md) - [Immediate object](./code_constructs/IMMEDIATE_OBJECT.md) - [Object type](./code_constructs/OBJECT_TYPE.md) + - [Coercion](./code_constructs/COERCION.md) # Limitations diff --git a/docs/methods/code_constructs/COERCION.md b/docs/methods/code_constructs/COERCION.md new file mode 100644 index 00000000..6b05bffd --- /dev/null +++ b/docs/methods/code_constructs/COERCION.md @@ -0,0 +1,82 @@ +The reference files for this example are in the +[coercion](../../../examples/docs/methods/code_constructs/coercion) directory. + +The reference takes place in `/tmp/docs/methods/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/methods/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C coercion build +``` + +The analysis command is : +``` +make -C coercion analyze +``` + +The compile + analyze command is : +``` +make -C coercion +``` + +## First run + +Code: +```OCaml +(* coercion_lib.mli *) +val obj : + < used_by_requirement : unit + ; unused : unit + > +``` +```OCaml +(* coercion_lib.ml *) +let obj = + object + method used_by_requirement = () + method unused = () + end +``` +```OCaml +(* coercion_bin.ml *) +open Coercion_lib + +let () = + let _coerce = (obj :> < used_by_requirement : unit >) in + () +``` + +Before looking at the analysis results, let's look at the code. + +There is 1 object : `Coercion_lib.obj`, which defined 2 zmthods : +`used_by_requirement`, and `unused`. Neither of them is explicitly referenced, +and the object is only manipulated through a coercion. The coercion produces an +alias to `obj` named `_coerce`, which only exposes the method +`used_by_requirement`. Because the method is required to exists in `obj` for the +coercion, then the analyzer effectively considers it as used by requirement. + +Compile and analyze: +``` +$ make -C coercion +make: Entering directory '/tmp/docs/methods/code_constructs/coercion' +ocamlopt -bin-annot coercion_lib.mli coercion_lib.ml coercion_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= +/tmp/docs/methods/code_constructs/coercion/coercion_lib.mli:2: obj#unused + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_constructs/coercion' +``` + +As expected, the anlyzer reports `obj#unsed` as unused and not +`obj#used_by_requirement`. The unused method can be removed from the `.mli` and +the `.ml`. Our work here is done. diff --git a/examples/docs/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile index 31ecc8fb..d3070d02 100644 --- a/examples/docs/methods/code_constructs/Makefile +++ b/examples/docs/methods/code_constructs/Makefile @@ -9,6 +9,7 @@ build: make -C inheritance build make -C immediate_object build make -C object_type build + make -C coercion build clean: rm -f *~ *.cm* *.o *.obj @@ -18,4 +19,5 @@ clean: make -C inheritance clean make -C immediate_object clean make -C object_type clean + make -C coercion clean diff --git a/examples/docs/methods/code_constructs/coercion/Makefile b/examples/docs/methods/code_constructs/coercion/Makefile new file mode 100644 index 00000000..cb75cadf --- /dev/null +++ b/examples/docs/methods/code_constructs/coercion/Makefile @@ -0,0 +1,12 @@ +SRC:=coercion_lib.mli coercion_lib.ml coercion_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/code_constructs/coercion/coercion_bin.ml b/examples/docs/methods/code_constructs/coercion/coercion_bin.ml new file mode 100644 index 00000000..757b26da --- /dev/null +++ b/examples/docs/methods/code_constructs/coercion/coercion_bin.ml @@ -0,0 +1,6 @@ +(* coercion_bin.ml *) +open Coercion_lib + +let () = + let _coerce = (obj :> < used_by_requirement : unit >) in + () diff --git a/examples/docs/methods/code_constructs/coercion/coercion_lib.ml b/examples/docs/methods/code_constructs/coercion/coercion_lib.ml new file mode 100644 index 00000000..6295cfb6 --- /dev/null +++ b/examples/docs/methods/code_constructs/coercion/coercion_lib.ml @@ -0,0 +1,6 @@ +(* coercion_lib.ml *) +let obj = + object + method used_by_requirement = () + method unused = () + end diff --git a/examples/docs/methods/code_constructs/coercion/coercion_lib.mli b/examples/docs/methods/code_constructs/coercion/coercion_lib.mli new file mode 100644 index 00000000..920bfe09 --- /dev/null +++ b/examples/docs/methods/code_constructs/coercion/coercion_lib.mli @@ -0,0 +1,5 @@ +(* coercion_lib.mli *) +val obj : + < used_by_requirement : unit + ; unused : unit + > From 79544cf88c119b29176ee56af0b9c68b7848659f Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Tue, 24 Mar 2026 16:25:17 +0100 Subject: [PATCH 12/13] [docs][methods][12/n] add factory example and limitation This shows that analyzing objects produced by factory functions is the same as considering the function as its resulting object. --- check/classic/classic.exp | 14 ++ check/classic/classic.ref | 22 ++- check/internal/internal.exp | 14 ++ check/internal/internal.ref | 22 ++- check/threshold-1/threshold-1.exp | 20 +++ check/threshold-1/threshold-1.ref | 28 +++- check/threshold-3-0.5/threshold-3-0.5.exp | 22 +++ check/threshold-3-0.5/threshold-3-0.5.ref | 30 +++- docs/methods/METHODS.md | 85 ++++++++++++ docs/methods/code_constructs/FACTORY_FUN.md | 128 ++++++++++++++++++ .../docs/methods/code_constructs/Makefile | 2 + .../code_constructs/factory_fun/Makefile | 12 ++ .../factory_fun/factory_fun_bin.ml | 15 ++ .../factory_fun/factory_fun_lib.ml | 16 +++ .../factory_fun/factory_fun_lib.mli | 8 ++ examples/docs/methods/limitations/Makefile | 2 + .../limitations/factory_fun_indir/Makefile | 12 ++ .../factory_fun_indir/factory_fun_indir.ml | 13 ++ 18 files changed, 449 insertions(+), 16 deletions(-) create mode 100644 docs/methods/code_constructs/FACTORY_FUN.md create mode 100644 examples/docs/methods/code_constructs/factory_fun/Makefile create mode 100644 examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml create mode 100644 examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.ml create mode 100644 examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli create mode 100644 examples/docs/methods/limitations/factory_fun_indir/Makefile create mode 100644 examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml diff --git a/check/classic/classic.exp b/check/classic/classic.exp index a58e920e..28001661 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -25,8 +25,13 @@ ./examples/docs/exported_values/hello_world/hello_world_with_intf.mli:3: goodbye ./examples/docs/exported_values/hello_world/hello_world_with_intf.mli:4: world +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:3: internally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:38: internally_used_f @@ -156,6 +161,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory#unused_method +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -163,6 +171,9 @@ Nothing else to report in this section ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory#m + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -588,6 +599,9 @@ Nothing else to report in this section ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:3: let x = ... in x (=> useless binding) +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:12: let x = ... in x (=> useless binding) + ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: let () = ... in ... (=> use sequence) ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: unit pattern unit_binding ./examples/using_dune/preprocessed_lib/preprocessed.ml:84: val f: ... -> (... -> ?_:_ -> ...) -> ... diff --git a/check/classic/classic.ref b/check/classic/classic.ref index e633c81e..74d18a7c 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -30,8 +30,13 @@ ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:40: new_method: Should not be detected ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:41: public_method_label: Should not be detected ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:3: internally_used ./examples/using_dune/preprocessed_lib/preprocessed.mli:38: internally_used_f @@ -161,6 +166,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory#unused_method +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -168,6 +176,9 @@ Nothing else to report in this section ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m: Not detected +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory#m + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -593,6 +604,9 @@ Nothing else to report in this section ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:3: let x = ... in x (=> useless binding) +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:12: let x = ... in x (=> useless binding) + ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: let () = ... in ... (=> use sequence) ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: unit pattern unit_binding ./examples/using_dune/preprocessed_lib/preprocessed.ml:84: val f: ... -> (... -> ?_:_ -> ...) -> ... @@ -640,7 +654,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 547 -Success: 541 -Failed: 6 -Ratio: 98.9031078611% +Total: 556 +Success: 549 +Failed: 7 +Ratio: 98.7410071942% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index 56ffb3fc..d4bc81aa 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -15,8 +15,13 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -111,6 +116,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory#unused_method +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -118,6 +126,9 @@ Nothing else to report in this section ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory#m + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -543,6 +554,9 @@ Nothing else to report in this section ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:3: let x = ... in x (=> useless binding) +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:12: let x = ... in x (=> useless binding) + ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: let () = ... in ... (=> use sequence) ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: unit pattern unit_binding ./examples/using_dune/preprocessed_lib/preprocessed.ml:84: val f: ... -> (... -> ?_:_ -> ...) -> ... diff --git a/check/internal/internal.ref b/check/internal/internal.ref index 18a3e7b4..ca9af38d 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -20,8 +20,13 @@ ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:40: new_method: Should not be detected ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:41: public_method_label: Should not be detected ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -116,6 +121,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory#unused_method +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -123,6 +131,9 @@ Nothing else to report in this section ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m: Not detected +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory#m + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -548,6 +559,9 @@ Nothing else to report in this section ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:3: let x = ... in x (=> useless binding) +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:12: let x = ... in x (=> useless binding) + ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: let () = ... in ... (=> use sequence) ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: unit pattern unit_binding ./examples/using_dune/preprocessed_lib/preprocessed.ml:84: val f: ... -> (... -> ?_:_ -> ...) -> ... @@ -595,7 +609,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 505 -Success: 499 -Failed: 6 -Ratio: 98.8118811881% +Total: 514 +Success: 507 +Failed: 7 +Ratio: 98.6381322957% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index 2382dec9..8b3e85cc 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -15,8 +15,13 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -143,6 +148,8 @@ ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times @@ -362,6 +369,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory#unused_method +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -369,6 +379,9 @@ Nothing else to report in this section ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory#m + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -439,6 +452,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#peek +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#pop +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push @@ -954,6 +971,9 @@ Nothing else to report in this section ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:3: let x = ... in x (=> useless binding) +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:12: let x = ... in x (=> useless binding) + ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: let () = ... in ... (=> use sequence) ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: unit pattern unit_binding ./examples/using_dune/preprocessed_lib/preprocessed.ml:84: val f: ... -> (... -> ?_:_ -> ...) -> ... diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index ffbe7229..1aaee288 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -20,8 +20,13 @@ ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:40: new_method: Should not be detected ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:41: public_method_label: Should not be detected ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -148,6 +153,8 @@ ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times @@ -367,6 +374,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory#unused_method +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -374,6 +384,9 @@ Nothing else to report in this section ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m: Not detected +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory#m + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -444,6 +457,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#peek +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#pop +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push @@ -958,6 +975,9 @@ Nothing else to report in this section ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:3: let x = ... in x (=> useless binding) +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:12: let x = ... in x (=> useless binding) + ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: let () = ... in ... (=> use sequence) ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: unit pattern unit_binding ./examples/using_dune/preprocessed_lib/preprocessed.ml:84: val f: ... -> (... -> ?_:_ -> ...) -> ... @@ -1005,7 +1025,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 857 -Success: 850 -Failed: 7 -Ratio: 99.1831971995% +Total: 870 +Success: 862 +Failed: 8 +Ratio: 99.0804597701% 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 6692f275..4c14e2d7 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -15,8 +15,13 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -143,6 +148,8 @@ ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times @@ -465,6 +472,8 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./examples/docs/methods/code_constructs/class_type/class_type_lib.mli:10: int_stack +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack ./examples/docs/methods/code_constructs/object_type/object_type_lib.mli:9: int_stack @@ -498,6 +507,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory#unused_method +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -505,6 +517,9 @@ Nothing else to report in this section ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory#m + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -575,6 +590,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#peek +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#pop +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push @@ -1351,6 +1370,9 @@ Nothing else to report in this section ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:3: let x = ... in x (=> useless binding) +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:12: let x = ... in x (=> useless binding) + ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: let () = ... in ... (=> use sequence) ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: unit pattern unit_binding ./examples/using_dune/preprocessed_lib/preprocessed.ml:84: val f: ... -> (... -> ?_:_ -> ...) -> ... 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 2d3168f1..9f436cd8 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -20,8 +20,13 @@ ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:40: new_method: Should not be detected ./examples/docs/exported_values/limitations/incl_same_name/oo.mli:41: public_method_label: Should not be detected ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory + ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -148,6 +153,8 @@ ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:4: push_n_times + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:4: push_n_times ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times @@ -470,6 +477,8 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./examples/docs/methods/code_constructs/class_type/class_type_lib.mli:10: int_stack +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack ./examples/docs/methods/code_constructs/object_type/object_type_lib.mli:9: int_stack @@ -503,6 +512,9 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:2: unused_class#unused_method ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#reset +./examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory#unused_method +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#reset + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_bin.ml:2: unused_obj#unused_method ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#reset @@ -510,6 +522,9 @@ Nothing else to report in this section ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m: Not detected +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory#m + ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:12: immediate#unused @@ -580,6 +595,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/constructor/constructor_lib.mli:2: int_stack#push +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#peek +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#pop +./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#push + ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#peek ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#pop ./examples/docs/methods/code_constructs/immediate_object/immediate_object_lib.mli:2: int_stack#push @@ -1355,6 +1374,9 @@ Nothing else to report in this section ./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:3: let x = ... in x (=> useless binding) +./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:12: let x = ... in x (=> useless binding) + ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: let () = ... in ... (=> use sequence) ./examples/using_dune/preprocessed_lib/preprocessed.ml:83: unit pattern unit_binding ./examples/using_dune/preprocessed_lib/preprocessed.ml:84: val f: ... -> (... -> ?_:_ -> ...) -> ... @@ -1402,7 +1424,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1173 -Success: 1166 -Failed: 7 -Ratio: 99.4032395567% +Total: 1187 +Success: 1179 +Failed: 8 +Ratio: 99.3260320135% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index bb79f3bd..f0060516 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -10,6 +10,7 @@ +[Class type](#class-type) +[Object type](#object-type) +[Alias](#alias) + +[Factory function](#factory-function) # Methods @@ -145,6 +146,7 @@ from the `.mli` if there is one and the `.ml`. - [Class type](./code_constructs/CLASS_TYPE.md) - [Inheritance](./code_constructs/INHERITANCE.md) - [Immediate object](./code_constructs/IMMEDIATE_OBJECT.md) + - [Factory function](./code_constructs/FACTORY_FUN.md) - [Object type](./code_constructs/OBJECT_TYPE.md) - [Coercion](./code_constructs/COERCION.md) @@ -255,3 +257,86 @@ make: Leaving directory '/tmp/docs/methods/limitations/alias' The analyzer reports `original#used_by_alias` although it is used by `alias#used_by_alias`. + +## Factory function + +Related issue : +[issue #67](https://github.com/LexiFi/dead_code_analyzer/issues/67). + +Factory functions' methods analysis is currently very limited to situations like +the one in the [Factory function](./code_constructs/FACTORY_FUN.md) example : +functions without intermediate binding to the returned object in at least one +branch. I.e. if in all the branches, the result object is bound to a name, then +the analyzer fails to track its methods. This leads to **false negatives**. + +### Example + +The reference files for this example are in the +[factory\_fun\_indir](../../examples/docs/methods/limitations/factory_fun_indir) directory. + +The reference takes place in `/tmp/docs/methods/limitations`, which +is a copy of the [limitations](../../../examples/docs/methods/limitations) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C factory_fun_indir build +``` + +The analysis command is : +``` +make -C factory_fun_indir analyze +``` + +The compile + analyze command is : +``` +make -C factory_fun_indir +``` + +Code: +```OCaml +(* factoy_fun_indir.ml *) +let factory_with_intermediate_binding () = + let res = + object method m = () end + in + res + +let random_factory () = + if Random.bool () then + object method m = () end + else + let res = object method m = () end in + res +``` + +Compile and analyze: +``` +$ make -C factory_fun_indir +make: Entering directory '/tmp/docs/methods/limitations/factory_fun_indir' +ocamlopt -bin-annot factory_fun_indir.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= +/tmp/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:8: random_factory#m + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/limitations/factory_fun_indir' +``` + +The analyzer correctly reports `random_factory#m` because its last expression in +the `if` branch is the object's definition. It does not report +`factory_with_intermediate_binding#m` because the returned object is bound +inside the function. + +> [!NOTE] +> The analyzer does not distinguish which object is actually returned when there +> are alternatives like in `random_factory`. Only uses outside of the function +> are accounted for. E.g. using `res#m` in the `else` branch does not count. diff --git a/docs/methods/code_constructs/FACTORY_FUN.md b/docs/methods/code_constructs/FACTORY_FUN.md new file mode 100644 index 00000000..bffaf5ac --- /dev/null +++ b/docs/methods/code_constructs/FACTORY_FUN.md @@ -0,0 +1,128 @@ +The reference files for this example are in the +[factory_fun](../../../examples/docs/methods/code_constructs/factory_fun) directory. + +The reference takes place in `/tmp/docs/methods/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/methods/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C factory_fun build +``` + +The analysis command is : +``` +make -C factory_fun analyze +``` + +The compile + analyze command is : +``` +make -C factory_fun +``` + +> [!IMPORTANT] +> **LIMITATION** +> +> Only factory functions that return the object without intermediate binding +> in at least one branch are understood by the analyzer. This may lead to +> **false negatives**. +> See [Factory function | Limitations](../METHODS.md#factory-function). +> +> Storing the result of a factory function in a new binding breaks the analysis. +> Although 2 calls to the same factory function may produce different objects, +> they are considered to be the same by the analyzer. Hence, storing the result +> in a new binding is similar to an alias, which may lead to **false positives**. +> See [Alias | Limitations](../METHODS.md#alias) + +## First run + +Code: +```OCaml +(* factoy_fun_lib.mli *) +val get_stack : + unit -> + < push : int -> unit + ; pop : unit + ; peek : int option + ; reset : unit + > +``` +```OCaml +(* factoy_fun_lib.ml *) +let stack = ref [] + +let get_stack () = + object + method push x = stack := x::!stack + method pop = + match !stack with + | [] -> () + | _::tl -> stack := tl + method peek = + match !stack with + | [] -> None + | hd::_ -> Some hd + method reset = stack := [] + end +``` +```OCaml +(* factoy_fun_bin.ml *) +let unused_factory () = object method unused_method = () end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let open Factory_fun_lib in + let n = 42 in + push_n_times n (get_stack ()); + while (get_stack ())#peek <> None do + (get_stack ())#pop; + done +``` + +Before looking at the analysis results, let's look at the code. + +The `Factory_fun_lib` declares and exports 1 factory function `get_stack` which +takes `unit` as parameter and returns a fresh object. The return object has +4 methods, manipulating the unexported value `stack`. +1 of these methods is used by requirement : `push`. +2 of these methods are explicitly referenced : `peek`, and `pop`. +This leaves `reset` as unused. + +The `Factory_fun_bin` declares and exports 1 factory function `unused_factory` +which takes `unit` as parameter and returns a fresh object with one method +`unused_method`. This function is unused, leaving its method unused too. + +Compile and analyze: +``` +$ make -C factory_fun +make: Entering directory '/tmp/docs/methods/code_constructs/factory_fun' +ocamlopt -bin-annot factory_fun_lib.mli factory_fun_lib.ml factory_fun_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= +/tmp/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml:2: unused_factory#unused_method +/tmp/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack#reset + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_constructs/factory_fun' +``` + +As expected, the analyzer reports `unused_factory#unused_method` and +`get_stack#reset` as unused. Following the report line format +`filepath:line: source#method`, here the sources are the functions themselves. +Indeed, the returned objects are defined as the immediate results of the +functions, making the functions behave similarly to class constructors. + +The reported methods can be removed from the `.mli` and `.ml`. +Our work here is done. diff --git a/examples/docs/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile index d3070d02..c56f58ad 100644 --- a/examples/docs/methods/code_constructs/Makefile +++ b/examples/docs/methods/code_constructs/Makefile @@ -8,6 +8,7 @@ build: make -C class_type build make -C inheritance build make -C immediate_object build + make -C factory_fun build make -C object_type build make -C coercion build @@ -18,6 +19,7 @@ clean: make -C class_type clean make -C inheritance clean make -C immediate_object clean + make -C factory_fun clean make -C object_type clean make -C coercion clean diff --git a/examples/docs/methods/code_constructs/factory_fun/Makefile b/examples/docs/methods/code_constructs/factory_fun/Makefile new file mode 100644 index 00000000..78329836 --- /dev/null +++ b/examples/docs/methods/code_constructs/factory_fun/Makefile @@ -0,0 +1,12 @@ +SRC:=factory_fun_lib.mli factory_fun_lib.ml factory_fun_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml b/examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml new file mode 100644 index 00000000..d30aafa1 --- /dev/null +++ b/examples/docs/methods/code_constructs/factory_fun/factory_fun_bin.ml @@ -0,0 +1,15 @@ +(* factoy_fun_bin.ml *) +let unused_factory () = object method unused_method = () end + +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let open Factory_fun_lib in + let n = 42 in + push_n_times n (get_stack ()); + while (get_stack ())#peek <> None do + (get_stack ())#pop; + done diff --git a/examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.ml b/examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.ml new file mode 100644 index 00000000..cf79464b --- /dev/null +++ b/examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.ml @@ -0,0 +1,16 @@ +(* factoy_fun_lib.ml *) +let stack = ref [] + +let get_stack () = + object + method push x = stack := x::!stack + method pop = + match !stack with + | [] -> () + | _::tl -> stack := tl + method peek = + match !stack with + | [] -> None + | hd::_ -> Some hd + method reset = stack := [] + end diff --git a/examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli b/examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli new file mode 100644 index 00000000..42fd5287 --- /dev/null +++ b/examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli @@ -0,0 +1,8 @@ +(* factoy_fun_lib.mli *) +val get_stack : + unit -> + < push : int -> unit + ; pop : unit + ; peek : int option + ; reset : unit + > diff --git a/examples/docs/methods/limitations/Makefile b/examples/docs/methods/limitations/Makefile index e0b60d24..1123cd42 100644 --- a/examples/docs/methods/limitations/Makefile +++ b/examples/docs/methods/limitations/Makefile @@ -4,8 +4,10 @@ all: build build: make -C alias build + make -C factory_fun_indir build clean: rm -f *~ *.cm* *.o *.obj make -C alias clean + make -C factory_fun_indir clean diff --git a/examples/docs/methods/limitations/factory_fun_indir/Makefile b/examples/docs/methods/limitations/factory_fun_indir/Makefile new file mode 100644 index 00000000..0b8d6204 --- /dev/null +++ b/examples/docs/methods/limitations/factory_fun_indir/Makefile @@ -0,0 +1,12 @@ +SRC:=factory_fun_indir.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml b/examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml new file mode 100644 index 00000000..1c1961fa --- /dev/null +++ b/examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml @@ -0,0 +1,13 @@ +(* factoy_fun_indir.ml *) +let factory_with_intermediate_binding () = + let res = + object method unused_method = () end + in + res + +let random_factory () = + if Random.bool () then + object method m = () end + else + let res = object method m = () end in + res From 7c62ec1b636227b1a2dd8496acdeaad49e319d2c Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Tue, 24 Mar 2026 18:50:19 +0100 Subject: [PATCH 13/13] [docs][methods][13/n] add polymorphic class example This is the same as the class example with a polymorphic stack and without the unnecessary classes. --- check/classic/classic.exp | 2 + check/classic/classic.ref | 8 +- check/internal/internal.exp | 2 + check/internal/internal.ref | 8 +- check/threshold-1/threshold-1.exp | 8 ++ check/threshold-1/threshold-1.ref | 14 ++- check/threshold-3-0.5/threshold-3-0.5.exp | 8 ++ check/threshold-3-0.5/threshold-3-0.5.ref | 14 ++- docs/methods/METHODS.md | 1 + .../code_constructs/POLYMORPHIC_CLASS.md | 106 ++++++++++++++++++ .../docs/methods/code_constructs/Makefile | 2 + .../polymorphic_class/Makefile | 12 ++ .../polymorphic_class_bin.ml | 13 +++ .../polymorphic_class_lib.ml | 15 +++ .../polymorphic_class_lib.mli | 8 ++ 15 files changed, 209 insertions(+), 12 deletions(-) create mode 100644 docs/methods/code_constructs/POLYMORPHIC_CLASS.md create mode 100644 examples/docs/methods/code_constructs/polymorphic_class/Makefile create mode 100644 examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_bin.ml create mode 100644 examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.ml create mode 100644 examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli diff --git a/check/classic/classic.exp b/check/classic/classic.exp index 28001661..dd991654 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -169,6 +169,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#reset + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m diff --git a/check/classic/classic.ref b/check/classic/classic.ref index 74d18a7c..093c0b1d 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -174,6 +174,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#reset + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected ./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m: Not detected @@ -654,7 +656,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 556 -Success: 549 +Total: 557 +Success: 550 Failed: 7 -Ratio: 98.7410071942% +Ratio: 98.7432675045% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index d4bc81aa..e6137438 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -124,6 +124,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#reset + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m diff --git a/check/internal/internal.ref b/check/internal/internal.ref index ca9af38d..5ba89818 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -129,6 +129,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#reset + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected ./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m: Not detected @@ -609,7 +611,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 514 -Success: 507 +Total: 515 +Success: 508 Failed: 7 -Ratio: 98.6381322957% +Ratio: 98.640776699% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index 8b3e85cc..a330fc91 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -154,6 +154,8 @@ ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_bin.ml:2: push_n_times + ./examples/docs/methods/limitations/alias/alias_lib.mli:8: alias ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -377,6 +379,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#reset + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m @@ -463,6 +467,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#peek +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#pop +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#push + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 1aaee288..ce484c1c 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -159,6 +159,8 @@ ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_bin.ml:2: push_n_times + ./examples/docs/methods/limitations/alias/alias_lib.mli:8: alias ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -382,6 +384,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#reset + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected ./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m: Not detected @@ -468,6 +472,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#peek +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#pop +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#push + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Not detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used @@ -1025,7 +1033,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 870 -Success: 862 +Total: 875 +Success: 867 Failed: 8 -Ratio: 99.0804597701% +Ratio: 99.0857142857% 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 4c14e2d7..8992101b 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -154,6 +154,8 @@ ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_bin.ml:2: push_n_times + ./examples/docs/methods/limitations/alias/alias_lib.mli:8: alias ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -515,6 +517,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#reset + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m @@ -601,6 +605,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#peek +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#pop +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#push + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias 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 9f436cd8..ffdf5ab0 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -159,6 +159,8 @@ ./examples/docs/methods/code_constructs/object_type/object_type_bin.ml:4: push_n_times +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_bin.ml:2: push_n_times + ./examples/docs/methods/limitations/alias/alias_lib.mli:8: alias ./examples/using_dune/bin/use_preprocessed_lib/use_preprocessed.mli:1: mark_used @@ -520,6 +522,8 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#unused +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#reset + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#unused ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Should not be detected ./examples/docs/methods/limitations/factory_fun_indir/factory_fun_indir.ml:2: factory_with_intermediate_binding#m: Not detected @@ -606,6 +610,10 @@ Nothing else to report in this section ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used ./examples/docs/methods/code_constructs/inheritance/inheritance_lib.mli:2: parent#used_by_child +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#peek +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#pop +./examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#push + ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used ./examples/docs/methods/limitations/alias/alias_lib.mli:2: original#used_by_alias: Not detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:6: immediate#externally_used @@ -1424,7 +1432,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1187 -Success: 1179 +Total: 1192 +Success: 1184 Failed: 8 -Ratio: 99.3260320135% +Ratio: 99.3288590604% diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index f0060516..1ad372f9 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -142,6 +142,7 @@ from the `.mli` if there is one and the `.ml`. - The [code constructs](./code_constructs) directory contains a collection of examples dedicated to specific code constructs : - [Class](./code_constructs/CLASS.md) + - [Polymorphic class](./code_constructs/CLASS.md) - [Constructor](./code_constructs/CONSTRUCTOR.md) - [Class type](./code_constructs/CLASS_TYPE.md) - [Inheritance](./code_constructs/INHERITANCE.md) diff --git a/docs/methods/code_constructs/POLYMORPHIC_CLASS.md b/docs/methods/code_constructs/POLYMORPHIC_CLASS.md new file mode 100644 index 00000000..a59b2eb1 --- /dev/null +++ b/docs/methods/code_constructs/POLYMORPHIC_CLASS.md @@ -0,0 +1,106 @@ +The reference files for this example are in the +[polymorphic\_class](../../../examples/docs/methods/code_constructs/polymorphic_class) directory. + +The reference takes place in `/tmp/docs/methods/code_constructs`, which +is a copy of the [code\_constructs](../../../examples/docs/methods/code_constructs) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C polymorphic_class build +``` + +The analysis command is : +``` +make -C polymorphic_class analyze +``` + +The compile + analyze command is : +``` +make -C polymorphic_class +``` + +## First run + +Code: +```OCaml +(* polymorphic_class_lib.mli *) +class ['a] stack : + object + method push : 'a -> unit + method pop : unit + method peek : 'a option + method reset : unit + end +``` +```OCaml +(* polymorphic_class_lib.ml *) +class ['a] stack = + object + val mutable l : 'a list = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end +``` +```OCaml +(* polymorphic_class_bin.ml *) +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let int_stack = new Polymorphic_class_lib.stack in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done +``` + +Before looking at the analysis results, let's look at the code. + +This example is very similar to the [Class](./CLASS.md) example, without the +`unused_class` class. Instead of using an definitive `int_stack` class, the +`Polymorphic_class_lib` defines a polymorphic `['a] stack` class. + +Methods `push`, `peek`, and `pop` are used, leaving `reset` as the only unused method. + +Compile and analyze: +``` +$ make -C polymorphic_class/ +make: Entering directory '/tmp/docs/methods/code_constructs/polymorphic_class' +ocamlopt -bin-annot polymorphic_class_lib.mli polymorphic_class_lib.ml polymorphic_class_bin.ml +dead_code_analyzer --nothing -M all . +Scanning files... + [DONE] + +.> UNUSED METHODS: +================= +/tmp/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli:2: stack#reset + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/methods/code_constructs/polymorphic_class' +``` + +As expected, the analyzer reports `stack#reset` as unused. + +> [!NOTE] +> The analyzer does not specify the type parameter of `stack`. This is because +> it does not distinguish the monomorphizations of `stack` and its polymoprhic +> definition. + +After removing the reported unused methods, the analyzer will not find anymore +unused method. Our work here is done. diff --git a/examples/docs/methods/code_constructs/Makefile b/examples/docs/methods/code_constructs/Makefile index c56f58ad..33cff97b 100644 --- a/examples/docs/methods/code_constructs/Makefile +++ b/examples/docs/methods/code_constructs/Makefile @@ -4,6 +4,7 @@ all: build build: make -C class build + make -C polymorphic_class build make -C constructor build make -C class_type build make -C inheritance build @@ -15,6 +16,7 @@ build: clean: rm -f *~ *.cm* *.o *.obj make -C class clean + make -C polymorphic_class clean make -C constructor clean make -C class_type clean make -C inheritance clean diff --git a/examples/docs/methods/code_constructs/polymorphic_class/Makefile b/examples/docs/methods/code_constructs/polymorphic_class/Makefile new file mode 100644 index 00000000..8e6af3f1 --- /dev/null +++ b/examples/docs/methods/code_constructs/polymorphic_class/Makefile @@ -0,0 +1,12 @@ +SRC:=polymorphic_class_lib.mli polymorphic_class_lib.ml polymorphic_class_bin.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -M all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_bin.ml b/examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_bin.ml new file mode 100644 index 00000000..e0809bff --- /dev/null +++ b/examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_bin.ml @@ -0,0 +1,13 @@ +(* polymorphic_class_bin.ml *) +let push_n_times n stack = + for i = 1 to n do + stack#push i; + done + +let () = + let int_stack = new Polymorphic_class_lib.stack in + let n = 42 in + push_n_times n int_stack; + while int_stack#peek <> None do + int_stack#pop; + done diff --git a/examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.ml b/examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.ml new file mode 100644 index 00000000..efeaa52d --- /dev/null +++ b/examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.ml @@ -0,0 +1,15 @@ +(* polymorphic_class_lib.ml *) +class ['a] stack = + object + val mutable l : 'a list = [] + method push x = l <- x::l + method pop = + match l with + | [] -> () + | _::tl -> l <- tl + method peek = + match l with + | [] -> None + | hd::_ -> Some hd + method reset = l <- [] + end diff --git a/examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli b/examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli new file mode 100644 index 00000000..d91c0c48 --- /dev/null +++ b/examples/docs/methods/code_constructs/polymorphic_class/polymorphic_class_lib.mli @@ -0,0 +1,8 @@ +(* polymorphic_class_lib.mli *) +class ['a] stack : + object + method push : 'a -> unit + method pop : unit + method peek : 'a option + method reset : unit + end