From 83a3ab6e402642229d5ed52d202f1b25ccc4fc87 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Fri, 18 Sep 2026 13:53:18 +0200 Subject: [PATCH 1/3] [src][deadObj] stop tracking methods of classes with class types as signatures This is supposed to be the behavior according to the documentation and some legacy tests were actually expecting the wrong results according it. The tests are now fixed to fit the described semantics and `DeadObj.collect_export` too. NB: class types have a restriction similar to module types. --- 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 | 7 ------- check/threshold-3-0.5/threshold-3-0.5.ref | 13 +++---------- src/deadObj.ml | 13 +++++++------ 9 files changed, 19 insertions(+), 50 deletions(-) diff --git a/check/classic/classic.exp b/check/classic/classic.exp index 9326ee3c..2470fa69 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -236,8 +236,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#h ./examples/using_make/obj/class_type.mli:9: c#h -./examples/using_make/obj/coerce.mli:6: p#f -./examples/using_make/obj/coerce.mli:6: p#h ./examples/using_make/obj/constraint.ml:1: p#g ./examples/using_make/obj/fooCl.mli:1: p1#g ./examples/using_make/obj/fooCl.mli:1: p1#h diff --git a/check/classic/classic.ref b/check/classic/classic.ref index 3b3d0c5b..8edc44ad 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -236,8 +236,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#h ./examples/using_make/obj/class_type.mli:9: c#h -./examples/using_make/obj/coerce.mli:6: p#f -./examples/using_make/obj/coerce.mli:6: p#h ./examples/using_make/obj/constraint.ml:1: p#g ./examples/using_make/obj/fooCl.mli:1: p1#g ./examples/using_make/obj/fooCl.mli:1: p1#h @@ -770,7 +768,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 641 -Success: 635 +Total: 639 +Success: 633 Failed: 6 -Ratio: 99.0639625585% +Ratio: 99.0610328638% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index 5435b5b1..b10343a6 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -188,8 +188,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#h ./examples/using_make/obj/class_type.mli:9: c#h -./examples/using_make/obj/coerce.mli:6: p#f -./examples/using_make/obj/coerce.mli:6: p#h ./examples/using_make/obj/constraint.ml:1: p#g ./examples/using_make/obj/fooCl.mli:1: p1#g ./examples/using_make/obj/fooCl.mli:1: p1#h diff --git a/check/internal/internal.ref b/check/internal/internal.ref index 6219ff7c..dc25bb84 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -188,8 +188,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#h ./examples/using_make/obj/class_type.mli:9: c#h -./examples/using_make/obj/coerce.mli:6: p#f -./examples/using_make/obj/coerce.mli:6: p#h ./examples/using_make/obj/constraint.ml:1: p#g ./examples/using_make/obj/fooCl.mli:1: p1#g ./examples/using_make/obj/fooCl.mli:1: p1#h @@ -722,7 +720,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 597 -Success: 591 +Total: 595 +Success: 589 Failed: 6 -Ratio: 98.9949748744% +Ratio: 98.9915966387% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index 5fd52d3d..a7c9c50f 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -482,8 +482,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#h ./examples/using_make/obj/class_type.mli:9: c#h -./examples/using_make/obj/coerce.mli:6: p#f -./examples/using_make/obj/coerce.mli:6: p#h ./examples/using_make/obj/constraint.ml:1: p#g ./examples/using_make/obj/fooCl.mli:1: p1#g ./examples/using_make/obj/fooCl.mli:1: p1#h @@ -576,9 +574,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#f ./examples/using_make/obj/class.mli:1: c#g -./examples/using_make/obj/class_type.mli:7: p#f -./examples/using_make/obj/class_type.mli:7: p#h -./examples/using_make/obj/coerce.mli:8: c#h ./examples/using_make/obj/constraint.ml:1: p#f ./examples/using_make/obj/depend.ml:8: M.c#f ./examples/using_make/obj/fooCl.mli:1: p1#f diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 69746819..52b08821 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -482,8 +482,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#h ./examples/using_make/obj/class_type.mli:9: c#h -./examples/using_make/obj/coerce.mli:6: p#f -./examples/using_make/obj/coerce.mli:6: p#h ./examples/using_make/obj/constraint.ml:1: p#g ./examples/using_make/obj/fooCl.mli:1: p1#g ./examples/using_make/obj/fooCl.mli:1: p1#h @@ -576,9 +574,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#f ./examples/using_make/obj/class.mli:1: c#g -./examples/using_make/obj/class_type.mli:7: p#f -./examples/using_make/obj/class_type.mli:7: p#h -./examples/using_make/obj/coerce.mli:8: c#h ./examples/using_make/obj/constraint.ml:1: p#f ./examples/using_make/obj/depend.ml:8: M.c#f ./examples/using_make/obj/fooCl.mli:1: p1#f @@ -1250,7 +1245,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1039 -Success: 1033 +Total: 1034 +Success: 1028 Failed: 6 -Ratio: 99.4225216554% +Ratio: 99.419729207% 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 7cd2c3d0..f4667732 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -625,8 +625,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#h ./examples/using_make/obj/class_type.mli:9: c#h -./examples/using_make/obj/coerce.mli:6: p#f -./examples/using_make/obj/coerce.mli:6: p#h ./examples/using_make/obj/constraint.ml:1: p#g ./examples/using_make/obj/fooCl.mli:1: p1#g ./examples/using_make/obj/fooCl.mli:1: p1#h @@ -719,9 +717,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#f ./examples/using_make/obj/class.mli:1: c#g -./examples/using_make/obj/class_type.mli:7: p#f -./examples/using_make/obj/class_type.mli:7: p#h -./examples/using_make/obj/coerce.mli:8: c#h ./examples/using_make/obj/constraint.ml:1: p#f ./examples/using_make/obj/depend.ml:8: M.c#f ./examples/using_make/obj/fooCl.mli:1: p1#f @@ -772,8 +767,6 @@ Nothing else to report in this section ./examples/using_dune/wrapped_lib/obj/without_class.mli:11: factory#used_fun ./examples/using_dune/wrapped_lib/obj/without_class.mli:11: factory#used_int -./examples/using_make/obj/class_type.mli:7: p#g -./examples/using_make/obj/coerce.mli:8: c#f ./examples/using_make/obj/named.mli:1: p1#f ./examples/using_make/obj/obj_inher.ml:1: c#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 b1bacdd1..d1ce0dde 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -625,8 +625,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#h ./examples/using_make/obj/class_type.mli:9: c#h -./examples/using_make/obj/coerce.mli:6: p#f -./examples/using_make/obj/coerce.mli:6: p#h ./examples/using_make/obj/constraint.ml:1: p#g ./examples/using_make/obj/fooCl.mli:1: p1#g ./examples/using_make/obj/fooCl.mli:1: p1#h @@ -719,9 +717,6 @@ Nothing else to report in this section ./examples/using_make/obj/class.mli:1: c#f ./examples/using_make/obj/class.mli:1: c#g -./examples/using_make/obj/class_type.mli:7: p#f -./examples/using_make/obj/class_type.mli:7: p#h -./examples/using_make/obj/coerce.mli:8: c#h ./examples/using_make/obj/constraint.ml:1: p#f ./examples/using_make/obj/depend.ml:8: M.c#f ./examples/using_make/obj/fooCl.mli:1: p1#f @@ -772,8 +767,6 @@ Nothing else to report in this section ./examples/using_dune/wrapped_lib/obj/without_class.mli:11: factory#used_fun ./examples/using_dune/wrapped_lib/obj/without_class.mli:11: factory#used_int -./examples/using_make/obj/class_type.mli:7: p#g -./examples/using_make/obj/coerce.mli:8: c#f ./examples/using_make/obj/named.mli:1: p1#f ./examples/using_make/obj/obj_inher.ml:1: c#f -------- @@ -1651,7 +1644,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1361 -Success: 1355 +Total: 1354 +Success: 1348 Failed: 6 -Ratio: 99.5591476855% +Ratio: 99.5568685377% diff --git a/src/deadObj.ml b/src/deadObj.ml index b4b9ac37..4de5f342 100644 --- a/src/deadObj.ml +++ b/src/deadObj.ml @@ -126,11 +126,6 @@ let add_equal loc1 loc2 = end -let rec sign = function - | Cty_signature sg -> sg - | Cty_arrow (_, _, t) - | Cty_constr (_, _, t) -> sign t - let rec treat_fields action typ = match get_deep_desc typ with | Tobject (t, _) @@ -204,9 +199,15 @@ let collect_export path u stock ~obj ~cltyp loc = export ~sep:"#" path u stock id loc; in + + let rec sig_self = function + | Cty_signature sg -> Some (sg.csig_self) + | Cty_arrow (_, _, t) -> sig_self t + | Cty_constr _ -> None (* do not track class types' methods *) + in let typ = match cltyp with | None -> obj - | Some cltyp -> Some (sign cltyp).csig_self + | Some cltyp -> sig_self cltyp in match typ with | Some typ -> From 3ca46562503cb5abc21ee8ef5d668f11ae77a06a Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:06:47 +0200 Subject: [PATCH 2/3] [docs][methods] update class_type example Now it includes a class with a class type as signature, identical to the immediate object with class type as signature --- check/threshold-1/threshold-1.exp | 2 - check/threshold-1/threshold-1.ref | 8 ++-- check/threshold-3-0.5/threshold-3-0.5.exp | 6 +-- check/threshold-3-0.5/threshold-3-0.5.ref | 6 +-- docs/methods/code_constructs/CLASS_TYPE.md | 38 ++++++++++++++++--- .../class_type/class_type_bin.ml | 11 ++++++ .../class_type/class_type_lib.ml | 19 +++++++++- .../class_type/class_type_lib.mli | 6 ++- 8 files changed, 74 insertions(+), 22 deletions(-) diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index a7c9c50f..a13c7cd0 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -186,8 +186,6 @@ ./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/coercion/coercion_lib.mli:2: obj ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 52b08821..5b3d2d6e 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -186,8 +186,6 @@ ./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/coercion/coercion_lib.mli:2: obj ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times @@ -1245,7 +1243,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1034 -Success: 1028 +Total: 1033 +Success: 1027 Failed: 6 -Ratio: 99.419729207% +Ratio: 99.4191674734% 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 f4667732..c2ea93ba 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -186,8 +186,6 @@ ./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/coercion/coercion_lib.mli:2: obj ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times @@ -426,6 +424,8 @@ ./examples/docs/methods/code_constructs/alias/alias_lib.mli:2: original +./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times + ./examples/docs/optional_arguments/code_constructs/intext_app/intext_app_lib.mli:2: max ./examples/docs/optional_arguments/code_constructs/intext_app/intext_app_lib.mli:3: min @@ -536,7 +536,7 @@ .>-> 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/class_type/class_type_lib.mli:10: int_stack_o ./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack 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 d1ce0dde..84456521 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -186,8 +186,6 @@ ./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/coercion/coercion_lib.mli:2: obj ./examples/docs/methods/code_constructs/constructor/constructor_bin.ml:4: push_n_times @@ -426,6 +424,8 @@ ./examples/docs/methods/code_constructs/alias/alias_lib.mli:2: original +./examples/docs/methods/code_constructs/class_type/class_type_bin.ml:4: push_n_times + ./examples/docs/optional_arguments/code_constructs/intext_app/intext_app_lib.mli:2: max ./examples/docs/optional_arguments/code_constructs/intext_app/intext_app_lib.mli:3: min @@ -536,7 +536,7 @@ .>-> 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/class_type/class_type_lib.mli:10: int_stack_o ./examples/docs/methods/code_constructs/factory_fun/factory_fun_lib.mli:2: get_stack diff --git a/docs/methods/code_constructs/CLASS_TYPE.md b/docs/methods/code_constructs/CLASS_TYPE.md index 263cb84a..50e78d32 100644 --- a/docs/methods/code_constructs/CLASS_TYPE.md +++ b/docs/methods/code_constructs/CLASS_TYPE.md @@ -32,7 +32,7 @@ make -C class_type Code: ```OCaml (* class_type_lib.mli *) -class type int_stack = +class type int_stack_t = object method push : int -> unit method pop : unit @@ -40,11 +40,13 @@ class type int_stack = method reset : unit end -val int_stack : int_stack +val int_stack_o : int_stack_t + +class int_stack_c : int_stack_t ``` ```OCaml (* class_type_lib.ml *) -class type int_stack = +class type int_stack_t = object method push : int -> unit method pop : unit @@ -52,7 +54,22 @@ class type int_stack = method reset : unit end -let int_stack = +let int_stack_o = + 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 + +class int_stack_c = object val mutable l : int list = [] method push x = l <- x::l @@ -76,9 +93,20 @@ let push_n_times n stack = stack#push i; done +(* test immediate object *) +let () = + let open Class_type_lib in + let n = 42 in + push_n_times n int_stack_o; + while int_stack_o#peek <> None do + int_stack_o#pop; + done + +(* test class *) let () = let open Class_type_lib in let n = 42 in + let int_stack = new int_stack_c in push_n_times n int_stack; while int_stack#peek <> None do int_stack#pop; @@ -86,7 +114,7 @@ let () = ``` By looking at the code, we could make the same observation as in the -[Class](./CLASS.md) example. +[Class](./CLASS.md) and [Immediate Object](./IMMEDIATE_OBJECT.md) examples. However, because of the current limitation on class types, nothing is expected to reported. 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 index d759e973..0f1da518 100644 --- a/examples/docs/methods/code_constructs/class_type/class_type_bin.ml +++ b/examples/docs/methods/code_constructs/class_type/class_type_bin.ml @@ -6,9 +6,20 @@ let push_n_times n stack = stack#push i; done +(* test immediate object *) let () = let open Class_type_lib in let n = 42 in + push_n_times n int_stack_o; + while int_stack_o#peek <> None do + int_stack_o#pop; + done + +(* test class *) +let () = + let open Class_type_lib in + let n = 42 in + let int_stack = new int_stack_c in push_n_times n int_stack; while int_stack#peek <> None do int_stack#pop; 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 index 1dafd2a4..7fd5e4f4 100644 --- a/examples/docs/methods/code_constructs/class_type/class_type_lib.ml +++ b/examples/docs/methods/code_constructs/class_type/class_type_lib.ml @@ -1,5 +1,5 @@ (* class_type_lib.ml *) -class type int_stack = +class type int_stack_t = object method push : int -> unit method pop : unit @@ -7,7 +7,22 @@ class type int_stack = method reset : unit end -let int_stack = +let int_stack_o = + 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 + +class int_stack_c = object val mutable l : int list = [] method push x = l <- x::l 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 index 7d016c4f..c13ffbf5 100644 --- a/examples/docs/methods/code_constructs/class_type/class_type_lib.mli +++ b/examples/docs/methods/code_constructs/class_type/class_type_lib.mli @@ -1,5 +1,5 @@ (* class_type_lib.mli *) -class type int_stack = +class type int_stack_t = object method push : int -> unit method pop : unit @@ -7,4 +7,6 @@ class type int_stack = method reset : unit end -val int_stack : int_stack +val int_stack_o : int_stack_t + +class int_stack_c : int_stack_t From 651225ac68f5ff9fc6fe37715cf0bf1db920d0f7 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:08:46 +0200 Subject: [PATCH 3/3] [docs][methods] fix limitations It was still including the example for the alias limitation, which has been fixed by https://github.com/LexiFi/dead_code_analyzer/pull/98. --- docs/methods/METHODS.md | 84 ----------------------------------------- 1 file changed, 84 deletions(-) diff --git a/docs/methods/METHODS.md b/docs/methods/METHODS.md index b37761f4..8cf634e0 100644 --- a/docs/methods/METHODS.md +++ b/docs/methods/METHODS.md @@ -166,87 +166,3 @@ 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. - -### 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`.