Skip to content

Commit 5066e28

Browse files
committed
DCE: Make ProcessDeadAnnotations state explicit
- Create AnnotationState module with explicit state type and accessor functions - Thread annotation_state through DeadCode.processCmt and Reanalyze pipeline - Update declIsDead, doReportDead, resolveRecursiveRefs to use explicit state - Update DeadOptionalArgs.check to take explicit state - Remove global positionsAnnotated hashtable from ProcessDeadAnnotations - Remove unused ~config parameter from iterFilesFromRootsToLeaves Note: Current implementation still mixes input (source annotations) with output (analysis results). This will be properly separated in Task 8.
1 parent 7936d69 commit 5066e28

File tree

4 files changed

+89
-72
lines changed

4 files changed

+89
-72
lines changed

analysis/reanalyze/src/DeadCode.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ let processSignature ~config ~file ~doValues ~doTypes
99
~path:[FileContext.module_name_tagged file]
1010
sig_item)
1111

12-
let processCmt ~config ~file ~cmtFilePath (cmt_infos : Cmt_format.cmt_infos) =
12+
let processCmt ~state ~config ~file ~cmtFilePath
13+
(cmt_infos : Cmt_format.cmt_infos) =
1314
(match cmt_infos.cmt_annots with
1415
| Interface signature ->
15-
ProcessDeadAnnotations.signature ~config signature;
16+
ProcessDeadAnnotations.signature ~state ~config signature;
1617
processSignature ~config ~file ~doValues:true ~doTypes:true
1718
signature.sig_type
1819
| Implementation structure ->
1920
let cmtiExists =
2021
Sys.file_exists ((cmtFilePath |> Filename.remove_extension) ^ ".cmti")
2122
in
22-
ProcessDeadAnnotations.structure ~config ~doGenType:(not cmtiExists)
23+
ProcessDeadAnnotations.structure ~state ~config ~doGenType:(not cmtiExists)
2324
structure;
2425
processSignature ~config ~file ~doValues:true ~doTypes:false
2526
structure.str_type;

analysis/reanalyze/src/DeadCommon.ml

Lines changed: 73 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,35 @@ module PosHash = struct
5555
replace h k (PosSet.add v set)
5656
end
5757

58+
(** State tracking positions annotated as @dead, @live, or @genType *)
59+
module AnnotationState = struct
60+
type annotated_as = GenType | Dead | Live
61+
type t = annotated_as PosHash.t
62+
63+
let create () : t = PosHash.create 1
64+
65+
let is_annotated_dead (state : t) pos = PosHash.find_opt state pos = Some Dead
66+
67+
let is_annotated_gentype_or_live (state : t) pos =
68+
match PosHash.find_opt state pos with
69+
| Some (Live | GenType) -> true
70+
| Some Dead | None -> false
71+
72+
let is_annotated_gentype_or_dead (state : t) pos =
73+
match PosHash.find_opt state pos with
74+
| Some (Dead | GenType) -> true
75+
| Some Live | None -> false
76+
77+
let annotate_gentype (state : t) (pos : Lexing.position) =
78+
PosHash.replace state pos GenType
79+
80+
let annotate_dead (state : t) (pos : Lexing.position) =
81+
PosHash.replace state pos Dead
82+
83+
let annotate_live (state : t) (pos : Lexing.position) =
84+
PosHash.replace state pos Live
85+
end
86+
5887
type decls = decl PosHash.t
5988
(** all exported declarations *)
6089

@@ -114,7 +143,7 @@ let addValueReference ~config ~(binding : Location.t) ~addFileReference
114143
&& effectiveFrom.loc_start.pos_fname <> locTo.loc_start.pos_fname
115144
then FileReferences.add effectiveFrom locTo)
116145

117-
let iterFilesFromRootsToLeaves ~config iterFun =
146+
let iterFilesFromRootsToLeaves iterFun =
118147
(* For each file, the number of incoming references *)
119148
let inverseReferences = (Hashtbl.create 1 : (string, int) Hashtbl.t) in
120149
(* For each number of incoming references, the files *)
@@ -189,43 +218,19 @@ let iterFilesFromRootsToLeaves ~config iterFun =
189218
});
190219
iterFun fileName))
191220

