Skip to content

Commit b87daec

Browse files
committed
[src][state] expose location_dependencies through state.file_infos
Rather than adding a `signature` field to the state to hold a `uid_to_loc` table to then use in `DeadCode.load_file` to convert uids into locations, to then convert `cmt_declaration_dependencies` into a list of pairs of locations, directly construct that list and store along with the `file_infos`. This move is more consistent with the nature, usage and provenance of the information : it is created using info in `cmt_infos` and `cmti_infos` to replace the `cmt_value_dependencies` field that existed prior to OCaml 5.3, and should only live as long the corresponding `cmt_infos` live.
1 parent 736e674 commit b87daec

File tree

9 files changed

+131
-120
lines changed

9 files changed

+131
-120
lines changed

src/deadCode.ml

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -460,30 +460,17 @@ let rec load_file state fn =
460460
init_and_continue state fn (fun state ->
461461
match state.file_infos.cmt_infos with
462462
| None -> bad_files := fn :: !bad_files
463-
| Some ({cmt_annots = Implementation x; _} as cmt_infos) ->
463+
| Some {cmt_annots = Implementation x; _} ->
464464
regabs state;
465-
let uid_decl_dep_to_loc_pair (_dep_kind, uid_def, uid_decl) =
466-
let ( let* ) x f = Option.bind x f in
467-
let loc_opt_of_uid uid =
468-
Uid.Tbl.find_opt state.signature.uid_to_loc uid
469-
in
470-
let* def_loc = loc_opt_of_uid uid_def in
471-
let* decl_loc = loc_opt_of_uid uid_decl in
472-
Some (def_loc, decl_loc)
473-
in
474-
let value_dep =
475-
cmt_infos.cmt_declaration_dependencies
476-
|> List.filter_map uid_decl_dep_to_loc_pair
477-
in
478465
let prepare (loc1, loc2) =
479466
DeadObj.add_equal loc1 loc2;
480467
VdNode.merge_locs ~force:true loc2 loc1
481468
in
482-
List.iter prepare value_dep;
469+
List.iter prepare state.file_infos.location_dependencies;
483470
ignore (collect_references.Tast_mapper.structure collect_references x);
484471
let loc_dep =
485472
if !DeadFlag.exported.DeadFlag.print then
486-
value_dep
473+
state.file_infos.location_dependencies
487474
else []
488475
in
489476
eof loc_dep

src/state/file_infos.ml

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
type t = {
2-
cm_file : string;
3-
sourcepath : string option;
42
builddir : string;
5-
modname : string;
3+
cm_file : string;
64
cmi_infos : Cmi_format.cmi_infos option;
75
cmt_infos : Cmt_format.cmt_infos option;
86
cmti_infos : Cmt_format.cmt_infos option;
7+
location_dependencies : Location_dependencies.t;
8+
modname : string;
9+
sourcepath : string option;
910
}
1011

1112
let empty = {
12-
cm_file = "";
13-
sourcepath = None;
1413
builddir = "!!UNKNOWN_BUILDDIR!!";
15-
modname = "!!UNKNOWN_MODNAME!!";
14+
cm_file = "";
1615
cmi_infos = None;
1716
cmt_infos = None;
1817
cmti_infos = None;
18+
location_dependencies = Location_dependencies.empty;
19+
modname = "!!UNKNOWN_MODNAME!!";
20+
sourcepath = None;
1921
}
2022

2123
(** [init_from_all_cm_infos ~orig ~cm_file cmi_infos cmt_infos] creates a [t] with:
@@ -35,7 +37,13 @@ let empty = {
3537
| `Cmt -> Some cmt_infos, None
3638
| `Cmti -> None, Some cmt_infos
3739
in
38-
{cm_file; sourcepath; builddir; modname; cmi_infos; cmt_infos; cmti_infos}
40+
{empty with builddir;
41+
cm_file;
42+
cmi_infos;
43+
cmt_infos;
44+
cmti_infos;
45+
modname;
46+
sourcepath}
3947

4048
(** [init_from_cm_file ~orig cm_file] returns an [Ok t] with [t] filled using
4149
the [cm_file] (see [init_from_cmt_infos]).
@@ -80,7 +88,15 @@ let init cm_file =
8088
in
8189
file_infos.cmi_infos, cmt_infos, file_infos.cmti_infos
8290
in
83-
Result.ok {file_infos with cmi_infos; cmt_infos; cmti_infos}
91+
let* location_dependencies =
92+
match orig with
93+
| `Cmt -> Location_dependencies.init cmt_infos cmti_infos
94+
| `Cmti -> Result.ok Location_dependencies.empty
95+
in
96+
Result.ok {file_infos with cmi_infos;
97+
cmt_infos;
98+
cmti_infos;
99+
location_dependencies}
84100

85101
let change_file file_infos cm_file =
86102
let no_ext = Filename.remove_extension cm_file in
@@ -90,7 +106,11 @@ let change_file file_infos cm_file =
90106
let res =
91107
init_from_all_cm_infos ~orig:`Cmt ~cm_file cmi_infos cmt_infos
92108
in
93-
Result.ok {res with cmi_infos; cmti_infos}
109+
let res = {res with cmi_infos; cmti_infos} in
110+
let* location_dependencies =
111+
Location_dependencies.init res.cmt_infos res.cmti_infos
112+
in
113+
Result.ok {res with location_dependencies}
94114
| ".cmti", {cmti_infos=Some cmti_infos; cmi_infos; cmt_infos; _} ->
95115
let res =
96116
init_from_all_cm_infos ~orig:`Cmti ~cm_file cmi_infos cmti_infos

src/state/file_infos.mli

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
(** Information about a analyzable file ([.cmti] or [.cmt] file) *)
22

33
type t = {
4-
cm_file : string; (** The filepath currently analyzed *)
5-
sourcepath : string option; (** The path to the associated source file *)
64
builddir : string; (** The [cmt_builddir] *)
7-
modname : string; (** Either [cmti_name] or [cmt_modname] *)
5+
cm_file : string; (** The filepath currently analyzed *)
86
cmi_infos : Cmi_format.cmi_infos option;
97
cmt_infos : Cmt_format.cmt_infos option;
108
cmti_infos : Cmt_format.cmt_infos option;
9+
location_dependencies : Location_dependencies.t;
10+
(** Dependencies similar to [cmt_infos.cmt_value_dependencies] in OCaml 5.2 *)
11+
modname : string; (** Either [cmti_name] or [cmt_modname] *)
12+
sourcepath : string option; (** The path to the associated source file *)
1113
}
1214

1315
val empty : t (** No file info *)

src/state/location_dependencies.ml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
type t = (Lexing.position * Lexing.position) list
2+
3+
let empty = []
4+
5+
module UidTbl = Shape.Uid.Tbl
6+
7+
let fill_from_structure (structure : Typedtree.structure) res_uid_to_loc =
8+
let open Types in
9+
let rec fill_from_signature_item = function
10+
| Sig_value (_, {val_loc; val_uid; _}, _) ->
11+
UidTbl.replace res_uid_to_loc val_uid val_loc.loc_start
12+
| Sig_module (_, _, {md_type = modtype; _}, _, _)
13+
| Sig_modtype (_, {mtd_type = Some modtype; _}, _) ->
14+
Utils.signature_of_modtype modtype
15+
|> fill_from_signature
16+
| _ -> ()
17+
and fill_from_signature s =
18+
List.iter fill_from_signature_item s
19+
in
20+
let iterator =
21+
let super = Tast_iterator.default_iterator in
22+
let structure_item self struct_item =
23+
let open Typedtree in
24+
begin match struct_item.str_desc with
25+
| Tstr_include {incl_type; _} -> fill_from_signature incl_type
26+
| _ -> ()
27+
end;
28+
super.Tast_iterator.structure_item self struct_item
29+
in
30+
{super with structure_item}
31+
in
32+
iterator.structure iterator structure;
33+
res_uid_to_loc
34+
35+
let fill_from_cmt_infos cmt_infos res_uid_to_loc =
36+
let open Typedtree in
37+
let loc_of_item_decl = function
38+
| Value {val_loc = loc; _}
39+
| Value_binding {vb_pat = {pat_loc = loc; _}; _} ->
40+
Some loc.loc_start
41+
| _ -> None
42+
in
43+
let add_uid_loc uid item_decl =
44+
let loc = loc_of_item_decl item_decl in
45+
Option.iter (UidTbl.replace res_uid_to_loc uid) loc
46+
in
47+
UidTbl.iter add_uid_loc cmt_infos.Cmt_format.cmt_uid_to_decl;
48+
res_uid_to_loc
49+
50+
let cmt_decl_dep_to_loc_dep cmt_decl_dep uid_to_loc =
51+
let convert_pair (_dep_kind, uid_def, uid_decl) =
52+
let ( let* ) x f = Option.bind x f in
53+
let loc_opt_of_uid uid =
54+
UidTbl.find_opt uid_to_loc uid
55+
in
56+
let* def_loc = loc_opt_of_uid uid_def in
57+
let* decl_loc = loc_opt_of_uid uid_decl in
58+
Some (def_loc, decl_loc)
59+
in
60+
List.filter_map convert_pair cmt_decl_dep
61+
62+
let init cmt_infos cmti_infos =
63+
match cmt_infos with
64+
| None -> Result.error "No cmt_infos available"
65+
| Some (Cmt_format.{cmt_annots = Implementation structure; _} as cmt_infos) -> (
66+
let fill_from_cmti_infos tbl =
67+
match cmti_infos with
68+
| None -> tbl
69+
| Some cmti_infos -> fill_from_cmt_infos cmti_infos tbl
70+
in
71+
(* TODO: Evaluate a generally good size for the tbl ? *)
72+
UidTbl.create 512
73+
|> fill_from_structure structure
74+
|> fill_from_cmt_infos cmt_infos
75+
|> fill_from_cmti_infos
76+
|> cmt_decl_dep_to_loc_dep cmt_infos.cmt_declaration_dependencies
77+
|> Result.ok
78+
)
79+
| Some _ -> Result.error "No implementation found in cmt_infos"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
type t = (Lexing.position * Lexing.position) list
2+
(** Dependencies similar to [cmt_infos.cmt_value_dependencies] in OCaml 5.2 *)
3+
4+
val empty : t (** No signature read *)
5+
6+
val init : Cmt_format.cmt_infos option -> Cmt_format.cmt_infos option -> (t, string) result
7+
(** [init cmt_infos cmti_infos] expects [cmt_infos = Some _].
8+
It reads the [cmt_infos] and the |cmti_infos] to retrieve their
9+
[cmt_declaration_dependencies] and convert them into a single [t].
10+
It returns an [Ok t] with [t] on success.
11+
In case the [cmt_infos] is missing or does not contain an implementation,
12+
it returns an [Err msg] with msg a string describing the issue. *)

src/state/signature.ml

Lines changed: 0 additions & 69 deletions
This file was deleted.

src/state/signature.mli

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/state/state.ml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,16 @@ module File_infos = File_infos
22

33
type t = {
44
file_infos : File_infos.t;
5-
signature : Signature.t
65
}
76

87
let empty = {
98
file_infos = File_infos.empty;
10-
signature = Signature.empty ();
119
}
1210

1311
let init cm_file =
1412
let ( let* ) x f = Result.bind x f in
1513
let* file_infos = File_infos.init cm_file in
16-
let* signature = Signature.init file_infos in
17-
Result.ok {file_infos; signature}
14+
Result.ok {file_infos}
1815

1916
let change_file state cm_file =
2017
let file_infos = state.file_infos in
@@ -27,7 +24,7 @@ let change_file state cm_file =
2724
Result.ok state
2825
else if equal_no_ext file_infos.cm_file cm_file then
2926
let file_infos = File_infos.change_file file_infos cm_file in
30-
Result.map (fun file_infos -> {state with file_infos}) file_infos
27+
Result.map (fun file_infos -> {file_infos}) file_infos
3128
else
3229
init cm_file
3330

src/state/state.mli

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ module File_infos = File_infos
44

55
type t = {
66
file_infos : File_infos.t; (** Info about the file being analyzed *)
7-
signature : Signature.t; (** Data extracted or built using the current
8-
compiltion unit's signature *)
97
}
108

119
val empty : t (** The empty state *)
1210

1311
val init : string -> (t, string) result
1412
(** [init cmti_file] initialize a state to analyze [cmti_file].
15-
See [File_infos.init] for error cases. *)
13+
See the fields respective [init]s for error cases. *)
1614

1715
val change_file : t -> string -> (t, string) result
1816
(** [cahnge_file t cmti_file] prepare the analysis to move on to [cmti_file].

0 commit comments

Comments
 (0)