Skip to content

Commit e071754

Browse files
authored
Add config for reporting transitively dead things. (#601)
* Add config for reporting transitively dead things. This is the normal behaviour: no change. When turned off, only the top dead things, and not the transitive ones, are reported. * Turn off the flag for reporting transitive dead things. * Comment. * Do not report empty modules when transitive reporting is off. As the only way for a module to be dead would be for it to be empty. * Make transitive reports configurable. * Restore default behaviour in tests. * comment * Update CHANGELOG.md
1 parent 721de24 commit e071754

File tree

7 files changed

+43
-12
lines changed

7 files changed

+43
-12
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
1313
## master
1414

15+
#### :rocket: New Feature
16+
17+
- Add configuration parameter `"transitive"` under `"reanalyze"` is `bsconfig.json`. If set to `false`, the analysis does not report transitively dead items. So removing the reported item individually can be done in isolation. This is a more fine-grained process for guiding the user to remove dead code one item at a time. https://github.com/rescript-lang/rescript-vscode/pull/601
18+
This feature comes from a conversation with @jfmengels on how https://github.com/jfmengels/elm-review is designed.
19+
1520
#### :bug: Bug Fix
1621

1722
- Fix issue where module paths in `-open` in `bsc-flags` such as "-open ReScriptJs.Js" were not recognized https://github.com/rescript-lang/rescript-vscode/issues/607

analysis/reanalyze/examples/deadcode/bsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"reanalyze": {
33
"analysis": ["dce"],
44
"suppress": [],
5-
"unsuppress": []
5+
"unsuppress": [],
6+
"transitive": true
67
},
78
"name": "sample-typescript-app",
89
"bsc-flags": ["-bs-super-errors -w a"],

analysis/reanalyze/src/Common.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ type decl = {
197197
pos: Lexing.position;
198198
posEnd: Lexing.position;
199199
posStart: Lexing.position;
200-
mutable resolved: bool;
200+
mutable resolvedDead: bool option;
201201
mutable report: bool;
202202
}
203203

analysis/reanalyze/src/DeadCommon.ml

+19-8
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ let addDeclaration_ ?posEnd ?posStart ~declKind ~path ~(loc : Location.t)
375375
pos;
376376
posEnd;
377377
posStart;
378-
resolved = false;
378+
resolvedDead = None;
379379
report = true;
380380
}
381381
in
@@ -536,12 +536,22 @@ module Decl = struct
536536
| VariantCase ->
537537
(WarningDeadType, "is a variant case which is never constructed")
538538
in
539+
let hasRefBelow () =
540+
let refs = ValueReferences.find decl.pos in
541+
let refIsBelow (pos : Lexing.position) =
542+
decl.pos.pos_fname <> pos.pos_fname
543+
|| decl.pos.pos_cnum < pos.pos_cnum
544+
&& (* not a function defined inside a function, e.g. not a callback *)
545+
decl.posEnd.pos_cnum < pos.pos_cnum
546+
in
547+
refs |> PosSet.exists refIsBelow
548+
in
539549
let shouldEmitWarning =
540550
(not insideReportedValue)
541-
&&
542-
match decl.path with
543-
| name :: _ when name |> Name.isUnderscore -> Config.reportUnderscore
544-
| _ -> true
551+
&& (match decl.path with
552+
| name :: _ when name |> Name.isUnderscore -> Config.reportUnderscore
553+
| _ -> true)
554+
&& (runConfig.transitive || not (hasRefBelow ()))
545555
in
546556
if shouldEmitWarning then (
547557
decl.path
@@ -563,7 +573,7 @@ let doReportDead pos = not (ProcessDeadAnnotations.isAnnotatedGenTypeOrDead pos)
563573
let rec resolveRecursiveRefs ~checkOptionalArg ~deadDeclarations ~level
564574
~orderedFiles ~refs ~refsBeingResolved decl : bool =
565575
match decl.pos with
566-
| _ when decl.resolved ->
576+
| _ when decl.resolvedDead <> None ->
567577
if Config.recursiveDebug then
568578
Log_.item "recursiveDebug %s [%d] already resolved@."
569579
(decl.path |> Path.toString)
@@ -609,13 +619,13 @@ let rec resolveRecursiveRefs ~checkOptionalArg ~deadDeclarations ~level
609619
~level:(level + 1) ~orderedFiles ~refs:xRefs
610620
~refsBeingResolved
611621
in
612-
if not xDecl.resolved then allDepsResolved := false;
622+
if xDecl.resolvedDead = None then allDepsResolved := false;
613623
not xDeclIsDead)
614624
in
615625
let isDead = decl |> declIsDead ~refs:newRefs in
616626
let isResolved = (not isDead) || !allDepsResolved || level = 0 in
617627
if isResolved then (
618-
decl.resolved <- true;
628+
decl.resolvedDead <- Some isDead;
619629
if isDead then (
620630
decl.path
621631
|> DeadModules.markDead
@@ -691,4 +701,5 @@ let reportDead ~checkOptionalArg =
691701
let sortedDeadDeclarations =
692702
!deadDeclarations |> List.fast_sort Decl.compareForReporting
693703
in
704+
(* XXX *)
694705
sortedDeadDeclarations |> List.iter Decl.report

analysis/reanalyze/src/DeadModules.ml

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
let active () = true
1+
let active () =
2+
(* When transitive reporting is off, the only dead modules would be empty modules *)
3+
RunConfig.runConfig.transitive
4+
25
let table = Hashtbl.create 1
36

47
let markDead ~isType ~loc path =

analysis/reanalyze/src/Paths.ml

+8-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ module Config = struct
7373
(* if no "analysis" specified, default to dce *)
7474
RunConfig.dce ()
7575

76+
let readTransitive conf =
77+
match Json.get "transitive" conf with
78+
| Some True -> RunConfig.transitive true
79+
| Some False -> RunConfig.transitive false
80+
| _ -> ()
81+
7682
(* Read the config from bsconfig.json and apply it to runConfig and suppress and unsuppress *)
7783
let processBsconfig () =
7884
Lazy.force setReScriptProjectRoot;
@@ -87,7 +93,8 @@ module Config = struct
8793
| Some conf ->
8894
readSuppress conf;
8995
readUnsuppress conf;
90-
readAnalysis conf
96+
readAnalysis conf;
97+
readTransitive conf
9198
| None ->
9299
(* if no "analysis" specified, default to dce *)
93100
RunConfig.dce ()))

analysis/reanalyze/src/RunConfig.ml

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ type t = {
55
mutable projectRoot: string;
66
mutable suppress: string list;
77
mutable termination: bool;
8+
mutable transitive: bool;
89
mutable unsuppress: string list;
910
}
1011

@@ -16,6 +17,7 @@ let runConfig =
1617
projectRoot = "";
1718
suppress = [];
1819
termination = false;
20+
transitive = true;
1921
unsuppress = [];
2022
}
2123

@@ -27,3 +29,5 @@ let all () =
2729
let dce () = runConfig.dce <- true
2830
let exception_ () = runConfig.exception_ <- true
2931
let termination () = runConfig.termination <- true
32+
33+
let transitive b = runConfig.transitive <- b

0 commit comments

Comments
 (0)