192-
(** Keep track of the location of values annotated @genType or @dead *)
221+
(** Process AST to collect locations annotated @genType, @dead, or @live *)
193222
module ProcessDeadAnnotations = struct
194-
type annotatedAs = GenType | Dead | Live
195-
196-
let positionsAnnotated = PosHash.create 1
197-
let isAnnotatedDead pos = PosHash.find_opt positionsAnnotated pos = Some Dead
198-
199-
let isAnnotatedGenTypeOrLive pos =
200-
match PosHash.find_opt positionsAnnotated pos with
201-
| Some (Live | GenType) -> true
202-
| Some Dead | None -> false
203-
204-
let isAnnotatedGenTypeOrDead pos =
205-
match PosHash.find_opt positionsAnnotated pos with
206-
| Some (Dead | GenType) -> true
207-
| Some Live | None -> false
208-
209-
let annotateGenType (pos : Lexing.position) =
210-
PosHash.replace positionsAnnotated pos GenType
211-
212-
let annotateDead (pos : Lexing.position) =
213-
PosHash.replace positionsAnnotated pos Dead
214-
215-
let annotateLive (pos : Lexing.position) =
216-
PosHash.replace positionsAnnotated pos Live
217-
218-
let processAttributes ~config ~doGenType ~name ~pos attributes =
223+
let processAttributes ~state ~config ~doGenType ~name ~pos attributes =
219224
let getPayloadFun f = attributes |> Annotation.getAttributePayload f in
220225
let getPayload (x : string) =
221226
attributes |> Annotation.getAttributePayload (( = ) x)
222227
in
223228
if
224229
doGenType
225230
&& getPayloadFun Annotation.tagIsOneOfTheGenTypeAnnotations <> None
226-
then pos |> annotateGenType;
231+
then AnnotationState.annotate_gentype state pos;
227232
if getPayload WriteDeadAnnotations.deadAnnotation <> None then
228-
pos |> annotateDead;
233+
AnnotationState.annotate_dead state pos;
229234
let nameIsInLiveNamesOrPaths () =
230235
config.DceConfig.cli.live_names |> List.mem name
231236
||
@@ -243,21 +248,23 @@ module ProcessDeadAnnotations = struct
243248
with Invalid_argument _ -> false)
244249
in
245250
if getPayload liveAnnotation <> None || nameIsInLiveNamesOrPaths () then
246-
pos |> annotateLive;
251+
AnnotationState.annotate_live state pos;
247252
if attributes |> Annotation.isOcamlSuppressDeadWarning then
248-
pos |> annotateLive
253+
AnnotationState.annotate_live state pos
249254

