From d3f751d3d9eec2de050e30095b2c31bac5b1ea5a Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Fri, 13 Mar 2026 17:17:01 +0100 Subject: [PATCH 1/8] [check][exp] fix expected results for docs Some values were wrongly expected to be reported as used twice : - Those in `functor_lib.mli` (`External_param.*`) are actually only used once. - Those in `modtyp_lib.mli` (`M_subst.*`) should not be reported at all because they belong to module type `T`. --- check/threshold-1/threshold-1.exp | 2 ++ check/threshold-1/threshold-1.ref | 8 +++++--- check/threshold-3-0.5/threshold-3-0.5.exp | 9 ++------- check/threshold-3-0.5/threshold-3-0.5.ref | 22 +++++++++++----------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index b1c62f3c..612c3f69 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -107,6 +107,8 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:9: F.internally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:14: Internal_param.used_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:15: Internal_param.unused_required +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:24: Internal_app.externally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:25: Internal_app.internally_used diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 13e7d268..96855234 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -108,6 +108,8 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:9: F.internally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:14: Internal_param.used_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:15: Internal_param.unused_required +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required: Not detected +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required: Not detected ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:24: Internal_app.externally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:25: Internal_app.internally_used @@ -950,7 +952,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 821 +Total: 823 Success: 817 -Failed: 4 -Ratio: 99.5127892814% +Failed: 6 +Ratio: 99.2709599028% 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 a587ebad..62b720b8 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -107,6 +107,8 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:9: F.internally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:14: Internal_param.used_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:15: Internal_param.unused_required +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:24: Internal_app.externally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:25: Internal_app.internally_used @@ -334,13 +336,6 @@ .>-> ALMOST UNUSED EXPORTED VALUES: Called 2 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required - -./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.externally_used -./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.internally_used -./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.unused - ./examples/docs/exported_values/hello_world/hello_world_lib.mli:4: world ./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 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 faf280c6..865d10d0 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -108,6 +108,8 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:9: F.internally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:14: Internal_param.used_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:15: Internal_param.unused_required +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required: Not detected +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required: Not detected ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:24: Internal_app.externally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:25: Internal_app.internally_used @@ -338,13 +340,11 @@ .>-> ALMOST UNUSED EXPORTED VALUES: Called 2 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required - -./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.externally_used -./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.internally_used -./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.unused - +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required: Should not be detected +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required: Should not be detected +./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.externally_used: Should not be detected +./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.internally_used: Should not be detected +./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.unused: Should not be detected ./examples/docs/exported_values/hello_world/hello_world_lib.mli:4: world ./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 @@ -1346,7 +1346,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1138 -Success: 1134 -Failed: 4 -Ratio: 99.6485061511% +Total: 1140 +Success: 1129 +Failed: 11 +Ratio: 99.0350877193% From 1025e887752943916e2fa54345ef4d6e88295c9b Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:04:34 +0100 Subject: [PATCH 2/8] [src][deadCode] export at most 1 value per loc This fixes the duplicated reports in case a module is included within its compilation unit (https://github.com/LexiFi/dead_code_analyzer/issues/57). --- check/classic/classic.ref | 7 +++---- check/internal/internal.ref | 7 +++---- check/threshold-1/threshold-1.ref | 10 +++------- check/threshold-3-0.5/threshold-3-0.5.ref | 12 +++--------- src/deadCode.ml | 12 ++++++++++-- 5 files changed, 22 insertions(+), 26 deletions(-) diff --git a/check/classic/classic.ref b/check/classic/classic.ref index bf4b80b1..ed7d193f 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -10,7 +10,6 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:26: Internal_app.unused ./examples/docs/exported_values/code_constructs/include/include_lib.ml:5: Original.unused -./examples/docs/exported_values/code_constructs/include/include_lib.ml:5: Reexport.unused: Should not be detected ./examples/docs/exported_values/code_constructs/include/include_lib.ml:15: Redefine.unused ./examples/docs/exported_values/code_constructs/modsig/modsig_lib.ml:6: Original.unused @@ -617,7 +616,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 531 +Total: 530 Success: 530 -Failed: 1 -Ratio: 99.8116760829% +Failed: 0 +Ratio: 100.% diff --git a/check/internal/internal.ref b/check/internal/internal.ref index f028200a..2168abdf 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -6,7 +6,6 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:26: Internal_app.unused ./examples/docs/exported_values/code_constructs/include/include_lib.ml:5: Original.unused -./examples/docs/exported_values/code_constructs/include/include_lib.ml:5: Reexport.unused: Should not be detected ./examples/docs/exported_values/code_constructs/include/include_lib.ml:15: Redefine.unused ./examples/docs/exported_values/code_constructs/modsig/modsig_lib.ml:6: Original.unused @@ -572,7 +571,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 489 +Total: 488 Success: 488 -Failed: 1 -Ratio: 99.7955010225% +Failed: 0 +Ratio: 100.% diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 96855234..d86de2c1 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -6,7 +6,6 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:26: Internal_app.unused ./examples/docs/exported_values/code_constructs/include/include_lib.ml:5: Original.unused -./examples/docs/exported_values/code_constructs/include/include_lib.ml:5: Reexport.unused: Should not be detected ./examples/docs/exported_values/code_constructs/include/include_lib.ml:15: Redefine.unused ./examples/docs/exported_values/code_constructs/modsig/modsig_lib.ml:6: Original.unused @@ -114,10 +113,7 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:25: Internal_app.internally_used ./examples/docs/exported_values/code_constructs/include/include_lib.ml:3: Original.used_directly -./examples/docs/exported_values/code_constructs/include/include_lib.ml:3: Reexport.used_directly: Should not be detected ./examples/docs/exported_values/code_constructs/include/include_lib.ml:4: Original.used_indirectly -./examples/docs/exported_values/code_constructs/include/include_lib.ml:4: Redefine.used_indirectly: Should not be detected -./examples/docs/exported_values/code_constructs/include/include_lib.ml:4: Reexport.used_indirectly: Should not be detected ./examples/docs/exported_values/code_constructs/include/include_lib.ml:14: Redefine.used_directly ./examples/docs/exported_values/code_constructs/modsig/modsig_lib.ml:3: Original.used_directly @@ -952,7 +948,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 823 +Total: 819 Success: 817 -Failed: 6 -Ratio: 99.2709599028% +Failed: 2 +Ratio: 99.7557997558% 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 865d10d0..40097c3b 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -6,7 +6,6 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:26: Internal_app.unused ./examples/docs/exported_values/code_constructs/include/include_lib.ml:5: Original.unused -./examples/docs/exported_values/code_constructs/include/include_lib.ml:5: Reexport.unused: Should not be detected ./examples/docs/exported_values/code_constructs/include/include_lib.ml:15: Redefine.unused ./examples/docs/exported_values/code_constructs/modsig/modsig_lib.ml:6: Original.unused @@ -114,10 +113,7 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:25: Internal_app.internally_used ./examples/docs/exported_values/code_constructs/include/include_lib.ml:3: Original.used_directly -./examples/docs/exported_values/code_constructs/include/include_lib.ml:3: Reexport.used_directly: Should not be detected ./examples/docs/exported_values/code_constructs/include/include_lib.ml:4: Original.used_indirectly -./examples/docs/exported_values/code_constructs/include/include_lib.ml:4: Redefine.used_indirectly: Should not be detected -./examples/docs/exported_values/code_constructs/include/include_lib.ml:4: Reexport.used_indirectly: Should not be detected ./examples/docs/exported_values/code_constructs/include/include_lib.ml:14: Redefine.used_directly ./examples/docs/exported_values/code_constructs/modsig/modsig_lib.ml:3: Original.used_directly @@ -343,8 +339,6 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required: Should not be detected ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required: Should not be detected ./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.externally_used: Should not be detected -./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.internally_used: Should not be detected -./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.unused: Should not be detected ./examples/docs/exported_values/hello_world/hello_world_lib.mli:4: world ./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 @@ -1346,7 +1340,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1140 +Total: 1134 Success: 1129 -Failed: 11 -Ratio: 99.0350877193% +Failed: 5 +Ratio: 99.5590828924% diff --git a/src/deadCode.ml b/src/deadCode.ml index 76b26c85..88ac3b35 100644 --- a/src/deadCode.ml +++ b/src/deadCode.ml @@ -36,11 +36,19 @@ let rec collect_export ?(mod_type = false) path u stock = function | Sig_value (id, ({Types.val_loc; val_type; _} as value), _) when not val_loc.Location.loc_ghost -> let state = State.get_current () in + let builddir = State.File_infos.get_builddir state.file_infos in let should_export stock loc = + let loc = loc.Location.loc_start in + let already_exported stock loc = + match Hashtbl.find_opt stock loc with + | Some (builddir', _) -> String.equal builddir builddir' + | None -> false + in Config.must_report_section state.config.sections.exported_values - && (* do not add the loc in decs if it belongs to a module type *) + && (* do not add the loc in decs if it belongs to a module type + or if it is already exported *) ( stock != decs - || not (Hashtbl.mem in_modtype loc.Location.loc_start) + || not (Hashtbl.mem in_modtype loc || already_exported stock loc) ) in if should_export stock val_loc then export path u stock id val_loc; From 53b0668873919552d8e0b935945896e1610bb59b Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Fri, 13 Mar 2026 17:09:02 +0100 Subject: [PATCH 3/8] [src][deadCode] only export values owned by the current module This replaces the previous fix for internal includes. It also fixes the invalid tracking and reporting of values coming from module types with substition. --- check/threshold-3-0.5/threshold-3-0.5.ref | 7 +- src/deadCode.ml | 83 +++++++++++++++-------- 2 files changed, 59 insertions(+), 31 deletions(-) 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 40097c3b..f90593ae 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -338,7 +338,6 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required: Should not be detected ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required: Should not be detected -./examples/docs/exported_values/code_constructs/modtyp/modtyp_lib.mli:13: M_subst.externally_used: Should not be detected ./examples/docs/exported_values/hello_world/hello_world_lib.mli:4: world ./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 @@ -1340,7 +1339,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1134 +Total: 1133 Success: 1129 -Failed: 5 -Ratio: 99.5590828924% +Failed: 4 +Ratio: 99.6469549868% diff --git a/src/deadCode.ml b/src/deadCode.ml index 88ac3b35..55843db7 100644 --- a/src/deadCode.ml +++ b/src/deadCode.ml @@ -31,27 +31,55 @@ let main_files = Hashtbl.create 256 (* names -> paths *) (******** PROCESSING ********) -let rec collect_export ?(mod_type = false) path u stock = function +type context = + | Toplevel + | In_module of (Ident.t * Location.t) + | In_modtyp of (Ident.t * Location.t) + | Include + +let should_export_value ~context stock loc = + let state = State.get_current () in + let belongs_to_context loc = + match context with + | Toplevel | Include -> true + | In_module (_, md_loc) + | In_modtyp (_, md_loc) -> + (* When a value is part of a module sig because of: + - an include, then its location precedes that of the current module; + - a module type with substitution, then its location ends + with the current module's sig. + Checking that the value's location is striclty within the + module's rules out these 2 cases. + *) + let get_pos_info loc = + let fname, start_l, start_c = + Location.get_pos_info loc.Location.loc_start + in + let _, end_l, end_c = Location.get_pos_info loc.loc_end in + fname, (start_l, start_c), (end_l, end_c) + in + let v_fname, v_start, v_end = get_pos_info loc in + let md_fname, md_start, md_end = get_pos_info md_loc in + let ( > ) (l1, c1) (l2, c2) = + l1 > l2 || (l1 = l2 && c1 > c2) + in + String.equal v_fname md_fname + && v_start > md_start + && md_end > v_end + in + Config.must_report_section state.config.sections.exported_values + && (* do not add the loc in decs if it belongs to a module type + or if it is not actually declared in the current context *) + ( stock != decs + || (not (Hashtbl.mem in_modtype loc.Location.loc_start) + && belongs_to_context loc) + ) + +let rec collect_export ~context path u stock = function | Sig_value (id, ({Types.val_loc; val_type; _} as value), _) when not val_loc.Location.loc_ghost -> - let state = State.get_current () in - let builddir = State.File_infos.get_builddir state.file_infos in - let should_export stock loc = - let loc = loc.Location.loc_start in - let already_exported stock loc = - match Hashtbl.find_opt stock loc with - | Some (builddir', _) -> String.equal builddir builddir' - | None -> false - in - Config.must_report_section state.config.sections.exported_values - && (* do not add the loc in decs if it belongs to a module type - or if it is already exported *) - ( stock != decs - || not (Hashtbl.mem in_modtype loc || already_exported stock loc) - ) - in - if should_export stock val_loc then export path u stock id val_loc; + if should_export_value ~context stock val_loc then export path u stock id val_loc; let path = Ident.create_persistent (Ident.name id ^ "*") :: path in DeadObj.collect_export path u stock ~obj:val_type val_loc; !DeadLexiFi.sig_value value @@ -62,15 +90,16 @@ let rec collect_export ?(mod_type = false) path u stock = function | Sig_class (id, {Types.cty_type = t; cty_loc = loc; _}, _, _) -> DeadObj.collect_export (id :: path) u stock ~cltyp:t loc - | (Sig_module (id, _, {Types.md_type = t; _}, _, _) - | Sig_modtype (id, {Types.mtd_type = Some t; _}, _)) as s -> - let stock = - match s with - | Sig_modtype _ when not mod_type -> in_modtype - | _ -> stock + | (Sig_module (id, _, {Types.md_type = t; md_loc = loc; _}, _, _) + | Sig_modtype (id, {Types.mtd_type = Some t; mtd_loc = loc; _}, _)) as s -> + let stock, context = + match s, context with + | _, Include -> stock, Include + | Sig_modtype _, _ -> in_modtype, In_modtyp (id, loc) + | _, _ -> stock, In_module (id, loc) in DeadMod.sign t - |> List.iter (collect_export ~mod_type (id :: path) u stock) + |> List.iter (collect_export ~context (id :: path) u stock) | _ -> () @@ -156,7 +185,7 @@ let structure_item super self i = |> Ident.create_persistent in List.iter - (collect_export ~mod_type:true [module_id] _include incl) + (collect_export ~context:Include [module_id] _include incl) signature; last_loc := prev_last_loc; in @@ -373,7 +402,7 @@ let read_interface fn cmi_infos state = let open Cmi_format in |> Ident.create_persistent in let f = - collect_export [module_id] u decs + collect_export ~context:Toplevel [module_id] u decs in List.iter f cmi_infos.cmi_sign; last_loc := Lexing.dummy_pos From 288abb6d64f07788845b72ca3030f2940367df7e Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Fri, 13 Mar 2026 17:51:58 +0100 Subject: [PATCH 4/8] [src][deadCode] only assoc if one location belongs to the current comp unit This fixes the potential duplicate use for values in modules used as functor parameters outside their compilation units. --- check/threshold-1/threshold-1.ref | 10 +++++----- check/threshold-3-0.5/threshold-3-0.5.ref | 14 ++++++-------- src/deadCode.ml | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index d86de2c1..9b642c3f 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -107,8 +107,8 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:9: F.internally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:14: Internal_param.used_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:15: Internal_param.unused_required -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required: Not detected -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required: Not detected +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:24: Internal_app.externally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:25: Internal_app.internally_used @@ -949,6 +949,6 @@ Nothing else to report in this section Total: 819 -Success: 817 -Failed: 2 -Ratio: 99.7557997558% +Success: 819 +Failed: 0 +Ratio: 100.% 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 f90593ae..fef95534 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -107,8 +107,8 @@ ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:9: F.internally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:14: Internal_param.used_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:15: Internal_param.unused_required -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required: Not detected -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required: Not detected +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required +./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:24: Internal_app.externally_used ./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:25: Internal_app.internally_used @@ -336,8 +336,6 @@ .>-> ALMOST UNUSED EXPORTED VALUES: Called 2 time(s): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:19: External_param.used_required: Should not be detected -./examples/docs/exported_values/code_constructs/functor/functor_lib.mli:20: External_param.unused_required: Should not be detected ./examples/docs/exported_values/hello_world/hello_world_lib.mli:4: world ./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 @@ -1339,7 +1337,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1133 -Success: 1129 -Failed: 4 -Ratio: 99.6469549868% +Total: 1131 +Success: 1131 +Failed: 0 +Ratio: 100.% diff --git a/src/deadCode.ml b/src/deadCode.ml index 55843db7..a05a491b 100644 --- a/src/deadCode.ml +++ b/src/deadCode.ml @@ -516,9 +516,19 @@ let load_file fn state = let loc_dep = if Config.must_report_section state.config.sections.exported_values then - List.rev_map + let sourceunit = + State.File_infos.get_sourceunit state.file_infos + in + let in_sourceunit (pos : Lexing.position) = + String.equal (Utils.Filepath.unit pos.pos_fname) sourceunit + in + List.filter_map (fun (vd1, vd2) -> - (vd1.Types.val_loc.Location.loc_start, vd2.Types.val_loc.Location.loc_start) + let loc1 = vd1.Types.val_loc.Location.loc_start in + let loc2 = vd2.Types.val_loc.Location.loc_start in + if in_sourceunit loc1 || in_sourceunit loc2 then + Some (loc1, loc2) + else None ) cmt_value_dependencies else [] From 197b22cc01d86e3b6e74e6e88d1ac46ab721d802 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 16 Mar 2026 14:07:38 +0100 Subject: [PATCH 5/8] [docs][exported_values] update include doc Reflect the recent fix on the example --- docs/exported_values/code_constructs/INCLUDE.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/docs/exported_values/code_constructs/INCLUDE.md b/docs/exported_values/code_constructs/INCLUDE.md index 32afa596..6465ab5b 100644 --- a/docs/exported_values/code_constructs/INCLUDE.md +++ b/docs/exported_values/code_constructs/INCLUDE.md @@ -85,7 +85,6 @@ Scanning files... .> UNUSED EXPORTED VALUES: ========================= /tmp/docs/exported_values/code_constructs/include/include_lib.ml:5: Original.unused -/tmp/docs/exported_values/code_constructs/include/include_lib.ml:5: Reexport.unused /tmp/docs/exported_values/code_constructs/include/include_lib.ml:15: Redefine.unused Nothing else to report in this section @@ -98,17 +97,6 @@ make: Leaving directory '/tmp/docs/exported_values/code_constructs/include' The compiler does not report any unused value. As expected, the analyzer reports `Original.unused` and `Redefine.unused`. -However, it also reports `Reexport.unused`, which is unexpected. - -> [!WARNING] -> The extra report on `Reexport.unused` is a known bug, tracked by -> [issue #57](https://github.com/LexiFi/dead_code_analyzer/issues/57). -> This duplicated report only exists because the modules `Original` and -> `Reexport` belong to the same compilation unit (`Include_lib`). This can -> easily be verified by moving `Reexport` in `Include_bin` instead. - -Because the report of `Reexport.unused` is actually a duplicate of the report -of `Original.unused`, we can simply ignore it. ## Removing the unused values From c6cafff8d6bae09aa45dac0e67c7ee0b8062b0ab Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 16 Mar 2026 15:07:30 +0100 Subject: [PATCH 6/8] [docs][exported_values] document limitations Document the module type limitation and issue #64 As for the examples, code presented in the limitations is added to the testsuite. --- check/classic/classic.exp | 2 + check/classic/classic.ref | 11 +- check/internal/internal.exp | 2 + check/internal/internal.ref | 11 +- check/threshold-1/threshold-1.exp | 2 + check/threshold-1/threshold-1.ref | 11 +- check/threshold-3-0.5/threshold-3-0.5.exp | 2 + check/threshold-3-0.5/threshold-3-0.5.ref | 11 +- docs/exported_values/EXPORTED_VALUES.md | 106 ++++++++++++++++++ examples/docs/exported_values/Makefile | 2 + .../docs/exported_values/limitations/Makefile | 11 ++ .../limitations/sigincl/Makefile | 12 ++ .../limitations/sigincl/sigincl_lib.ml | 12 ++ .../limitations/sigincl/sigincl_lib.mli | 11 ++ 14 files changed, 190 insertions(+), 16 deletions(-) create mode 100644 examples/docs/exported_values/limitations/Makefile create mode 100644 examples/docs/exported_values/limitations/sigincl/Makefile create mode 100644 examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml create mode 100644 examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli diff --git a/check/classic/classic.exp b/check/classic/classic.exp index 1804311c..efc07a67 100644 --- a/check/classic/classic.exp +++ b/check/classic/classic.exp @@ -569,6 +569,8 @@ Nothing else to report in this section ./examples/docs/exported_values/code_constructs/module/module_lib.ml:6: unit pattern unused ./examples/docs/exported_values/code_constructs/module/module_lib.ml:7: unit pattern unused_unexported +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x + ./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 ed7d193f..72fe2583 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -25,6 +25,7 @@ ./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/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected ./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 @@ -569,6 +570,8 @@ Nothing else to report in this section ./examples/docs/exported_values/code_constructs/module/module_lib.ml:6: unit pattern unused ./examples/docs/exported_values/code_constructs/module/module_lib.ml:7: unit pattern unused_unexported +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x + ./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: ... -> (... -> ?_:_ -> ...) -> ... @@ -616,7 +619,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 530 -Success: 530 -Failed: 0 -Ratio: 100.% +Total: 532 +Success: 531 +Failed: 1 +Ratio: 99.8120300752% diff --git a/check/internal/internal.exp b/check/internal/internal.exp index 7a7042c8..0b9dfad1 100644 --- a/check/internal/internal.exp +++ b/check/internal/internal.exp @@ -524,6 +524,8 @@ Nothing else to report in this section ./examples/docs/exported_values/code_constructs/module/module_lib.ml:6: unit pattern unused ./examples/docs/exported_values/code_constructs/module/module_lib.ml:7: unit pattern unused_unexported +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x + ./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 2168abdf..8286ebce 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -15,6 +15,7 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -524,6 +525,8 @@ Nothing else to report in this section ./examples/docs/exported_values/code_constructs/module/module_lib.ml:6: unit pattern unused ./examples/docs/exported_values/code_constructs/module/module_lib.ml:7: unit pattern unused_unexported +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x + ./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: ... -> (... -> ?_:_ -> ...) -> ... @@ -571,7 +574,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 488 -Success: 488 -Failed: 0 -Ratio: 100.% +Total: 490 +Success: 489 +Failed: 1 +Ratio: 99.7959183673% diff --git a/check/threshold-1/threshold-1.exp b/check/threshold-1/threshold-1.exp index 612c3f69..7f8b44f8 100644 --- a/check/threshold-1/threshold-1.exp +++ b/check/threshold-1/threshold-1.exp @@ -901,6 +901,8 @@ Nothing else to report in this section ./examples/docs/exported_values/code_constructs/module/module_lib.ml:6: unit pattern unused ./examples/docs/exported_values/code_constructs/module/module_lib.ml:7: unit pattern unused_unexported +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x + ./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 9b642c3f..4c47612d 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -15,6 +15,7 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -901,6 +902,8 @@ Nothing else to report in this section ./examples/docs/exported_values/code_constructs/module/module_lib.ml:6: unit pattern unused ./examples/docs/exported_values/code_constructs/module/module_lib.ml:7: unit pattern unused_unexported +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x + ./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: ... -> (... -> ?_:_ -> ...) -> ... @@ -948,7 +951,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 819 -Success: 819 -Failed: 0 -Ratio: 100.% +Total: 821 +Success: 820 +Failed: 1 +Ratio: 99.8781973203% 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 62b720b8..13143ef3 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.exp +++ b/check/threshold-3-0.5/threshold-3-0.5.exp @@ -1290,6 +1290,8 @@ Nothing else to report in this section ./examples/docs/exported_values/code_constructs/module/module_lib.ml:6: unit pattern unused ./examples/docs/exported_values/code_constructs/module/module_lib.ml:7: unit pattern unused_unexported +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x + ./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 fef95534..ec5b636f 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -15,6 +15,7 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x: Should not be detected ./examples/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -1290,6 +1291,8 @@ Nothing else to report in this section ./examples/docs/exported_values/code_constructs/module/module_lib.ml:6: unit pattern unused ./examples/docs/exported_values/code_constructs/module/module_lib.ml:7: unit pattern unused_unexported +./examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml:9: unit pattern x + ./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: ... -> (... -> ?_:_ -> ...) -> ... @@ -1337,7 +1340,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1131 -Success: 1131 -Failed: 0 -Ratio: 100.% +Total: 1133 +Success: 1132 +Failed: 1 +Ratio: 99.9117387467% diff --git a/docs/exported_values/EXPORTED_VALUES.md b/docs/exported_values/EXPORTED_VALUES.md index 715bf97f..7ec7ae16 100644 --- a/docs/exported_values/EXPORTED_VALUES.md +++ b/docs/exported_values/EXPORTED_VALUES.md @@ -8,6 +8,9 @@ + [Warning 32: unused-value-declaration](#warning-32-unused-value-declaration) + [Usage](#usage) + [Examples](#examples) ++ [Limitations](#limitations) + + [Module type](#module-type) + + [Include module type with substitution](#include-module-type-with-substitution) # Exported Values @@ -212,3 +215,106 @@ Warning 26 [unused-var]: unused variable y. - [Module type](./code_constructs/MODTYP.md) - [Module signature](./code_constructs/MODSIG.md) - [Include](./code_constructs/INCLUDE.md) + +# Limitations + +## Module type + +Related issue : +[issue #50](https://github.com/LexiFi/dead_code_analyzer/issues/50). + +As explained in the [Module type](./code_constructs/MODTYP.md) example, the +analyzer is currently restrcited to not reporting values declared in module +types. This means that any unused value defined by a module with a module type +as signature, even with constraints or substitutions, will not be reported. + +A future improvement would be to report unused exported values declared in +module types by considering all the values defined in modules of such types as +instances of the values in the module types. + +## Include module type with substitution + +Related issue : +[issue #64](https://github.com/LexiFi/dead_code_analyzer/issues/64). + +According to the above limitation on values in module types, values included +from a module type should not be reported. Even more so according to the +semantics described in the [Include](./code_constructs/INCLUDE.md) example. +This is the case unless there is a substitution on the module type. + +### Example + +The reference files for this example are in the +[sigincl](../examples/docs/exported_values/limitations/sigincl) directory. + +The reference takes place in `/tmp/docs/exported_values/limitations`, which +is a copy of the [limitations](../examples/docs/exported_values/limitations) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C sigincl build +``` + +The analysis command is : +``` +make -C sigincl analyze +``` + +The compile + analyze command is : +``` +make -C sigincl +``` + +Code: +```OCaml +(* sigincl_lib.mli *) +module type T = sig + type t + val x : t +end + +module M : T + +module I : sig + include T with type t := unit +end +``` +```OCaml +(* sigincl_lib.ml *) +module type T = sig + type t + val x : t +end + +module M = struct + type t = unit + let x = () +end + +module I = M +``` + +Compile and analyze: +``` +$ make -C sigincl +make: Entering directory '/tmp/docs/exported_values/limitations/sigincl' +ocamlopt -bin-annot sigincl_lib.mli sigincl_lib.ml +dead_code_analyzer --nothing -E all . +Scanning files... + [DONE] + +.> UNUSED EXPORTED VALUES: +========================= +/tmp/docs/exported_values/limitations/sigincl/sigincl_lib.mli:10: I.x + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/exported_values/limitations/sigincl' +``` + +The analyzer reports `I.x` at the line where `T` is included although it is +actually declared in `T`. diff --git a/examples/docs/exported_values/Makefile b/examples/docs/exported_values/Makefile index c452f3e9..64f975a2 100644 --- a/examples/docs/exported_values/Makefile +++ b/examples/docs/exported_values/Makefile @@ -5,9 +5,11 @@ all: build build: make -C hello_world make -C code_constructs + make -C limitations clean: rm -f *~ *.cm* *.o *.obj make -C hello_world clean make -C code_constructs clean + make -C limitations clean diff --git a/examples/docs/exported_values/limitations/Makefile b/examples/docs/exported_values/limitations/Makefile new file mode 100644 index 00000000..719ddd17 --- /dev/null +++ b/examples/docs/exported_values/limitations/Makefile @@ -0,0 +1,11 @@ +.PHONY: clean build + +all: build + +build: + make -C sigincl build + +clean: + rm -f *~ *.cm* *.o *.obj + make -C sigincl clean + diff --git a/examples/docs/exported_values/limitations/sigincl/Makefile b/examples/docs/exported_values/limitations/sigincl/Makefile new file mode 100644 index 00000000..faff1949 --- /dev/null +++ b/examples/docs/exported_values/limitations/sigincl/Makefile @@ -0,0 +1,12 @@ +SRC:=sigincl_lib.mli sigincl_lib.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -E all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml b/examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml new file mode 100644 index 00000000..f30d1341 --- /dev/null +++ b/examples/docs/exported_values/limitations/sigincl/sigincl_lib.ml @@ -0,0 +1,12 @@ +(* sigincl_lib.ml *) +module type T = sig + type t + val x : t +end + +module M = struct + type t = unit + let x = () +end + +module I = M diff --git a/examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli b/examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli new file mode 100644 index 00000000..a0c32a3f --- /dev/null +++ b/examples/docs/exported_values/limitations/sigincl/sigincl_lib.mli @@ -0,0 +1,11 @@ +(* sigincl_lib.mli *) +module type T = sig + type t + val x : t +end + +module M : T + +module I : sig + include T with type t := unit +end From 9c9c5acdf387ccc5f2a43b9785aad5f2b6e9c2b3 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Mon, 16 Mar 2026 15:51:32 +0100 Subject: [PATCH 7/8] [docs][exported_values] add issue #55 to limitations --- check/classic/classic.ref | 10 ++- check/internal/internal.ref | 10 ++- check/threshold-1/threshold-1.ref | 10 ++- check/threshold-3-0.5/threshold-3-0.5.ref | 10 ++- docs/exported_values/EXPORTED_VALUES.md | 70 +++++++++++++++++++ .../docs/exported_values/limitations/Makefile | 3 +- .../limitations/incl_same_name/Makefile | 12 ++++ .../limitations/incl_same_name/oo.ml | 2 + 8 files changed, 114 insertions(+), 13 deletions(-) create mode 100644 examples/docs/exported_values/limitations/incl_same_name/Makefile create mode 100644 examples/docs/exported_values/limitations/incl_same_name/oo.ml diff --git a/check/classic/classic.ref b/check/classic/classic.ref index 72fe2583..ba7997bf 100644 --- a/check/classic/classic.ref +++ b/check/classic/classic.ref @@ -25,6 +25,10 @@ ./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/exported_values/limitations/incl_same_name/oo.mli:20: copy: Should not be detected +./examples/docs/exported_values/limitations/incl_same_name/oo.mli:25: id: Should not be detected +./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/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed.mli:3: internally_used @@ -619,7 +623,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 532 +Total: 536 Success: 531 -Failed: 1 -Ratio: 99.8120300752% +Failed: 5 +Ratio: 99.0671641791% diff --git a/check/internal/internal.ref b/check/internal/internal.ref index 8286ebce..9c869823 100644 --- a/check/internal/internal.ref +++ b/check/internal/internal.ref @@ -15,6 +15,10 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/exported_values/limitations/incl_same_name/oo.mli:20: copy: Should not be detected +./examples/docs/exported_values/limitations/incl_same_name/oo.mli:25: id: Should not be detected +./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/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -574,7 +578,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 490 +Total: 494 Success: 489 -Failed: 1 -Ratio: 99.7959183673% +Failed: 5 +Ratio: 98.987854251% diff --git a/check/threshold-1/threshold-1.ref b/check/threshold-1/threshold-1.ref index 4c47612d..0f3a3f17 100644 --- a/check/threshold-1/threshold-1.ref +++ b/check/threshold-1/threshold-1.ref @@ -15,6 +15,10 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/exported_values/limitations/incl_same_name/oo.mli:20: copy: Should not be detected +./examples/docs/exported_values/limitations/incl_same_name/oo.mli:25: id: Should not be detected +./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/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -951,7 +955,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 821 +Total: 825 Success: 820 -Failed: 1 -Ratio: 99.8781973203% +Failed: 5 +Ratio: 99.3939393939% 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 ec5b636f..518f3410 100644 --- a/check/threshold-3-0.5/threshold-3-0.5.ref +++ b/check/threshold-3-0.5/threshold-3-0.5.ref @@ -15,6 +15,10 @@ ./examples/docs/exported_values/code_constructs/module/module_lib.mli:6: M.unused +./examples/docs/exported_values/limitations/incl_same_name/oo.mli:20: copy: Should not be detected +./examples/docs/exported_values/limitations/incl_same_name/oo.mli:25: id: Should not be detected +./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/using_dune/preprocessed_lib/preprocessed.mli:1: unused ./examples/using_dune/preprocessed_lib/preprocessed_no_intf.ml:2: unused @@ -1340,7 +1344,7 @@ Nothing else to report in this section -------------------------------------------------------------------------------- -Total: 1133 +Total: 1137 Success: 1132 -Failed: 1 -Ratio: 99.9117387467% +Failed: 5 +Ratio: 99.5602462621% diff --git a/docs/exported_values/EXPORTED_VALUES.md b/docs/exported_values/EXPORTED_VALUES.md index 7ec7ae16..257db969 100644 --- a/docs/exported_values/EXPORTED_VALUES.md +++ b/docs/exported_values/EXPORTED_VALUES.md @@ -11,6 +11,7 @@ + [Limitations](#limitations) + [Module type](#module-type) + [Include module type with substitution](#include-module-type-with-substitution) + + [Including a module with same name](#including-a-module-with-the-same-name) # Exported Values @@ -318,3 +319,72 @@ make: Leaving directory '/tmp/docs/exported_values/limitations/sigincl' The analyzer reports `I.x` at the line where `T` is included although it is actually declared in `T`. + +## Including a module with the same name + +Related issue : +[issue #55](https://github.com/LexiFi/dead_code_analyzer/issues/55). + +According to the semantics described in the +[Include](./code_constructs/INCLUDE.md) example, values re-exported via included +should not be reported. However, it may happen that values re-exported by +including a compilation unit out of the current codebase are reported when the +re-exporting compilation unit has the same name as the one included. + +### Example + +The reference files for this example are in the +[incl\_same\_name](../examples/docs/exported_values/limitations/incl_same_name) +directory. + +The reference takes place in `/tmp/docs/exported_values/limitations`, which +is a copy of the [limitations](../examples/docs/exported_values/limitations) +directory. Reported locations may differ depending on the location of the source +files. + +The compilation command is : +``` +make -C incl_same_name build +``` + +The analysis command is : +``` +make -C incl_same_name analyze +``` + +The compile + analyze command is : +``` +make -C incl_same_name +``` + +Code: +```OCaml +(* oo.ml *) +include Stdlib.Oo +``` + +Compile and analyze: +``` +$ make -C incl_same_name +make: Entering directory '/tmp/docs/exported_values/limitations/incl_same_name' +ocamlopt -bin-annot oo.ml +dead_code_analyzer --nothing -E all . +Scanning files... + [DONE] + +.> UNUSED EXPORTED VALUES: +========================= +/tmp/docs/exported_values/limitations/incl_same_name/oo.mli:20: copy +/tmp/docs/exported_values/limitations/incl_same_name/oo.mli:25: id +/tmp/docs/exported_values/limitations/incl_same_name/oo.mli:40: new_method +/tmp/docs/exported_values/limitations/incl_same_name/oo.mli:41: public_method_label + +Nothing else to report in this section +-------------------------------------------------------------------------------- + + +make: Leaving directory '/tmp/docs/exported_values/limitations/incl_same_name' +``` + +The analyzer reports values in `oo.mli` although they are included from +`Stdlib.Oo`. diff --git a/examples/docs/exported_values/limitations/Makefile b/examples/docs/exported_values/limitations/Makefile index 719ddd17..e54f6339 100644 --- a/examples/docs/exported_values/limitations/Makefile +++ b/examples/docs/exported_values/limitations/Makefile @@ -4,8 +4,9 @@ all: build build: make -C sigincl build + make -C incl_same_name build clean: rm -f *~ *.cm* *.o *.obj make -C sigincl clean - + make -C incl_same_name clean diff --git a/examples/docs/exported_values/limitations/incl_same_name/Makefile b/examples/docs/exported_values/limitations/incl_same_name/Makefile new file mode 100644 index 00000000..cd91c72e --- /dev/null +++ b/examples/docs/exported_values/limitations/incl_same_name/Makefile @@ -0,0 +1,12 @@ +SRC:=oo.ml + +all: build analyze + +build: + ocamlopt -bin-annot ${SRC} + +analyze: + dead_code_analyzer --nothing -E all . + +clean: + rm -f *.cm* *.o a.out diff --git a/examples/docs/exported_values/limitations/incl_same_name/oo.ml b/examples/docs/exported_values/limitations/incl_same_name/oo.ml new file mode 100644 index 00000000..29e63421 --- /dev/null +++ b/examples/docs/exported_values/limitations/incl_same_name/oo.ml @@ -0,0 +1,2 @@ +(* oo.ml *) +include Stdlib.Oo From f4a0a850f6db028524a6142c3da5240204ccca28 Mon Sep 17 00:00:00 2001 From: Corentin De Souza <9597216+fantazio@users.noreply.github.com> Date: Tue, 17 Mar 2026 16:22:59 +0100 Subject: [PATCH 8/8] [docs][exported_values] fix missing section description A significant part of a previous code review's suggestion was left out when applying the suggestion. --- docs/exported_values/EXPORTED_VALUES.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/exported_values/EXPORTED_VALUES.md b/docs/exported_values/EXPORTED_VALUES.md index 257db969..f2d43678 100644 --- a/docs/exported_values/EXPORTED_VALUES.md +++ b/docs/exported_values/EXPORTED_VALUES.md @@ -161,6 +161,19 @@ For more details about the command line arguments see [the more general Usage documentation](../USAGE.md). The report section looks like: +``` +.> UNUSED EXPORTED VALUES: +========================= +filepath:line: value + +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 `value` is +declared, `line` the line index in `filepath` at which `value` is declared, and +`value` the path of the value within its compilation unit (e.g. `M.x`). +There can be any number of such lines. The expected resolution for an unused exported value is to remove it from the `.mli` if there is one, or the `.ml` otherwise.