11open DeadCommon
22
3- module Values = struct
4- let valueBindingsTable =
5- (Hashtbl. create 15 : (string, (Name.t, Exceptions.t ) Hashtbl. t) Hashtbl. t)
3+ (* * Per-file mutable builder for exception values during AST processing *)
4+ type values_builder = (Name .t , Exceptions .t ) Hashtbl .t
5+
6+ (* * Merged immutable table for cross-file lookups *)
7+ type values_table = (string , (Name .t , Exceptions .t ) Hashtbl .t ) Hashtbl .t
8+
9+ let create_values_builder () : values_builder = Hashtbl. create 15
610
7- let currentFileTable = ref (Hashtbl. create 1 )
11+ let values_builder_add (builder : values_builder ) ~modulePath ~name exceptions =
12+ let path = (name |> Name. create) :: modulePath.ModulePath. path in
13+ Hashtbl. replace builder (path |> DcePath. toName) exceptions
814
9- let add ~modulePath ~name exceptions =
10- let path = (name |> Name. create) :: modulePath.ModulePath. path in
11- Hashtbl. replace ! currentFileTable (path |> DcePath. toName) exceptions
15+ (* * Merge all per-file builders into a single lookup table *)
16+ let merge_values_builders (builders : (string * values_builder) list ) :
17+ values_table =
18+ let table = Hashtbl. create 15 in
19+ builders
20+ |> List. iter (fun (moduleName , builder ) ->
21+ Hashtbl. replace table moduleName builder);
22+ table
1223
13- let getFromModule ~moduleName ~modulePath (path_ : DcePath.t ) =
24+ module Values = struct
25+ let getFromModule (table : values_table ) ~moduleName ~modulePath
26+ (path_ : DcePath.t ) =
1427 let name = path_ @ modulePath |> DcePath. toName in
15- match
16- Hashtbl. find_opt valueBindingsTable (String. capitalize_ascii moduleName)
17- with
28+ match Hashtbl. find_opt table (String. capitalize_ascii moduleName) with
1829 | Some tbl -> Hashtbl. find_opt tbl name
1930 | None -> (
20- match
21- Hashtbl. find_opt valueBindingsTable
22- (String. uncapitalize_ascii moduleName)
23- with
31+ match Hashtbl. find_opt table (String. uncapitalize_ascii moduleName) with
2432 | Some tbl -> Hashtbl. find_opt tbl name
2533 | None -> None )
2634
27- let rec findLocal ~moduleName ~modulePath path =
28- match path |> getFromModule ~module Name ~module Path with
35+ let rec findLocal ( table : values_table ) ~moduleName ~modulePath path =
36+ match path |> getFromModule table ~module Name ~module Path with
2937 | Some exceptions -> Some exceptions
3038 | None -> (
3139 match modulePath with
3240 | [] -> None
3341 | _ :: restModulePath ->
34- path |> findLocal ~module Name ~module Path:restModulePath)
42+ path |> findLocal table ~module Name ~module Path:restModulePath)
3543
36- let findPath ~moduleName ~modulePath path =
44+ let findPath ( table : values_table ) ~moduleName ~modulePath path =
3745 let findExternal ~externalModuleName ~pathRev =
3846 pathRev |> List. rev
39- |> getFromModule
47+ |> getFromModule table
4048 ~module Name:(externalModuleName |> Name. toString)
4149 ~module Path:[]
4250 in
43- match path |> findLocal ~module Name ~module Path with
51+ match path |> findLocal table ~module Name ~module Path with
4452 | None -> (
4553 (* Search in another file *)
4654 match path |> List. rev with
@@ -54,10 +62,6 @@ module Values = struct
5462 | None , _ -> None )
5563 | [] -> None )
5664 | Some exceptions -> Some exceptions
57-
58- let newCmt ~moduleName =
59- currentFileTable := Hashtbl. create 15 ;
60- Hashtbl. replace valueBindingsTable moduleName ! currentFileTable
6165end
6266
6367module Event = struct
@@ -99,7 +103,7 @@ module Event = struct
99103 nestedEvents |> List. iter (fun e -> Format. fprintf ppf " %a " print e))
100104 ()
101105
102- let combine ~config ~moduleName events =
106+ let combine ~( values_table : values_table ) ~ config ~moduleName events =
103107 if config.DceConfig. cli.debug then (
104108 Log_. item " @." ;
105109 Log_. item " Events combine: #events %d@." (events |> List. length));
@@ -123,7 +127,9 @@ module Event = struct
123127 | ({kind = Call {callee; modulePath} ; loc} as ev ) :: rest ->
124128 if config.DceConfig. cli.debug then Log_. item " %a@." print ev;
125129 let exceptions =
126- match callee |> Values. findPath ~module Name ~module Path with
130+ match
131+ callee |> Values. findPath values_table ~module Name ~module Path
132+ with
127133 | Some exceptions -> exceptions
128134 | _ -> (
129135 match ExnLib. find callee with
@@ -168,25 +174,33 @@ module Event = struct
168174 (exnSet, exnTable)
169175end
170176
171- module Checks = struct
172- type check = {
173- events : Event .t list ;
174- loc : Location .t ;
175- locFull : Location .t ;
176- moduleName : string ;
177- exnName : string ;
178- exceptions : Exceptions .t ;
179- }
177+ (* * Per-file mutable builder for checks during AST processing *)
178+ type checks_builder = check list ref
179+
180+ and check = {
181+ events : Event .t list ;
182+ loc : Location .t ;
183+ locFull : Location .t ;
184+ moduleName : string ;
185+ exnName : string ;
186+ exceptions : Exceptions .t ;
187+ }
180188
181- type t = check list
189+ let create_checks_builder () : checks_builder = ref []
182190
183- let checks = (ref [] : t ref )
191+ let checks_builder_add (builder : checks_builder ) ~events ~exceptions ~loc
192+ ?(locFull = loc) ~moduleName exnName =
193+ builder := {events; exceptions; loc; locFull; moduleName; exnName} :: ! builder
184194
185- let add ~ events ~ exceptions ~ loc ?( locFull = loc) ~ moduleName exnName =
186- checks := {events; exceptions; loc; locFull; moduleName; exnName} :: ! checks
195+ let checks_builder_to_list ( builder : checks_builder ) : check list =
196+ ! builder |> List. rev
187197
188- let doCheck ~config {events; exceptions; loc; locFull; moduleName; exnName} =
189- let throwSet, exnTable = events |> Event. combine ~config ~module Name in
198+ module Checks = struct
199+ let doCheck ~(values_table : values_table ) ~config
200+ {events; exceptions; loc; locFull; moduleName; exnName} =
201+ let throwSet, exnTable =
202+ events |> Event. combine ~values_table ~config ~module Name
203+ in
190204 let missingAnnotations = Exceptions. diff throwSet exceptions in
191205 let redundantAnnotations = Exceptions. diff exceptions throwSet in
192206 (if not (Exceptions. isEmpty missingAnnotations) then
@@ -215,13 +229,28 @@ module Checks = struct
215229 redundantAnnotations);
216230 })
217231
218- let doChecks ~config = ! checks |> List. rev |> List. iter (doCheck ~config )
232+ let doChecks ~values_table ~config (checks : check list ) =
233+ checks |> List. iter (doCheck ~values_table ~config )
219234end
220235
221- let traverseAst ~file () =
236+ let traverseAst ~file ~ values_builder ~ checks_builder () =
222237 let super = Tast_mapper. default in
223238 let currentId = ref " " in
224239 let currentEvents = ref [] in
240+ (* For local lookups during AST processing, we look up in the current file's builder *)
241+ let findLocalExceptions ~modulePath path =
242+ let name = path @ modulePath |> DcePath. toName in
243+ Hashtbl. find_opt values_builder name
244+ in
245+ let rec findLocalPath ~modulePath path =
246+ match path |> findLocalExceptions ~module Path with
247+ | Some exceptions -> Some exceptions
248+ | None -> (
249+ match modulePath with
250+ | [] -> None
251+ | _ :: restModulePath ->
252+ path |> findLocalPath ~module Path:restModulePath)
253+ in
225254 let exceptionsOfPatterns patterns =
226255 patterns
227256 |> List. fold_left
@@ -394,7 +423,7 @@ let traverseAst ~file () =
394423 currentEvents := [] ;
395424 let moduleName = file.FileContext. module_name in
396425 self.expr self expr |> ignore;
397- Checks. add ~events: ! currentEvents
426+ checks_builder_add checks_builder ~events: ! currentEvents
398427 ~exceptions: (getExceptionsFromAnnotations attributes)
399428 ~loc: expr.exp_loc ~module Name name;
400429 currentId := oldId;
@@ -416,19 +445,18 @@ let traverseAst ~file () =
416445 let exceptionsFromAnnotations =
417446 getExceptionsFromAnnotations vb.vb_attributes
418447 in
419- exceptionsFromAnnotations |> Values. add ~module Path ~name ;
448+ values_builder_add values_builder ~module Path ~name
449+ exceptionsFromAnnotations;
420450 let res = super.value_binding self vb in
421451 let moduleName = file.FileContext. module_name in
422452 let path = [name |> Name. create] in
423453 let exceptions =
424- match
425- path |> Values. findPath ~module Name ~module Path:modulePath.path
426- with
454+ match path |> findLocalPath ~module Path:modulePath.path with
427455 | Some exceptions -> exceptions
428456 | _ -> Exceptions. empty
429457 in
430- Checks. add ~events: ! currentEvents ~exceptions ~loc: vb.vb_pat.pat_loc
431- ~loc Full:vb.vb_loc ~module Name name;
458+ checks_builder_add checks_builder ~events: ! currentEvents ~exceptions
459+ ~loc: vb.vb_pat.pat_loc ~ loc Full:vb.vb_loc ~module Name name;
432460 currentId := oldId;
433461 currentEvents := oldEvents;
434462 res
@@ -509,14 +537,42 @@ let traverseAst ~file () =
509537 fun (structure : Typedtree.structure ) ->
510538 process_structure ModulePath. initial structure
511539
512- let processStructure ~file (structure : Typedtree.structure ) =
513- let process = traverseAst ~file () in
540+ (* * Result of processing a single file *)
541+ type file_result = {
542+ module_name : string ;
543+ values_builder : values_builder ;
544+ checks : check list ;
545+ }
546+
547+ let processStructure ~file ~values_builder ~checks_builder
548+ (structure : Typedtree.structure ) =
549+ let process = traverseAst ~file ~values_builder ~checks_builder () in
514550 process structure
515551
516- let processCmt ~file (cmt_infos : Cmt_format.cmt_infos ) =
552+ let processCmt ~file (cmt_infos : Cmt_format.cmt_infos ) : file_result option =
517553 match cmt_infos.cmt_annots with
518- | Interface _ -> ()
554+ | Interface _ -> None
519555 | Implementation structure ->
520- Values. newCmt ~module Name:file.FileContext. module_name;
521- structure |> processStructure ~file
522- | _ -> ()
556+ let values_builder = create_values_builder () in
557+ let checks_builder = create_checks_builder () in
558+ structure |> processStructure ~file ~values_builder ~checks_builder ;
559+ Some
560+ {
561+ module_name = file.FileContext. module_name;
562+ values_builder;
563+ checks = checks_builder_to_list checks_builder;
564+ }
565+ | _ -> None
566+
567+ (* * Process all accumulated checks using merged values table *)
568+ let runChecks ~config (all_results : file_result list ) =
569+ (* Merge all values builders *)
570+ let values_table =
571+ all_results
572+ |> List. map (fun r -> (r.module_name, r.values_builder))
573+ |> merge_values_builders
574+ in
575+ (* Collect all checks *)
576+ let all_checks = all_results |> List. concat_map (fun r -> r.checks) in
577+ (* Run checks with merged table *)
578+ Checks. doChecks ~values_table ~config all_checks
0 commit comments