250-
let collectExportLocations ~config ~doGenType =
255+
let collectExportLocations ~state ~config ~doGenType =
251256
let super = Tast_mapper.default in
252257
let currentlyDisableWarnings = ref false in
253258
let value_binding self
254259
({vb_attributes; vb_pat} as value_binding : Typedtree.value_binding) =
255260
(match vb_pat.pat_desc with
256261
| Tpat_var (id, {loc = {loc_start = pos}})
257262
| Tpat_alias ({pat_desc = Tpat_any}, id, {loc = {loc_start = pos}}) ->
258-
if !currentlyDisableWarnings then pos |> annotateLive;
263+
if !currentlyDisableWarnings then
264+
AnnotationState.annotate_live state pos;
259265
vb_attributes
260-
|> processAttributes ~config ~doGenType ~name:(id |> Ident.name) ~pos
266+
|> processAttributes ~state ~config ~doGenType ~name:(id |> Ident.name)
267+
~pos
261268
| _ -> ());
262269
super.value_binding self value_binding
263270
in
@@ -268,7 +275,7 @@ module ProcessDeadAnnotations = struct
268275
|> List.iter
269276
(fun ({ld_attributes; ld_loc} : Typedtree.label_declaration) ->
270277
toplevelAttrs @ ld_attributes
271-
|> processAttributes ~config ~doGenType:false ~name:""
278+
|> processAttributes ~state ~config ~doGenType:false ~name:""
272279
~pos:ld_loc.loc_start)
273280
| Ttype_variant constructorDeclarations ->
274281
constructorDeclarations
@@ -284,13 +291,13 @@ module ProcessDeadAnnotations = struct
284291
(fun ({ld_attributes; ld_loc} :
285292
Typedtree.label_declaration) ->
286293
toplevelAttrs @ cd_attributes @ ld_attributes
287-
|> processAttributes ~config ~doGenType:false ~name:""
288-
~pos:ld_loc.loc_start)
294+
|> processAttributes ~state ~config ~doGenType:false
295+
~name:"" ~pos:ld_loc.loc_start)
289296
flds
290297
| Cstr_tuple _ -> ()
291298
in
292299
toplevelAttrs @ cd_attributes
293-
|> processAttributes ~config ~doGenType:false ~name:""
300+
|> processAttributes ~state ~config ~doGenType:false ~name:""
294301
~pos:cd_loc.loc_start)
295302
| _ -> ());
296303
super.type_kind self typeKind
@@ -304,9 +311,10 @@ module ProcessDeadAnnotations = struct
304311
({val_attributes; val_id; val_val = {val_loc = {loc_start = pos}}} as
305312
value_description :
306313
Typedtree.value_description) =
307-
if !currentlyDisableWarnings then pos |> annotateLive;
314+
if !currentlyDisableWarnings then AnnotationState.annotate_live state pos;
308315
val_attributes
309-
|> processAttributes ~config ~doGenType ~name:(val_id |> Ident.name) ~pos;
316+
|> processAttributes ~state ~config ~doGenType
317+
~name:(val_id |> Ident.name) ~pos;
310318
super.value_description self value_description
311319
in
312320
let structure_item self (item : Typedtree.structure_item) =
@@ -348,15 +356,17 @@ module ProcessDeadAnnotations = struct
348356
value_description;
349357
}
350358

351-
let structure ~config ~doGenType structure =
352-
let collectExportLocations = collectExportLocations ~config ~doGenType in
359+
let structure ~state ~config ~doGenType structure =
360+
let collectExportLocations =
361+
collectExportLocations ~state ~config ~doGenType
362+
in
353363
structure
354364
|> collectExportLocations.structure collectExportLocations
355365
|> ignore
356366

357-
let signature ~config signature =
367+
let signature ~state ~config signature =
358368
let collectExportLocations =
359-
collectExportLocations ~config ~doGenType:true
369+
collectExportLocations ~state ~config ~doGenType:true
360370
in
361371
signature
362372
|> collectExportLocations.signature collectExportLocations
@@ -579,17 +589,18 @@ module Decl = struct
579589
emitWarning ~config ~decl ~message name)
580590
end
581591

582-
let declIsDead ~refs decl =
592+
let declIsDead ~state ~refs decl =
583593
let liveRefs =
584594
refs
585-
|> PosSet.filter (fun p -> not (ProcessDeadAnnotations.isAnnotatedDead p))
595+
|> PosSet.filter (fun p -> not (AnnotationState.is_annotated_dead state p))
586596
in
587597
liveRefs |> PosSet.cardinal = 0
588-
&& not (ProcessDeadAnnotations.isAnnotatedGenTypeOrLive decl.pos)
598+
&& not (AnnotationState.is_annotated_gentype_or_live state decl.pos)
589599

590-
let doReportDead pos = not (ProcessDeadAnnotations.isAnnotatedGenTypeOrDead pos)
600+
let doReportDead ~state pos =
601+
not (AnnotationState.is_annotated_gentype_or_dead state pos)
591602

592-
let rec resolveRecursiveRefs ~config
603+
let rec resolveRecursiveRefs ~state ~config
593604
~checkOptionalArg:(checkOptionalArgFn : config:DceConfig.t -> decl -> unit)
594605
~deadDeclarations ~level ~orderedFiles ~refs ~refsBeingResolved decl : bool
595606
=
@@ -599,7 +610,7 @@ let rec resolveRecursiveRefs ~config
599610
Log_.item "recursiveDebug %s [%d] already resolved@."
600611
(decl.path |> Path.toString)
601612
level;
602-
decl.pos |> ProcessDeadAnnotations.isAnnotatedDead
613+
AnnotationState.is_annotated_dead state decl.pos
603614
| _ when PosSet.mem decl.pos !refsBeingResolved ->
604615
if Config.recursiveDebug then
605616
Log_.item "recursiveDebug %s [%d] is being resolved: assume dead@."
@@ -636,15 +647,15 @@ let rec resolveRecursiveRefs ~config
636647
in
637648
let xDeclIsDead =
638649
xDecl
639-
|> resolveRecursiveRefs ~config
650+
|> resolveRecursiveRefs ~state ~config
640651
~checkOptionalArg:checkOptionalArgFn ~deadDeclarations
641652
~level:(level + 1) ~orderedFiles ~refs:xRefs
642653
~refsBeingResolved
643654
in
644655
if xDecl.resolvedDead = None then allDepsResolved := false;
645656
not xDeclIsDead)
646657
in
647-
let isDead = decl |> declIsDead ~refs:newRefs in
658+
let isDead = decl |> declIsDead ~state ~refs:newRefs in
648659
let isResolved = (not isDead) || !allDepsResolved || level = 0 in
649660
if isResolved then (
650661
decl.resolvedDead <- Some isDead;
@@ -653,17 +664,17 @@ let rec resolveRecursiveRefs ~config
653664
|> DeadModules.markDead ~config
654665
~isType:(decl.declKind |> DeclKind.isType)
655666
~loc:decl.moduleLoc;
656-
if not (decl.pos |> doReportDead) then decl.report <- false;
667+
if not (doReportDead ~state decl.pos) then decl.report <- false;
657668
deadDeclarations := decl :: !deadDeclarations;
658669
if not (Decl.isToplevelValueWithSideEffects decl) then
659-
decl.pos |> ProcessDeadAnnotations.annotateDead)
670+
AnnotationState.annotate_dead state decl.pos)
660671
else (
661672
checkOptionalArgFn ~config decl;
662673
decl.path
663674
|> DeadModules.markLive ~config
664675
~isType:(decl.declKind |> DeclKind.isType)
665676
~loc:decl.moduleLoc;
666-
if decl.pos |> ProcessDeadAnnotations.isAnnotatedDead then
677+
if AnnotationState.is_annotated_dead state decl.pos then
667678
emitWarning ~config ~decl ~message:" is annotated @dead but is live"
668679
IncorrectDeadAnnotation);
669680
if config.DceConfig.cli.debug then
@@ -681,16 +692,18 @@ let rec resolveRecursiveRefs ~config
681692
refsString level);
682693
isDead
683694

684-
let reportDead ~config
685-
~checkOptionalArg:(checkOptionalArgFn : config:DceConfig.t -> decl -> unit)
686-
=
695+
let reportDead ~state ~config
696+
~checkOptionalArg:
697+
(checkOptionalArgFn :
698+
state:AnnotationState.t -> config:DceConfig.t -> decl -> unit) =
687699
let iterDeclInOrder ~deadDeclarations ~orderedFiles decl =
688700
let refs =
689701
match decl |> Decl.isValue with
690702
| true -> ValueReferences.find decl.pos
691703
| false -> TypeReferences.find decl.pos
692704
in
693-
resolveRecursiveRefs ~config ~checkOptionalArg:checkOptionalArgFn
705+
resolveRecursiveRefs ~state ~config
706+
~checkOptionalArg:(checkOptionalArgFn ~state)
694707
~deadDeclarations ~level:0 ~orderedFiles
695708
~refsBeingResolved:(ref PosSet.empty) ~refs decl
696709
|> ignore
@@ -711,7 +724,7 @@ let reportDead ~config
711724
PosHash.fold (fun _pos decl declarations -> decl :: declarations) decls []
712725
in
713726
let orderedFiles = Hashtbl.create 256 in
714-
iterFilesFromRootsToLeaves ~config
727+
iterFilesFromRootsToLeaves
715728
(let current = ref 0 in
716729
fun fileName ->
717730
incr current;

analysis/reanalyze/src/DeadOptionalArgs.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ let forceDelayedItems () =
8181
OptionalArgs.combine rFrom.optionalArgs rTo.optionalArgs
8282
| _ -> ())
8383

84-
let check ~config:_ decl =
84+
let check ~state ~config:_ decl =
8585
match decl with
8686
| {declKind = Value {optionalArgs}}
8787
when active ()
88-
&& not (ProcessDeadAnnotations.isAnnotatedGenTypeOrLive decl.pos) ->
88+
&& not (AnnotationState.is_annotated_gentype_or_live state decl.pos) ->
8989
optionalArgs
9090
|> OptionalArgs.iterUnused (fun s ->
9191
Log_.warning ~loc:(decl |> declGetLoc)

analysis/reanalyze/src/Reanalyze.ml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
open Common
22

3-
let loadCmtFile ~config cmtFilePath =
3+
let loadCmtFile ~annotation_state ~config cmtFilePath =
44
let cmt_infos = Cmt_format.read_cmt cmtFilePath in
55
let excludePath sourceFile =
66
config.DceConfig.cli.exclude_paths
@@ -37,14 +37,16 @@ let loadCmtFile ~config cmtFilePath =
3737
| false -> sourceFile);
3838
FileReferences.addFile sourceFile;
3939
if config.DceConfig.run.dce then
40-
cmt_infos |> DeadCode.processCmt ~config ~file:file_context ~cmtFilePath;
40+
cmt_infos
41+
|> DeadCode.processCmt ~state:annotation_state ~config ~file:file_context
42+
~cmtFilePath;
4143
if config.DceConfig.run.exception_ then
4244
cmt_infos |> Exception.processCmt ~file:file_context;
4345
if config.DceConfig.run.termination then
4446
cmt_infos |> Arnold.processCmt ~config ~file:file_context
4547
| _ -> ()
4648

47-
let processCmtFiles ~config ~cmtRoot =
49+
let processCmtFiles ~annotation_state ~config ~cmtRoot =
4850
let ( +++ ) = Filename.concat in
4951
match cmtRoot with
5052
| Some root ->
@@ -65,7 +67,7 @@ let processCmtFiles ~config ~cmtRoot =
6567
else if
6668
Filename.check_suffix absDir ".cmt"
6769
|| Filename.check_suffix absDir ".cmti"
68-
then absDir |> loadCmtFile ~config
70+
then absDir |> loadCmtFile ~annotation_state ~config
6971
in
7072
walkSubDirs ""
7173
| None ->
@@ -91,14 +93,15 @@ let processCmtFiles ~config ~cmtRoot =
9193
cmtFiles |> List.sort String.compare
9294
|> List.iter (fun cmtFile ->
9395
let cmtFilePath = Filename.concat libBsSourceDir cmtFile in
94-
cmtFilePath |> loadCmtFile ~config))
96+
cmtFilePath |> loadCmtFile ~annotation_state ~config))
9597

9698
let runAnalysis ~dce_config ~cmtRoot =
97-
processCmtFiles ~config:dce_config ~cmtRoot;
99+
let annotation_state = DeadCommon.AnnotationState.create () in
100+
processCmtFiles ~annotation_state ~config:dce_config ~cmtRoot;
98101
if dce_config.DceConfig.run.dce then (
99102
DeadException.forceDelayedItems ~config:dce_config;
100103
DeadOptionalArgs.forceDelayedItems ();
101-
DeadCommon.reportDead ~config:dce_config
104+
DeadCommon.reportDead ~state:annotation_state ~config:dce_config
102105
~checkOptionalArg:DeadOptionalArgs.check;
103106
WriteDeadAnnotations.write ~config:dce_config);
104107
if dce_config.DceConfig.run.exception_ then

0 commit comments

Comments
 (0)