diff --git a/CHANGELOG.md b/CHANGELOG.md index b1e7a3ac94..640f5dc67d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ #### :bug: Bug fix +- Fix reanalyze optional-argument diagnostics for functions passed or returned as first-class values. https://github.com/rescript-lang/rescript/pull/8321 + #### :memo: Documentation #### :nail_care: Polish diff --git a/analysis/reanalyze/src/cross_file_items.ml b/analysis/reanalyze/src/cross_file_items.ml index 81ccc95111..6d0554a12d 100644 --- a/analysis/reanalyze/src/cross_file_items.ml +++ b/analysis/reanalyze/src/cross_file_items.ml @@ -16,24 +16,36 @@ type optional_arg_call = { type function_ref = {pos_from: Lexing.position; pos_to: Lexing.position} +type optional_arg_value_escape = { + pos_from: Lexing.position; + pos_to: Lexing.position; +} + (** {2 Types} *) type t = { exception_refs: exception_ref list; optional_arg_calls: optional_arg_call list; function_refs: function_ref list; + optional_arg_value_escapes: optional_arg_value_escape list; } type builder = { mutable exception_refs: exception_ref list; mutable optional_arg_calls: optional_arg_call list; mutable function_refs: function_ref list; + mutable optional_arg_value_escapes: optional_arg_value_escape list; } (** {2 Builder API} *) let create_builder () : builder = - {exception_refs = []; optional_arg_calls = []; function_refs = []} + { + exception_refs = []; + optional_arg_calls = []; + function_refs = []; + optional_arg_value_escapes = []; + } let add_exception_ref (b : builder) ~exception_path ~loc_from = b.exception_refs <- {exception_path; loc_from} :: b.exception_refs @@ -46,6 +58,10 @@ let add_optional_arg_call (b : builder) ~pos_from ~pos_to ~arg_names let add_function_reference (b : builder) ~pos_from ~pos_to = b.function_refs <- {pos_from; pos_to} :: b.function_refs +let add_optional_arg_value_escape (b : builder) ~pos_from ~pos_to = + b.optional_arg_value_escapes <- + {pos_from; pos_to} :: b.optional_arg_value_escapes + (** {2 Merge API} *) let merge_all (builders : builder list) : t = @@ -56,7 +72,15 @@ let merge_all (builders : builder list) : t = builders |> List.concat_map (fun b -> b.optional_arg_calls) in let function_refs = builders |> List.concat_map (fun b -> b.function_refs) in - {exception_refs; optional_arg_calls; function_refs} + let optional_arg_value_escapes = + builders |> List.concat_map (fun b -> b.optional_arg_value_escapes) + in + { + exception_refs; + optional_arg_calls; + function_refs; + optional_arg_value_escapes; + } (** {2 Builder extraction for reactive merge} *) @@ -65,6 +89,7 @@ let builder_to_t (builder : builder) : t = exception_refs = builder.exception_refs; optional_arg_calls = builder.optional_arg_calls; function_refs = builder.function_refs; + optional_arg_value_escapes = builder.optional_arg_value_escapes; } (** {2 Processing API} *) diff --git a/analysis/reanalyze/src/cross_file_items.mli b/analysis/reanalyze/src/cross_file_items.mli index 1fb9b92cbf..4863b92e73 100644 --- a/analysis/reanalyze/src/cross_file_items.mli +++ b/analysis/reanalyze/src/cross_file_items.mli @@ -18,12 +18,18 @@ type optional_arg_call = { type function_ref = {pos_from: Lexing.position; pos_to: Lexing.position} +type optional_arg_value_escape = { + pos_from: Lexing.position; + pos_to: Lexing.position; +} + (** {2 Types} *) type t = { exception_refs: exception_ref list; optional_arg_calls: optional_arg_call list; function_refs: function_ref list; + optional_arg_value_escapes: optional_arg_value_escape list; } (** Immutable cross-file items - for processing after merge *) @@ -49,7 +55,10 @@ val add_optional_arg_call : val add_function_reference : builder -> pos_from:Lexing.position -> pos_to:Lexing.position -> unit -(** Add a cross-file function reference (for optional args combining). *) + +val add_optional_arg_value_escape : + builder -> pos_from:Lexing.position -> pos_to:Lexing.position -> unit +(** Record an optional-arg function used as a first-class value. *) (** {2 Merge API} *) diff --git a/analysis/reanalyze/src/cross_file_items_store.ml b/analysis/reanalyze/src/cross_file_items_store.ml index 3a07beb11d..ec316d6b26 100644 --- a/analysis/reanalyze/src/cross_file_items_store.ml +++ b/analysis/reanalyze/src/cross_file_items_store.ml @@ -28,6 +28,15 @@ let iter_function_refs t f = (fun _path items -> List.iter f items.Cross_file_items.function_refs) r +let iter_optional_arg_value_escapes t f = + match t with + | Frozen cfi -> List.iter f cfi.Cross_file_items.optional_arg_value_escapes + | Reactive r -> + Reactive.iter + (fun _path items -> + List.iter f items.Cross_file_items.optional_arg_value_escapes) + r + (** Compute optional args state from calls and function references. Returns a map from position to final OptionalArgs.t state. Pure function - does not mutate declarations. *) @@ -65,3 +74,27 @@ let compute_optional_args_state (store : t) ~find_decl ~is_live : set_state pos_from updated_from; set_state pos_to updated_to)); state + +let compute_live_optional_arg_value_escapes (store : t) ~is_live : Pos_set.t = + let escapes = ref Pos_set.empty in + iter_optional_arg_value_escapes store + (fun {Cross_file_items.pos_from; pos_to} -> + if is_live pos_from then escapes := Pos_set.add pos_to !escapes); + let function_refs = ref [] in + iter_function_refs store (fun {Cross_file_items.pos_from; pos_to} -> + if is_live pos_from then + function_refs := (pos_from, pos_to) :: !function_refs); + (* A function reference aliases both declaration positions. Close escapes over + the undirected links so aliases and interface/implementation pairs agree. *) + let rec propagate escapes = + let propagated = + List.fold_left + (fun escapes (pos_from, pos_to) -> + if Pos_set.mem pos_from escapes then Pos_set.add pos_to escapes + else if Pos_set.mem pos_to escapes then Pos_set.add pos_from escapes + else escapes) + escapes !function_refs + in + if Pos_set.equal propagated escapes then escapes else propagate propagated + in + propagate !escapes diff --git a/analysis/reanalyze/src/cross_file_items_store.mli b/analysis/reanalyze/src/cross_file_items_store.mli index f8da5db43c..d3729d6339 100644 --- a/analysis/reanalyze/src/cross_file_items_store.mli +++ b/analysis/reanalyze/src/cross_file_items_store.mli @@ -22,9 +22,17 @@ val iter_optional_arg_calls : val iter_function_refs : t -> (Cross_file_items.function_ref -> unit) -> unit (** Iterate over all function refs *) +val iter_optional_arg_value_escapes : + t -> (Cross_file_items.optional_arg_value_escape -> unit) -> unit +(** Iterate over optional-arg functions used as first-class values *) + val compute_optional_args_state : t -> find_decl:(Lexing.position -> Decl.t option) -> is_live:(Lexing.position -> bool) -> Optional_args_state.t (** Compute optional args state from calls and function references *) + +val compute_live_optional_arg_value_escapes : + t -> is_live:(Lexing.position -> bool) -> Pos_set.t +(** Compute optional-arg declarations with live first-class value escapes *) diff --git a/analysis/reanalyze/src/dead_common.ml b/analysis/reanalyze/src/dead_common.ml index a843d68606..a3f39096f8 100644 --- a/analysis/reanalyze/src/dead_common.ml +++ b/analysis/reanalyze/src/dead_common.ml @@ -124,11 +124,13 @@ let addDeclaration_ ~config ~decls ~(file : File_context.t) ?pos_end ?pos_start Declarations.add decls pos decl) let add_value_declaration ~config ~decls ~file ?(is_toplevel = true) - ~(loc : Location.t) ~module_loc ?(optional_args = Optional_args.empty) ~path - ~side_effects name = + ?(reports_optional_args = false) ~(loc : Location.t) ~module_loc + ?(optional_args = Optional_args.empty) ~path ~side_effects name = name |> addDeclaration_ ~config ~decls ~file - ~decl_kind:(Value {is_toplevel; optional_args; side_effects}) + ~decl_kind: + (Value + {is_toplevel; reports_optional_args; optional_args; side_effects}) ~loc ~module_loc ~path (** Create a dead code issue. Pure - no side effects. *) diff --git a/analysis/reanalyze/src/dead_optional_args.ml b/analysis/reanalyze/src/dead_optional_args.ml index 2131181539..f1ff37407f 100644 --- a/analysis/reanalyze/src/dead_optional_args.ml +++ b/analysis/reanalyze/src/dead_optional_args.ml @@ -2,25 +2,6 @@ open Dead_common let active () = true -let add_function_reference ~config ~decls ~cross_file ~(loc_from : Location.t) - ~(loc_to : Location.t) = - if active () then - let pos_to = loc_to.loc_start in - let pos_from = loc_from.loc_start in - (* Check if target has optional args - for filtering and debug logging *) - let should_add = - match Declarations.find_opt_builder decls pos_to with - | Some {decl_kind = Value {optional_args}} -> - not (Optional_args.is_empty optional_args) - | _ -> false - in - if should_add then ( - if config.Dce_config.cli.debug then - Log_.item "OptionalArgs.addFunctionReference %s %s@." - (pos_from |> Pos.to_string) - (pos_to |> Pos.to_string); - Cross_file_items.add_function_reference cross_file ~pos_from ~pos_to) - let rec has_optional_args (texpr : Types.type_expr) = match texpr.desc with | _ when not (active ()) -> false @@ -30,6 +11,17 @@ let rec has_optional_args (texpr : Types.type_expr) = | Tsubst t -> has_optional_args t | _ -> false +let add_function_reference ~config ~cross_file ~(loc_from : Location.t) + ~(loc_to : Location.t) ~type_from ~type_to = + if has_optional_args type_from && has_optional_args type_to then ( + let pos_to = loc_to.loc_start in + let pos_from = loc_from.loc_start in + if config.Dce_config.cli.debug then + Log_.item "OptionalArgs.addFunctionReference %s %s@." + (pos_from |> Pos.to_string) + (pos_to |> Pos.to_string); + Cross_file_items.add_function_reference cross_file ~pos_from ~pos_to) + let rec from_type_expr (texpr : Types.type_expr) = match texpr.desc with | _ when not (active ()) -> [] @@ -39,6 +31,18 @@ let rec from_type_expr (texpr : Types.type_expr) = | Tsubst t -> from_type_expr t | _ -> [] +let rec from_type_expr_with_arity (texpr : Types.type_expr) arity = + if arity <= 0 then [] + else + match texpr.desc with + | _ when not (active ()) -> [] + | Tarrow ({lbl = Optional {txt = s}}, t_to, _, _) -> + s :: from_type_expr_with_arity t_to (arity - 1) + | Tarrow (_, t_to, _, _) -> from_type_expr_with_arity t_to (arity - 1) + | Tlink t -> from_type_expr_with_arity t arity + | Tsubst t -> from_type_expr_with_arity t arity + | _ -> [] + let add_references ~config ~cross_file ~(loc_from : Location.t) ~(loc_to : Location.t) ~(binding : Location.t) ~path (arg_names, arg_names_maybe) = @@ -59,10 +63,12 @@ let add_references ~config ~cross_file ~(loc_from : Location.t) (** Check for optional args issues. Returns issues instead of logging. Uses optional_args_state map for final computed state. *) -let check ~optional_args_state ~ann_store ~config:_ decl : Issue.t list = +let check ~optional_args_state ~optional_arg_value_escapes ~ann_store ~config:_ + decl : Issue.t list = match decl with - | {Decl.decl_kind = Value {optional_args}} + | {Decl.decl_kind = Value {reports_optional_args = true; optional_args}} when active () + && (not (Pos_set.mem decl.pos optional_arg_value_escapes)) && not (Annotation_store.is_annotated_gentype_or_live ann_store decl.pos) -> diff --git a/analysis/reanalyze/src/dead_value.ml b/analysis/reanalyze/src/dead_value.ml index 3fd1c343b7..69c92f09db 100644 --- a/analysis/reanalyze/src/dead_value.ml +++ b/analysis/reanalyze/src/dead_value.ml @@ -2,6 +2,14 @@ open Dead_common +(** Identity avoids conflating generated expressions that share source locations. *) +module Expression_table = Hashtbl.Make (struct + type t = Typedtree.expression + + let equal = ( == ) + let hash (e : t) = Hashtbl.hash e.exp_loc +end) + let check_any_value_binding_with_no_side_effects ~config ~decls ~file ~(module_path : Module_path.t) ({vb_pat = {pat_desc}; vb_expr = expr; vb_loc = loc} : @@ -27,13 +35,27 @@ let collect_value_binding ~config ~decls ~file ~(current_binding : Location.t) ({pat_desc = Tpat_any}, id, {loc = {loc_start; loc_ghost} as loc}) when (not loc_ghost) && not vb.vb_loc.loc_ghost -> let name = Ident.name id |> Name.create ~is_interface:false in - let optional_args = - vb.vb_expr.exp_type |> Dead_optional_args.from_type_expr - |> Optional_args.from_list + let optional_args, reports_optional_args = + match vb.vb_expr.exp_desc with + | Texp_function {arity = Some arity; _} -> + ( vb.vb_expr.exp_type + |> (fun texpr -> + Dead_optional_args.from_type_expr_with_arity texpr arity) + |> Optional_args.from_list, + true ) + | Texp_function _ -> + ( vb.vb_expr.exp_type |> Dead_optional_args.from_type_expr + |> Optional_args.from_list, + true ) + | _ -> + ( vb.vb_expr.exp_type |> Dead_optional_args.from_type_expr + |> Optional_args.from_list, + false ) in let exists = match Declarations.find_opt_builder decls loc_start with | Some {decl_kind = Value r} -> + r.reports_optional_args <- reports_optional_args; r.optional_args <- optional_args; true | _ -> false @@ -50,7 +72,8 @@ let collect_value_binding ~config ~decls ~file ~(current_binding : Location.t) let side_effects = Side_effects.check_expr vb.vb_expr in name |> add_value_declaration ~config ~decls ~file ~is_toplevel ~loc - ~module_loc:module_path.loc ~optional_args ~path ~side_effects); + ~module_loc:module_path.loc ~reports_optional_args ~optional_args + ~path ~side_effects); (match Declarations.find_opt_builder decls loc_start with | None -> () | Some decl -> @@ -109,12 +132,19 @@ let process_optional_args ~config ~cross_file ~exp_type ~(loc_from : Location.t) |> Dead_optional_args.add_references ~config ~cross_file ~loc_from ~loc_to ~binding ~path) -let rec collect_expr ~config ~refs ~file_deps ~cross_file +let rec collect_expr ~config ~refs ~file_deps ~cross_file ~direct_callees ~(last_binding : Location.t) super self (e : Typedtree.expression) = let loc_from = e.exp_loc in let binding = last_binding in + let add_optional_arg_value_escape ~val_type pos_from pos_to = + if Dead_optional_args.has_optional_args val_type then + Cross_file_items.add_optional_arg_value_escape cross_file ~pos_from + ~pos_to + in (match e.exp_desc with - | Texp_ident (_path, _, {Types.val_loc = {loc_ghost = false; _} as loc_to}) -> + | Texp_ident + (_path, _, {Types.val_loc = {loc_ghost = false; _} as loc_to; val_type}) + -> (* if Path.name _path = "rc" then assert false; *) if loc_from = loc_to && _path |> Path.name = "emptyArray" then ( (* Work around lowercase jsx with no children producing an artifact `emptyArray` @@ -125,9 +155,15 @@ let rec collect_expr ~config ~refs ~file_deps ~cross_file (loc_to.loc_start |> Pos.to_string); References.add_value_ref refs ~pos_to:loc_to.loc_start ~pos_from:Location.none.loc_start) - else + else ( add_value_reference ~config ~refs ~file_deps ~binding - ~add_file_reference:true ~loc_from ~loc_to + ~add_file_reference:true ~loc_from ~loc_to; + if not (Expression_table.mem direct_callees e) then + let pos_from = + if binding = Location.none then loc_from.loc_start + else binding.loc_start + in + add_optional_arg_value_escape ~val_type pos_from loc_to.loc_start) | Texp_apply { funct = @@ -136,9 +172,10 @@ let rec collect_expr ~config ~refs ~file_deps ~cross_file Texp_ident (path, _, {Types.val_loc = {loc_ghost = false; _} as loc_to}); exp_type; - }; + } as direct_callee; args; } -> + Expression_table.replace direct_callees direct_callee (); args |> process_optional_args ~config ~cross_file ~exp_type ~loc_from:(loc_from : Location.t) @@ -155,7 +192,7 @@ let rec collect_expr ~config ~refs ~file_deps ~cross_file Texp_ident (path, _, {Types.val_loc = {loc_ghost = false; _} as loc_to}); exp_type; - }; + } as direct_callee; }; ], { @@ -180,6 +217,7 @@ let rec collect_expr ~config ~refs ~file_deps ~cross_file when Ident.name id_arg = "arg" && Ident.name eta_arg = "eta" && Path.name id_arg2 = "arg" -> + Expression_table.replace direct_callees direct_callee (); args |> process_optional_args ~config ~cross_file ~exp_type ~loc_from:(loc_from : Location.t) @@ -213,8 +251,8 @@ let rec collect_expr ~config ~refs ~file_deps ~cross_file -> (* Punned field in OCaml projects has ghost location in expression *) let e = {e with exp_loc = {exp_loc with loc_ghost = false}} in - collect_expr ~config ~refs ~file_deps ~cross_file ~last_binding - super self e + collect_expr ~config ~refs ~file_deps ~cross_file ~direct_callees + ~last_binding super self e |> ignore | _ -> ()) | _ -> ()); @@ -351,13 +389,16 @@ let rec process_signature_item ~config ~decls ~file ~do_types ~do_values val_type |> Dead_optional_args.from_type_expr |> Optional_args.from_list in + let reports_optional_args = + not (Optional_args.is_empty optional_args) + in (* if Ident.name id = "someValue" then Printf.printf "XXX %s\n" (Ident.name id); *) Ident.name id |> Name.create ~is_interface:false |> add_value_declaration ~config ~decls ~file ~loc ~module_loc - ~optional_args ~path ~side_effects:false + ~reports_optional_args ~optional_args ~path ~side_effects:false | Sig_module (id, {Types.md_type = module_type; md_loc = module_loc}, _) | Sig_modtype (id, {Types.mtd_type = Some module_type; mtd_loc = module_loc}) -> @@ -382,6 +423,7 @@ let rec process_signature_item ~config ~decls ~file ~do_types ~do_values (* Traverse the AST *) let traverse_structure ~config ~decls ~refs ~file_deps ~cross_file ~file ~do_types ~do_externals (structure : Typedtree.structure) : unit = + let direct_callees = Expression_table.create 16 in let rec create_mapper (last_binding : Location.t) (module_path : Module_path.t) = let super = Tast_mapper.default in @@ -391,8 +433,8 @@ let traverse_structure ~config ~decls ~refs ~file_deps ~cross_file ~file expr = (fun _self e -> e - |> collect_expr ~config ~refs ~file_deps ~cross_file ~last_binding - super mapper); + |> collect_expr ~config ~refs ~file_deps ~cross_file ~direct_callees + ~last_binding super mapper); pat = (fun _self p -> p @@ -530,25 +572,27 @@ let traverse_structure ~config ~decls ~refs ~file_deps ~cross_file ~file mapper.structure mapper structure |> ignore (* Merge a location's references to another one's *) -let process_value_dependency ~config ~decls ~refs ~file_deps ~cross_file +let process_value_dependency ~config ~refs ~file_deps ~cross_file ( ({ val_loc = {loc_start = {pos_fname = fn_to} as pos_to; loc_ghost = ghost1} as loc_to; + val_type = type_to; } : Types.value_description), ({ val_loc = {loc_start = {pos_fname = fn_from} as pos_from; loc_ghost = ghost2} as loc_from; + val_type = type_from; } : Types.value_description) ) = if (not ghost1) && (not ghost2) && pos_to <> pos_from then ( let add_file_reference = file_is_implementation_of fn_to fn_from in add_value_reference ~config ~refs ~file_deps ~binding:Location.none ~add_file_reference ~loc_from ~loc_to; - Dead_optional_args.add_function_reference ~config ~decls ~cross_file - ~loc_from ~loc_to) + Dead_optional_args.add_function_reference ~config ~cross_file ~loc_from + ~loc_to ~type_from ~type_to) let process_structure ~config ~decls ~refs ~file_deps ~cross_file ~file ~cmt_value_dependencies ~do_types ~do_externals @@ -557,5 +601,4 @@ let process_structure ~config ~decls ~refs ~file_deps ~cross_file ~file ~do_externals structure; let value_dependencies = cmt_value_dependencies |> List.rev in value_dependencies - |> List.iter - (process_value_dependency ~config ~decls ~refs ~file_deps ~cross_file) + |> List.iter (process_value_dependency ~config ~refs ~file_deps ~cross_file) diff --git a/analysis/reanalyze/src/decl.ml b/analysis/reanalyze/src/decl.ml index aa457b3f5b..9ddaad60ac 100644 --- a/analysis/reanalyze/src/decl.ml +++ b/analysis/reanalyze/src/decl.ml @@ -7,6 +7,7 @@ module Kind = struct | VariantCase | Value of { is_toplevel: bool; + mutable reports_optional_args: bool; mutable optional_args: Optional_args.t; side_effects: bool; } diff --git a/analysis/reanalyze/src/reactive_merge.ml b/analysis/reanalyze/src/reactive_merge.ml index 6c376e0efa..14dc222d71 100644 --- a/analysis/reanalyze/src/reactive_merge.ml +++ b/analysis/reanalyze/src/reactive_merge.ml @@ -88,6 +88,8 @@ let create (source : (string, Dce_file_processing.file_data option) Reactive.t) exception_refs = a.exception_refs @ b.exception_refs; optional_arg_calls = a.optional_arg_calls @ b.optional_arg_calls; function_refs = a.function_refs @ b.function_refs; + optional_arg_value_escapes = + a.optional_arg_value_escapes @ b.optional_arg_value_escapes; }) () in @@ -225,17 +227,22 @@ let collect_cross_file_items (t : t) : Cross_file_items.t = let exception_refs = ref [] in let optional_arg_calls = ref [] in let function_refs = ref [] in + let optional_arg_value_escapes = ref [] in Reactive.iter (fun _path items -> exception_refs := items.Cross_file_items.exception_refs @ !exception_refs; optional_arg_calls := items.Cross_file_items.optional_arg_calls @ !optional_arg_calls; - function_refs := items.Cross_file_items.function_refs @ !function_refs) + function_refs := items.Cross_file_items.function_refs @ !function_refs; + optional_arg_value_escapes := + items.Cross_file_items.optional_arg_value_escapes + @ !optional_arg_value_escapes) t.cross_file_items; { Cross_file_items.exception_refs = !exception_refs; optional_arg_calls = !optional_arg_calls; function_refs = !function_refs; + optional_arg_value_escapes = !optional_arg_value_escapes; } (** Convert reactive file deps to FileDeps.t for solver. diff --git a/analysis/reanalyze/src/reanalyze.ml b/analysis/reanalyze/src/reanalyze.ml index 062df5c6ee..b96ad7a793 100644 --- a/analysis/reanalyze/src/reanalyze.ml +++ b/analysis/reanalyze/src/reanalyze.ml @@ -347,11 +347,16 @@ let run_analysis ~dce_config ~cmt_root ~reactive_collection ~reactive_merge Cross_file_items_store.compute_optional_args_state cross_file_store ~find_decl ~is_live in + let optional_arg_value_escapes = + Cross_file_items_store.compute_live_optional_arg_value_escapes + cross_file_store ~is_live + in (* Iterate live declarations and check for optional args issues *) let issues = ref [] in Reactive_solver.iter_live_decls ~t:solver (fun decl -> let decl_issues = - Dead_optional_args.check ~optional_args_state ~ann_store + Dead_optional_args.check ~optional_args_state + ~optional_arg_value_escapes ~ann_store ~config:dce_config decl in issues := List.rev_append decl_issues !issues); @@ -399,13 +404,18 @@ let run_analysis ~dce_config ~cmt_root ~reactive_collection ~reactive_merge ~find_decl:(Declaration_store.find_opt decl_store) ~is_live in + let optional_arg_value_escapes = + Cross_file_items_store.compute_live_optional_arg_value_escapes + cross_file_store ~is_live + in (* Collect optional args issues only for live declarations *) let optional_args_issues = Declaration_store.fold (fun _pos decl acc -> if Decl.is_live decl then let issues = - Dead_optional_args.check ~optional_args_state ~ann_store + Dead_optional_args.check ~optional_args_state + ~optional_arg_value_escapes ~ann_store ~config:dce_config decl in List.rev_append issues acc diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt b/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt index 10c70d7cd1..8588578ef6 100644 --- a/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt +++ b/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt @@ -32,6 +32,52 @@ addTypeReference _none_:1:-1 --> ComponentAsProp.res:6:20 addTypeReference _none_:1:-1 --> ComponentAsProp.res:6:34 addValueReference ComponentAsProp.res:6:4 --> React.res:16:0 + Scanning ContextOptionalArgs.cmt Source:ContextOptionalArgs.res + addValueDeclaration +dispatchNotificationContext ContextOptionalArgs.res:2:6 path:+ContextOptionalArgs.NotificationProvider + addValueDeclaration +make ContextOptionalArgs.res:8:8 path:+ContextOptionalArgs.NotificationProvider.Provider + addValueDeclaration +make ContextOptionalArgs.res:12:6 path:+ContextOptionalArgs.NotificationProvider + addValueDeclaration +useNotification ContextOptionalArgs.res:22:6 path:+ContextOptionalArgs.NotificationProvider + addValueDeclaration +make ContextOptionalArgs.res:27:6 path:+ContextOptionalArgs.ComponentUsingAction + addValueDeclaration +make ContextOptionalArgs.res:41:6 path:+ContextOptionalArgs.ComponentNotUsingAction + addValueDeclaration +make ContextOptionalArgs.res:55:4 path:+ContextOptionalArgs + addRecordLabelDeclaration children ContextOptionalArgs.res:12:14 path:+ContextOptionalArgs.NotificationProvider.props + addValueReference ContextOptionalArgs.res:2:6 --> React.res:81:0 + addValueReference ContextOptionalArgs.res:8:8 --> ContextOptionalArgs.res:2:6 + addValueReference ContextOptionalArgs.res:8:8 --> React.res:77:2 + addRecordLabelDeclaration children ContextOptionalArgs.res:12:14 path:+ContextOptionalArgs.NotificationProvider.props + addValueDeclaration +dispatchNotification ContextOptionalArgs.res:13:8 path:+ContextOptionalArgs.NotificationProvider + addValueReference ContextOptionalArgs.res:13:8 --> ContextOptionalArgs.res:13:43 + addValueReference ContextOptionalArgs.res:13:8 --> ContextOptionalArgs.res:15:13 + addValueReference ContextOptionalArgs.res:13:8 --> ContextOptionalArgs.res:13:43 + addValueReference ContextOptionalArgs.res:13:8 --> ContextOptionalArgs.res:13:32 + addValueReference ContextOptionalArgs.res:19:5 --> ContextOptionalArgs.res:8:8 + addValueReference ContextOptionalArgs.res:19:20 --> ContextOptionalArgs.res:13:8 + addValueReference ContextOptionalArgs.res:19:43 --> ContextOptionalArgs.res:12:14 + addTypeReference _none_:1:-1 --> ContextOptionalArgs.res:12:14 + addValueReference ContextOptionalArgs.res:12:6 --> React.res:16:0 + DeadOptionalArgs.addReferences React.useContext called with optional argNames: argNamesMaybe: ContextOptionalArgs.res:22:30 + addValueReference ContextOptionalArgs.res:22:6 --> ContextOptionalArgs.res:2:6 + addValueReference ContextOptionalArgs.res:22:6 --> React.res:250:0 + addValueDeclaration +dispatchNotification ContextOptionalArgs.res:28:8 path:+ContextOptionalArgs.ComponentUsingAction + DeadOptionalArgs.addReferences NotificationProvider.useNotification called with optional argNames: argNamesMaybe: ContextOptionalArgs.res:28:31 + addValueReference ContextOptionalArgs.res:28:8 --> ContextOptionalArgs.res:22:6 + addValueReference ContextOptionalArgs.res:35:4 --> React.res:3:0 + DeadOptionalArgs.addReferences dispatchNotification called with optional argNames:action argNamesMaybe: ContextOptionalArgs.res:31:6 + addValueReference ContextOptionalArgs.res:31:6 --> ContextOptionalArgs.res:28:8 + addValueReference ContextOptionalArgs.res:30:4 --> React.res:150:0 + addValueReference ContextOptionalArgs.res:27:6 --> React.res:16:0 + addValueDeclaration +dispatchNotification ContextOptionalArgs.res:42:8 path:+ContextOptionalArgs.ComponentNotUsingAction + DeadOptionalArgs.addReferences NotificationProvider.useNotification called with optional argNames: argNamesMaybe: ContextOptionalArgs.res:42:31 + addValueReference ContextOptionalArgs.res:42:8 --> ContextOptionalArgs.res:22:6 + addValueReference ContextOptionalArgs.res:49:4 --> React.res:3:0 + DeadOptionalArgs.addReferences dispatchNotification called with optional argNames: argNamesMaybe: ContextOptionalArgs.res:45:6 + addValueReference ContextOptionalArgs.res:45:6 --> ContextOptionalArgs.res:42:8 + addValueReference ContextOptionalArgs.res:44:4 --> React.res:150:0 + addValueReference ContextOptionalArgs.res:41:6 --> React.res:16:0 + addValueReference ContextOptionalArgs.res:56:3 --> ContextOptionalArgs.res:12:6 + addValueReference ContextOptionalArgs.res:57:5 --> ContextOptionalArgs.res:27:6 + addValueReference ContextOptionalArgs.res:58:5 --> ContextOptionalArgs.res:41:6 + addValueReference ContextOptionalArgs.res:55:4 --> React.res:16:0 Scanning CreateErrorHandler1.cmt Source:CreateErrorHandler1.res addValueDeclaration +notification CreateErrorHandler1.res:3:6 path:+CreateErrorHandler1.Error1 addValueReference CreateErrorHandler1.res:3:6 --> CreateErrorHandler1.res:3:21 @@ -42,6 +88,14 @@ addValueDeclaration +notification CreateErrorHandler2.res:3:6 path:+CreateErrorHandler2.Error2 addValueReference CreateErrorHandler2.res:3:6 --> CreateErrorHandler2.res:3:21 addValueReference ErrorHandler.resi:3:2 --> CreateErrorHandler2.res:3:6 + Scanning CrossFileOptionalArgProvider.cmt Source:CrossFileOptionalArgProvider.res + addValueDeclaration +formatDate CrossFileOptionalArgProvider.res:1:4 path:+CrossFileOptionalArgProvider + addValueReference CrossFileOptionalArgProvider.res:1:4 --> CrossFileOptionalArgProvider.res:1:26 + Scanning CrossFileOptionalArgValueUse.cmt Source:CrossFileOptionalArgValueUse.res + addValueDeclaration +liveReturnCaller CrossFileOptionalArgValueUse.res:1:4 path:+CrossFileOptionalArgValueUse + addValueReference CrossFileOptionalArgValueUse.res:1:4 --> CrossFileOptionalArgProvider.res:1:4 + DeadOptionalArgs.addReferences liveReturnCaller called with optional argNames: argNamesMaybe: CrossFileOptionalArgValueUse.res:5:8 + addValueReference CrossFileOptionalArgValueUse.res:5:8 --> CrossFileOptionalArgValueUse.res:1:4 Scanning DeadCodeImplementation.cmt Source:DeadCodeImplementation.res addValueDeclaration +x DeadCodeImplementation.res:2:6 path:+DeadCodeImplementation.M addValueReference DeadCodeInterface.res:2:2 --> DeadCodeImplementation.res:2:6 @@ -962,6 +1016,21 @@ addVariantCaseDeclaration Foo InnerModuleTypes.res:2:11 path:+InnerModuleTypes.I.t Scanning InnerModuleTypes.cmti Source:InnerModuleTypes.resi addVariantCaseDeclaration Foo InnerModuleTypes.resi:2:11 path:InnerModuleTypes.I.t + Scanning InterfaceOptionalArgEscape.cmt Source:InterfaceOptionalArgEscape.res + addValueDeclaration +escaped InterfaceOptionalArgEscape.res:1:4 path:+InterfaceOptionalArgEscape + addValueDeclaration +takesFn InterfaceOptionalArgEscape.res:3:4 path:+InterfaceOptionalArgEscape + addValueReference InterfaceOptionalArgEscape.res:1:4 --> InterfaceOptionalArgEscape.res:1:23 + addValueReference InterfaceOptionalArgEscape.res:5:8 --> InterfaceOptionalArgEscape.res:1:4 + addValueReference InterfaceOptionalArgEscape.res:5:0 --> InterfaceOptionalArgEscape.res:3:4 + addValueReference InterfaceOptionalArgEscape.resi:1:0 --> InterfaceOptionalArgEscape.res:1:4 + OptionalArgs.addFunctionReference InterfaceOptionalArgEscape.resi:1:0 InterfaceOptionalArgEscape.res:1:4 + Scanning InterfaceOptionalArgEscape.cmti Source:InterfaceOptionalArgEscape.resi + addValueDeclaration +escaped InterfaceOptionalArgEscape.resi:1:0 path:InterfaceOptionalArgEscape + Scanning InterfaceOptionalArgEscapeUse.cmt Source:InterfaceOptionalArgEscapeUse.res + addValueDeclaration +use InterfaceOptionalArgEscapeUse.res:1:4 path:+InterfaceOptionalArgEscapeUse + DeadOptionalArgs.addReferences InterfaceOptionalArgEscape.escaped called with optional argNames: argNamesMaybe: InterfaceOptionalArgEscapeUse.res:1:16 + addValueReference InterfaceOptionalArgEscapeUse.res:1:4 --> InterfaceOptionalArgEscape.resi:1:0 + addValueReference InterfaceOptionalArgEscapeUse.res:3:8 --> InterfaceOptionalArgEscapeUse.res:1:4 Scanning JSResource.cmt Source:JSResource.res Scanning JsxV4.cmt Source:JsxV4.res addValueDeclaration +make JsxV4.res:4:23 path:+JsxV4.C @@ -1455,6 +1524,71 @@ addTypeReference TestPromise.res:14:32 --> TestPromise.res:7:2 Scanning ToSuppress.cmt Source:ToSuppress.res addValueDeclaration +toSuppress ToSuppress.res:1:4 path:+ToSuppress + Scanning TopLevelOptionalArgValueUse.cmt Source:TopLevelOptionalArgValueUse.res + addValueDeclaration +formatDate TopLevelOptionalArgValueUse.res:4:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +formatDateEscapes TopLevelOptionalArgValueUse.res:5:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +formatDateReturn TopLevelOptionalArgValueUse.res:6:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +formatDateTuple TopLevelOptionalArgValueUse.res:7:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +formatDateForwarded TopLevelOptionalArgValueUse.res:8:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +formatDateTopLevelEscape TopLevelOptionalArgValueUse.res:9:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +formatDateAlias TopLevelOptionalArgValueUse.res:10:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +takesFn TopLevelOptionalArgValueUse.res:12:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +deadEscape TopLevelOptionalArgValueUse.res:16:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +liveCaller TopLevelOptionalArgValueUse.res:18:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +liveEscapeCaller TopLevelOptionalArgValueUse.res:20:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +liveReturnCaller TopLevelOptionalArgValueUse.res:25:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +liveTupleCaller TopLevelOptionalArgValueUse.res:29:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +liveForwardingCaller TopLevelOptionalArgValueUse.res:33:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +formatDateAlias2 TopLevelOptionalArgValueUse.res:37:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +liveAliasCaller TopLevelOptionalArgValueUse.res:38:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +mutuallyRecursiveCaller TopLevelOptionalArgValueUse.res:40:8 path:+TopLevelOptionalArgValueUse + addValueDeclaration +mutuallyRecursiveTarget TopLevelOptionalArgValueUse.res:41:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +returnsFunction TopLevelOptionalArgValueUse.res:43:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +returnedFunction TopLevelOptionalArgValueUse.res:44:4 path:+TopLevelOptionalArgValueUse + addValueDeclaration +liveReturnedFunctionCaller TopLevelOptionalArgValueUse.res:45:4 path:+TopLevelOptionalArgValueUse + addValueReference TopLevelOptionalArgValueUse.res:4:4 --> TopLevelOptionalArgValueUse.res:4:26 + addValueReference TopLevelOptionalArgValueUse.res:5:4 --> TopLevelOptionalArgValueUse.res:5:33 + addValueReference TopLevelOptionalArgValueUse.res:6:4 --> TopLevelOptionalArgValueUse.res:6:32 + addValueReference TopLevelOptionalArgValueUse.res:7:4 --> TopLevelOptionalArgValueUse.res:7:31 + addValueReference TopLevelOptionalArgValueUse.res:8:4 --> TopLevelOptionalArgValueUse.res:8:35 + addValueReference TopLevelOptionalArgValueUse.res:9:4 --> TopLevelOptionalArgValueUse.res:9:40 + addValueReference TopLevelOptionalArgValueUse.res:10:4 --> TopLevelOptionalArgValueUse.res:10:31 + addValueReference TopLevelOptionalArgValueUse.res:14:8 --> TopLevelOptionalArgValueUse.res:9:4 + addValueReference TopLevelOptionalArgValueUse.res:14:0 --> TopLevelOptionalArgValueUse.res:12:4 + addValueReference TopLevelOptionalArgValueUse.res:16:4 --> TopLevelOptionalArgValueUse.res:4:4 + addValueReference TopLevelOptionalArgValueUse.res:16:4 --> TopLevelOptionalArgValueUse.res:12:4 + DeadOptionalArgs.addReferences formatDate called with optional argNames: argNamesMaybe: TopLevelOptionalArgValueUse.res:18:23 + addValueReference TopLevelOptionalArgValueUse.res:18:4 --> TopLevelOptionalArgValueUse.res:4:4 + DeadOptionalArgs.addReferences formatDateEscapes called with optional argNames: argNamesMaybe: TopLevelOptionalArgValueUse.res:22:2 + addValueReference TopLevelOptionalArgValueUse.res:20:4 --> TopLevelOptionalArgValueUse.res:5:4 + addValueReference TopLevelOptionalArgValueUse.res:20:4 --> TopLevelOptionalArgValueUse.res:5:4 + addValueReference TopLevelOptionalArgValueUse.res:20:4 --> TopLevelOptionalArgValueUse.res:12:4 + addValueReference TopLevelOptionalArgValueUse.res:25:4 --> TopLevelOptionalArgValueUse.res:6:4 + addValueReference TopLevelOptionalArgValueUse.res:29:4 --> TopLevelOptionalArgValueUse.res:7:4 + DeadOptionalArgs.addReferences formatDateForwarded called with optional argNames:fmt argNamesMaybe:fmt TopLevelOptionalArgValueUse.res:34:2 + addValueReference TopLevelOptionalArgValueUse.res:33:4 --> TopLevelOptionalArgValueUse.res:33:28 + addValueReference TopLevelOptionalArgValueUse.res:33:4 --> TopLevelOptionalArgValueUse.res:8:4 + addValueReference TopLevelOptionalArgValueUse.res:37:4 --> TopLevelOptionalArgValueUse.res:10:4 + DeadOptionalArgs.addReferences formatDateAlias2 called with optional argNames: argNamesMaybe: TopLevelOptionalArgValueUse.res:38:28 + addValueReference TopLevelOptionalArgValueUse.res:38:4 --> TopLevelOptionalArgValueUse.res:37:4 + DeadOptionalArgs.addReferences mutuallyRecursiveTarget called with optional argNames:fmt argNamesMaybe: TopLevelOptionalArgValueUse.res:40:40 + addValueReference TopLevelOptionalArgValueUse.res:40:8 --> TopLevelOptionalArgValueUse.res:41:4 + addValueReference TopLevelOptionalArgValueUse.res:41:4 --> TopLevelOptionalArgValueUse.res:41:39 + addValueReference TopLevelOptionalArgValueUse.res:43:4 --> TopLevelOptionalArgValueUse.res:43:22 + DeadOptionalArgs.addReferences returnsFunction called with optional argNames: argNamesMaybe: TopLevelOptionalArgValueUse.res:44:23 + addValueReference TopLevelOptionalArgValueUse.res:44:4 --> TopLevelOptionalArgValueUse.res:43:4 + DeadOptionalArgs.addReferences returnedFunction called with optional argNames: argNamesMaybe: TopLevelOptionalArgValueUse.res:45:39 + addValueReference TopLevelOptionalArgValueUse.res:45:4 --> TopLevelOptionalArgValueUse.res:44:4 + addValueReference TopLevelOptionalArgValueUse.res:47:8 --> TopLevelOptionalArgValueUse.res:18:4 + addValueReference TopLevelOptionalArgValueUse.res:48:8 --> TopLevelOptionalArgValueUse.res:20:4 + DeadOptionalArgs.addReferences liveReturnCaller called with optional argNames: argNamesMaybe: TopLevelOptionalArgValueUse.res:49:8 + addValueReference TopLevelOptionalArgValueUse.res:49:8 --> TopLevelOptionalArgValueUse.res:25:4 + addValueReference TopLevelOptionalArgValueUse.res:50:8 --> TopLevelOptionalArgValueUse.res:29:4 + DeadOptionalArgs.addReferences liveForwardingCaller called with optional argNames: argNamesMaybe: TopLevelOptionalArgValueUse.res:51:8 + addValueReference TopLevelOptionalArgValueUse.res:51:8 --> TopLevelOptionalArgValueUse.res:33:4 + addValueReference TopLevelOptionalArgValueUse.res:52:8 --> TopLevelOptionalArgValueUse.res:38:4 + addValueReference TopLevelOptionalArgValueUse.res:53:8 --> TopLevelOptionalArgValueUse.res:40:8 + addValueReference TopLevelOptionalArgValueUse.res:54:8 --> TopLevelOptionalArgValueUse.res:45:4 Scanning TransitiveType1.cmt Source:TransitiveType1.res addValueDeclaration +convert TransitiveType1.res:2:4 path:+TransitiveType1 addValueDeclaration +convertAlias TransitiveType1.res:5:4 path:+TransitiveType1 @@ -1958,9 +2092,9 @@ Forward Liveness Analysis - decls: 702 - roots(external targets): 137 - decl-deps: decls_with_out=411 edges_to_decls=289 + decls: 740 + roots(external targets): 160 + decl-deps: decls_with_out=446 edges_to_decls=319 Root (external ref): Value +FirstClassModules.M.InnerModule2.+k Root (external ref): VariantCase DeadRT.moduleAccessPath.Root @@ -1975,6 +2109,7 @@ Forward Liveness Analysis Root (annotated): Value +NestedModules.Universe.Nested2.+nested2Function Root (annotated): Value +Tuples.+marry Root (annotated): Value +Docstrings.+unitArgWithoutConversionU + Root (external ref): Value +InterfaceOptionalArgEscape.+escaped Root (annotated): Value +Types.+i64Const Root (external ref): VariantCase +DeadTypeTest.deadType.OnlyInImplementation Root (annotated): Value +TestImport.+valueStartingWithUpperCaseLetter @@ -1985,6 +2120,7 @@ Forward Liveness Analysis Root (annotated): Value +TypeParams3.+test Root (annotated): Value +Variants.+sunday Root (annotated): Value +NestedModules.Universe.Nested2.Nested3.+nested3Value + Root (external ref): Value +TopLevelOptionalArgValueUse.+liveReturnCaller Root (external ref): RecordLabel +Unison.t.doc Root (annotated): Value +Tuples.+computeAreaWithIdent Root (annotated): Value +LetPrivate.+y @@ -1997,7 +2133,9 @@ Forward Liveness Analysis Root (external ref): Value +Newton.+f Root (external ref): RecordLabel +Records.record.v Root (external ref): VariantCase +DeadTest.VariantUsedOnlyInImplementation.t.A + Root (external ref): Value +ContextOptionalArgs.ComponentUsingAction.+make Root (external ref): RecordLabel +Records.person.address + Root (external ref): RecordLabel +ContextOptionalArgs.NotificationProvider.props.children Root (annotated): Value +Variants.+testConvert2 Root (annotated): Value +Tuples.+coord2d Root (external ref): Value +CreateErrorHandler1.Error1.+notification @@ -2030,10 +2168,12 @@ Forward Liveness Analysis Root (external ref): Value +OptArg.+foo Root (annotated): Value +Variants.+fortytwoOK Root (external ref): Value OptArg.+bar + Root (external ref): Value +TopLevelOptionalArgValueUse.+liveAliasCaller Root (annotated): Value +Records.+payloadValue Root (external ref): RecordLabel +DeadTest.props.s Root (annotated): Value +Hooks.+default Root (external ref): VariantCase +Unison.break_.Never + Root (external ref): Value +ContextOptionalArgs.NotificationProvider.+make Root (annotated): Value +TestEmitInnerModules.Inner.+y Root (external ref): VariantCase InnerModuleTypes.I.t.Foo Root (annotated): Value +Types.+selfRecursiveConverter @@ -2047,6 +2187,7 @@ Forward Liveness Analysis Root (annotated): Value +Variants.+restResult3 Root (external ref): RecordLabel +Tuples.person.name Root (external ref): Value +FirstClassModules.M.InnerModule3.+k3 + Root (external ref): Value +ContextOptionalArgs.ComponentNotUsingAction.+dispatchNotification Root (external ref): RecordLabel +Records.coord.x Root (annotated): RecordLabel +DeadTypeTest.record.y Root (annotated): Value +TestImport.+defaultValue @@ -2062,6 +2203,7 @@ Forward Liveness Analysis Root (annotated): Value +TestImport.+innerStuffContents Root (external ref): Value +ModuleExceptionBug.+ddjdj Root (annotated): Value +TransitiveType1.+convert + Root (external ref): Value +CrossFileOptionalArgValueUse.+liveReturnCaller Root (annotated): Value +ImportHooks.+make Root (external ref): VariantCase +Unison.break_.IfNeed Root (external ref): Value +DeadTest.+make @@ -2082,6 +2224,7 @@ Forward Liveness Analysis Root (annotated): Value +Hooks.Inner.Inner2.+make Root (annotated): Value +ImportJsValue.+area Root (annotated): Value +Records.+testMyRec + Root (external ref): Value +TopLevelOptionalArgValueUse.+mutuallyRecursiveCaller Root (annotated): Value +DeadTest.GloobLive.+globallyLive3 Root (external ref): RecordLabel +Uncurried.auth.login Root (annotated): Value +ImportJsValue.+roundedNumber @@ -2106,7 +2249,9 @@ Forward Liveness Analysis Root (external ref): Value +OptArg.+twoArgs Root (annotated): Value +OcamlWarningSuppressToplevel.+suppressed1 Root (external ref): RecordLabel +Records.business2.address2 + Root (external ref): Value +TopLevelOptionalArgValueUse.+liveCaller Root (annotated): Value +Tuples.+testTuple + Root (external ref): Value +ContextOptionalArgs.NotificationProvider.+dispatchNotification Root (annotated): Value +Records.+testMyObj2 Root (annotated): Value +Uncurried.+callback2 Root (external ref): Value +DeadTest.VariantUsedOnlyInImplementation.+a @@ -2117,14 +2262,17 @@ Forward Liveness Analysis Root (annotated): Value +TestEmitInnerModules.Inner.+x Root (external ref): Value +OptArg.+wrapOneArg Root (external ref): RecordLabel +ComponentAsProp.props.title + Root (external ref): Value +ContextOptionalArgs.ComponentUsingAction.+dispatchNotification Root (annotated): Value +Records.+findAddress Root (annotated): Value +Uncurried.+callback Root (annotated): Value +VariantsWithPayload.+printVariantWithPayload Root (annotated): Value +TestImmutableArray.+testImmutableArrayGet + Root (external ref): Value +TopLevelOptionalArgValueUse.+formatDateTopLevelEscape Root (external ref): Value +TypeReexport.UseOriginal.+value Root (annotated): Value +Docstrings.+unnamed2 Root (annotated): Value +LetPrivate.local_1.+x Root (annotated): Value +TestImport.+make + Root (external ref): Value +ContextOptionalArgs.NotificationProvider.Provider.+make Root (annotated): Value +DeadTest.GloobLive.+globallyLive1 Root (annotated): Value +Docstrings.+grouped Root (annotated): Value +OcamlWarningSuppressToplevel.M.+suppressed4 @@ -2166,13 +2314,18 @@ Forward Liveness Analysis Root (annotated): RecordLabel +DeadTypeTest.record.x Root (external ref): RecordLabel +Records.myRec.type_ Root (annotated): Value +TestOptArg.+liveSuppressesOptArgs + Root (external ref): Value +ContextOptionalArgs.ComponentNotUsingAction.+make Root (annotated): Value NestedModulesInSignature.Universe.+theAnswer Root (annotated): Value +Docstrings.+unitArgWithoutConversion + Root (annotated): Value +ContextOptionalArgs.+make Root (annotated): Value +References.+create Root (annotated): Value +Types.+currentTime + Root (external ref): Value +InterfaceOptionalArgEscapeUse.+use Root (annotated): Value +Records.+someBusiness2 + Root (external ref): Value +TopLevelOptionalArgValueUse.+liveEscapeCaller Root (external ref): Value +DeadTest.+ira Root (annotated): Value +FirstClassModules.+testConvert + Root (external ref): Value +TopLevelOptionalArgValueUse.+liveTupleCaller Root (external ref): RecordLabel +Records.coord.z Root (annotated): Value +Types.+someIntList Root (annotated): Value +Types.+jsString2T @@ -2218,6 +2371,7 @@ Forward Liveness Analysis Root (annotated): Value +Variants.+restResult2 Root (annotated): Value +Docstrings.+useParam Root (annotated): Value +Records.+getPayload + Root (external ref): Value +TopLevelOptionalArgValueUse.+liveReturnedFunctionCaller Root (annotated): Value +ScopedAnnotationsOverride.M.NestedInLive.+nestedLive Root (external ref): Value +FirstClassModules.M.+y Root (external ref): RecordLabel +Uncurried.authU.loginU @@ -2235,6 +2389,7 @@ Forward Liveness Analysis Root (external ref): VariantCase +Unison.stack.Cons Root (external ref): Exception +DeadExn.Inside.Einside Root (annotated): Value +TestImport.+defaultValue2 + Root (external ref): Value +TopLevelOptionalArgValueUse.+liveForwardingCaller Root (external ref): Exception +DeadExn.Etoplevel Root (annotated): Value +Variants.+monday Root (annotated): Value +VariantsWithPayload.+printVariantWithPayloads @@ -2253,6 +2408,7 @@ Forward Liveness Analysis Root (external ref): Value +FirstClassModules.M.+x Root (external ref): Value +TypeReexportCrossFileB.+recordValue Root (annotated): Value +Records.+computeArea4 + Root (external ref): Value +InterfaceOptionalArgEscape.+takesFn Root (annotated): Value +TestModuleAliases.+testInner1Expanded Root (external ref): Value +TypeReexport.OnlyReexportedDead.+value Root (annotated): Value +ImportIndex.+make @@ -2271,6 +2427,7 @@ Forward Liveness Analysis Root (annotated): Value +DeadTest.GloobLive.+globallyLive2 Root (external ref): RecordLabel +TypeReexport.OnlyReexportedDead.reexportedType.usedField Root (annotated): Value +Docstrings.+unitArgWithConversion + Root (external ref): Value +TopLevelOptionalArgValueUse.+takesFn Root (external ref): RecordLabel +Records.business.owner Root (external ref): VariantCase +DeadTest.WithInclude.t.A Root (external ref): VariantCase +DeadTypeTest.deadType.InBoth @@ -2288,23 +2445,28 @@ Forward Liveness Analysis Root (annotated): Value +UseImportJsValue.+useGetProp Root (annotated): Value +Hooks.+functionWithRenamedArgs - 325 roots found + 348 roots found Propagate: DeadRT.moduleAccessPath.Root -> +DeadRT.moduleAccessPath.Root Propagate: +TypeReexportCrossFileB.reexportedRecord.usedField -> +TypeReexportCrossFileA.originalRecord.usedField Propagate: +DeadTypeTest.deadType.OnlyInImplementation -> DeadTypeTest.deadType.OnlyInImplementation Propagate: +OptionalArgsLiveDead.+liveCaller -> +OptionalArgsLiveDead.+formatDate + Propagate: +TopLevelOptionalArgValueUse.+liveReturnCaller -> +TopLevelOptionalArgValueUse.+formatDateReturn Propagate: +Newton.+f -> +Newton.+- Propagate: +Newton.+f -> +Newton.++ Propagate: +Newton.+f -> +Newton.+* Propagate: +DeadTest.VariantUsedOnlyInImplementation.t.A -> +DeadTest.VariantUsedOnlyInImplementation.t.A + Propagate: +ContextOptionalArgs.ComponentUsingAction.+make -> +ContextOptionalArgs.NotificationProvider.+useNotification Propagate: +DeadTest.+thisIsMarkedLive -> +DeadTest.+thisIsKeptAlive Propagate: +TypeReexport.UseOriginal.reexportedType.directlyUsed -> +TypeReexport.UseOriginal.originalType.directlyUsed + Propagate: +TopLevelOptionalArgValueUse.+liveAliasCaller -> +TopLevelOptionalArgValueUse.+formatDateAlias2 Propagate: +Hooks.+default -> +Hooks.+make Propagate: InnerModuleTypes.I.t.Foo -> +InnerModuleTypes.I.t.Foo Propagate: DeadTypeTest.deadType.OnlyInInterface -> +DeadTypeTest.deadType.OnlyInInterface Propagate: +TypeReexport.UseReexported.reexportedType.usedField -> +TypeReexport.UseReexported.originalType.usedField + Propagate: +CrossFileOptionalArgValueUse.+liveReturnCaller -> +CrossFileOptionalArgProvider.+formatDate Propagate: +References.+get -> +References.R.+get + Propagate: +TopLevelOptionalArgValueUse.+mutuallyRecursiveCaller -> +TopLevelOptionalArgValueUse.+mutuallyRecursiveTarget Propagate: ErrorHandler.Make.+notify -> +ErrorHandler.Make.+notify Propagate: +References.+make -> +References.R.+make Propagate: +ScopedAnnotationsLiveVsDead.LiveScope.+root -> +ScopedAnnotationsLiveVsDead.+middleLive @@ -2312,23 +2474,31 @@ Forward Liveness Analysis Propagate: +Newton.+result -> +Newton.+fPrimed Propagate: +Records.+findAllAddresses -> +Records.+getOpt Propagate: +TestOptArg.+bar -> +TestOptArg.+foo + Propagate: +TopLevelOptionalArgValueUse.+liveCaller -> +TopLevelOptionalArgValueUse.+formatDate Propagate: +DeadTest.VariantUsedOnlyInImplementation.+a -> +DeadTest.VariantUsedOnlyInImplementation.+a Propagate: +OptArg.+wrapOneArg -> +OptArg.+oneArg Propagate: +TestImmutableArray.+testImmutableArrayGet -> ImmutableArray.Array.+get + Propagate: +ContextOptionalArgs.NotificationProvider.Provider.+make -> +ContextOptionalArgs.NotificationProvider.+dispatchNotificationContext Propagate: +TypeReexport.VariantUseReexported.reexportedType.A -> +TypeReexport.VariantUseReexported.originalType.A Propagate: +Unison.+toString -> +Unison.+fits Propagate: +References.+set -> +References.R.+set Propagate: +DeadTest.MM.+x -> +DeadTest.MM.+x Propagate: NestedModulesInSignature.Universe.+theAnswer -> +NestedModulesInSignature.Universe.+theAnswer + Propagate: +InterfaceOptionalArgEscapeUse.+use -> InterfaceOptionalArgEscape.+escaped + Propagate: +TopLevelOptionalArgValueUse.+liveEscapeCaller -> +TopLevelOptionalArgValueUse.+formatDateEscapes + Propagate: +TopLevelOptionalArgValueUse.+liveTupleCaller -> +TopLevelOptionalArgValueUse.+formatDateTuple Propagate: +DeadTypeTest.t.A -> DeadTypeTest.t.A Propagate: ImmutableArray.+fromArray -> +ImmutableArray.+fromArray Propagate: +OptArg.+wrapfourArgs -> +OptArg.+fourArgs Propagate: +DeadRT.moduleAccessPath.Kaboom -> DeadRT.moduleAccessPath.Kaboom + Propagate: +TopLevelOptionalArgValueUse.+liveReturnedFunctionCaller -> +TopLevelOptionalArgValueUse.+returnedFunction Propagate: DeadValueTest.+valueAlive -> +DeadValueTest.+valueAlive + Propagate: +TopLevelOptionalArgValueUse.+liveForwardingCaller -> +TopLevelOptionalArgValueUse.+formatDateForwarded Propagate: +ImportJsValue.+useGetAbs -> +ImportJsValue.AbsoluteValue.+getAbs Propagate: +TypeReexport.VariantUseOriginal.reexportedType.A -> +TypeReexport.VariantUseOriginal.originalType.A Propagate: +TypeReexport.OnlyReexportedDead.reexportedType.usedField -> +TypeReexport.OnlyReexportedDead.originalType.usedField Propagate: +DeadTest.WithInclude.t.A -> +DeadTest.WithInclude.t.A + Propagate: +TopLevelOptionalArgValueUse.+formatDateAlias2 -> +TopLevelOptionalArgValueUse.+formatDateAlias Propagate: +References.R.+get -> +References.R.+get Propagate: +References.R.+make -> +References.R.+make Propagate: +ScopedAnnotationsLiveVsDead.+middleLive -> +ScopedAnnotationsLiveVsDead.+leafLive @@ -2342,9 +2512,10 @@ Forward Liveness Analysis Propagate: ImmutableArray.Array.+get -> +ImmutableArray.+get Propagate: +References.R.+set -> +References.R.+set Propagate: +DeadTest.MM.+x -> +DeadTest.MM.+y + Propagate: +TopLevelOptionalArgValueUse.+returnedFunction -> +TopLevelOptionalArgValueUse.+returnsFunction Propagate: +ImportJsValue.AbsoluteValue.+getAbs -> +ImportJsValue.AbsoluteValue.+getAbs - 53 declarations marked live via propagation + 67 declarations marked live via propagation Dead VariantCase +AutoAnnotate.variant.R Dead RecordLabel +AutoAnnotate.record.variant @@ -2373,8 +2544,64 @@ Forward Liveness Analysis Live (external ref) RecordLabel +ComponentAsProp.props.button deps: in=1 (live=1 dead=0) out=0 <- +ComponentAsProp.+make (live) + Live (propagated) Value +ContextOptionalArgs.NotificationProvider.+dispatchNotificationContext + deps: in=2 (live=2 dead=0) out=0 + <- +ContextOptionalArgs.NotificationProvider.Provider.+make (live) + <- +ContextOptionalArgs.NotificationProvider.+useNotification (live) + Live (external ref) Value +ContextOptionalArgs.NotificationProvider.Provider.+make + deps: in=1 (live=1 dead=0) out=1 + <- +ContextOptionalArgs.NotificationProvider.+make (live) + -> +ContextOptionalArgs.NotificationProvider.+dispatchNotificationContext + Live (external ref) Value +ContextOptionalArgs.NotificationProvider.+make + deps: in=1 (live=1 dead=0) out=3 + <- +ContextOptionalArgs.+make (live) + -> +ContextOptionalArgs.NotificationProvider.Provider.+make + -> +ContextOptionalArgs.NotificationProvider.props.children + -> +ContextOptionalArgs.NotificationProvider.+dispatchNotification + Live (external ref) RecordLabel +ContextOptionalArgs.NotificationProvider.props.children + deps: in=1 (live=1 dead=0) out=0 + <- +ContextOptionalArgs.NotificationProvider.+make (live) + Live (external ref) Value +ContextOptionalArgs.NotificationProvider.+dispatchNotification + deps: in=1 (live=1 dead=0) out=0 + <- +ContextOptionalArgs.NotificationProvider.+make (live) + Live (propagated) Value +ContextOptionalArgs.NotificationProvider.+useNotification + deps: in=4 (live=4 dead=0) out=1 + <- +ContextOptionalArgs.ComponentUsingAction.+make (live) + <- +ContextOptionalArgs.ComponentUsingAction.+dispatchNotification (live) + <- +ContextOptionalArgs.ComponentNotUsingAction.+make (live) + <- ... (1 more) + -> +ContextOptionalArgs.NotificationProvider.+dispatchNotificationContext + Live (external ref) Value +ContextOptionalArgs.ComponentUsingAction.+make + deps: in=1 (live=1 dead=0) out=2 + <- +ContextOptionalArgs.+make (live) + -> +ContextOptionalArgs.NotificationProvider.+useNotification + -> +ContextOptionalArgs.ComponentUsingAction.+dispatchNotification + Live (external ref) Value +ContextOptionalArgs.ComponentUsingAction.+dispatchNotification + deps: in=1 (live=1 dead=0) out=1 + <- +ContextOptionalArgs.ComponentUsingAction.+make (live) + -> +ContextOptionalArgs.NotificationProvider.+useNotification + Live (external ref) Value +ContextOptionalArgs.ComponentNotUsingAction.+make + deps: in=1 (live=1 dead=0) out=2 + <- +ContextOptionalArgs.+make (live) + -> +ContextOptionalArgs.NotificationProvider.+useNotification + -> +ContextOptionalArgs.ComponentNotUsingAction.+dispatchNotification + Live (external ref) Value +ContextOptionalArgs.ComponentNotUsingAction.+dispatchNotification + deps: in=1 (live=1 dead=0) out=1 + <- +ContextOptionalArgs.ComponentNotUsingAction.+make (live) + -> +ContextOptionalArgs.NotificationProvider.+useNotification + Live (annotated) Value +ContextOptionalArgs.+make + deps: in=0 (live=0 dead=0) out=3 + -> +ContextOptionalArgs.NotificationProvider.+make + -> +ContextOptionalArgs.ComponentUsingAction.+make + -> +ContextOptionalArgs.ComponentNotUsingAction.+make Live (external ref) Value +CreateErrorHandler1.Error1.+notification Live (external ref) Value +CreateErrorHandler2.Error2.+notification + Live (propagated) Value +CrossFileOptionalArgProvider.+formatDate + deps: in=1 (live=1 dead=0) out=0 + <- +CrossFileOptionalArgValueUse.+liveReturnCaller (live) + Live (external ref) Value +CrossFileOptionalArgValueUse.+liveReturnCaller + deps: in=0 (live=0 dead=0) out=1 + -> +CrossFileOptionalArgProvider.+formatDate Live (external ref) Value +DeadCodeImplementation.M.+x Live (external ref) Exception +DeadExn.Etoplevel deps: in=1 (live=0 dead=1) out=0 @@ -3251,6 +3478,17 @@ Forward Liveness Analysis <- +InnerModuleTypes.I.t.Foo (live) <- +TestInnedModuleTypes.+_ (dead) -> +InnerModuleTypes.I.t.Foo + Live (external ref) Value +InterfaceOptionalArgEscape.+escaped + deps: in=1 (live=1 dead=0) out=0 + <- InterfaceOptionalArgEscape.+escaped (live) + Live (external ref) Value +InterfaceOptionalArgEscape.+takesFn + Live (propagated) Value InterfaceOptionalArgEscape.+escaped + deps: in=1 (live=1 dead=0) out=1 + <- +InterfaceOptionalArgEscapeUse.+use (live) + -> +InterfaceOptionalArgEscape.+escaped + Live (external ref) Value +InterfaceOptionalArgEscapeUse.+use + deps: in=0 (live=0 dead=0) out=1 + -> InterfaceOptionalArgEscape.+escaped Live (external ref) Value +JsxV4.C.+make Live (annotated) Value +LetPrivate.local_1.+x deps: in=1 (live=1 dead=0) out=0 @@ -3669,6 +3907,73 @@ Forward Liveness Analysis deps: in=0 (live=0 dead=0) out=1 -> +TestPromise.fromPayload.s Dead Value +ToSuppress.+toSuppress + Live (propagated) Value +TopLevelOptionalArgValueUse.+formatDate + deps: in=2 (live=1 dead=1) out=0 + <- +TopLevelOptionalArgValueUse.+deadEscape (dead) + <- +TopLevelOptionalArgValueUse.+liveCaller (live) + Live (propagated) Value +TopLevelOptionalArgValueUse.+formatDateEscapes + deps: in=1 (live=1 dead=0) out=0 + <- +TopLevelOptionalArgValueUse.+liveEscapeCaller (live) + Live (propagated) Value +TopLevelOptionalArgValueUse.+formatDateReturn + deps: in=1 (live=1 dead=0) out=0 + <- +TopLevelOptionalArgValueUse.+liveReturnCaller (live) + Live (propagated) Value +TopLevelOptionalArgValueUse.+formatDateTuple + deps: in=1 (live=1 dead=0) out=0 + <- +TopLevelOptionalArgValueUse.+liveTupleCaller (live) + Live (propagated) Value +TopLevelOptionalArgValueUse.+formatDateForwarded + deps: in=1 (live=1 dead=0) out=0 + <- +TopLevelOptionalArgValueUse.+liveForwardingCaller (live) + Live (external ref) Value +TopLevelOptionalArgValueUse.+formatDateTopLevelEscape + Live (propagated) Value +TopLevelOptionalArgValueUse.+formatDateAlias + deps: in=1 (live=1 dead=0) out=0 + <- +TopLevelOptionalArgValueUse.+formatDateAlias2 (live) + Live (external ref) Value +TopLevelOptionalArgValueUse.+takesFn + deps: in=2 (live=1 dead=1) out=0 + <- +TopLevelOptionalArgValueUse.+deadEscape (dead) + <- +TopLevelOptionalArgValueUse.+liveEscapeCaller (live) + Dead Value +TopLevelOptionalArgValueUse.+deadEscape + deps: in=0 (live=0 dead=0) out=2 + -> +TopLevelOptionalArgValueUse.+formatDate + -> +TopLevelOptionalArgValueUse.+takesFn + Live (external ref) Value +TopLevelOptionalArgValueUse.+liveCaller + deps: in=0 (live=0 dead=0) out=1 + -> +TopLevelOptionalArgValueUse.+formatDate + Live (external ref) Value +TopLevelOptionalArgValueUse.+liveEscapeCaller + deps: in=0 (live=0 dead=0) out=2 + -> +TopLevelOptionalArgValueUse.+formatDateEscapes + -> +TopLevelOptionalArgValueUse.+takesFn + Live (external ref) Value +TopLevelOptionalArgValueUse.+liveReturnCaller + deps: in=0 (live=0 dead=0) out=1 + -> +TopLevelOptionalArgValueUse.+formatDateReturn + Live (external ref) Value +TopLevelOptionalArgValueUse.+liveTupleCaller + deps: in=0 (live=0 dead=0) out=1 + -> +TopLevelOptionalArgValueUse.+formatDateTuple + Live (external ref) Value +TopLevelOptionalArgValueUse.+liveForwardingCaller + deps: in=0 (live=0 dead=0) out=1 + -> +TopLevelOptionalArgValueUse.+formatDateForwarded + Live (propagated) Value +TopLevelOptionalArgValueUse.+formatDateAlias2 + deps: in=1 (live=1 dead=0) out=1 + <- +TopLevelOptionalArgValueUse.+liveAliasCaller (live) + -> +TopLevelOptionalArgValueUse.+formatDateAlias + Live (external ref) Value +TopLevelOptionalArgValueUse.+liveAliasCaller + deps: in=0 (live=0 dead=0) out=1 + -> +TopLevelOptionalArgValueUse.+formatDateAlias2 + Live (external ref) Value +TopLevelOptionalArgValueUse.+mutuallyRecursiveCaller + deps: in=0 (live=0 dead=0) out=1 + -> +TopLevelOptionalArgValueUse.+mutuallyRecursiveTarget + Live (propagated) Value +TopLevelOptionalArgValueUse.+mutuallyRecursiveTarget + deps: in=1 (live=1 dead=0) out=0 + <- +TopLevelOptionalArgValueUse.+mutuallyRecursiveCaller (live) + Live (propagated) Value +TopLevelOptionalArgValueUse.+returnsFunction + deps: in=1 (live=1 dead=0) out=0 + <- +TopLevelOptionalArgValueUse.+returnedFunction (live) + Live (propagated) Value +TopLevelOptionalArgValueUse.+returnedFunction + deps: in=1 (live=1 dead=0) out=1 + <- +TopLevelOptionalArgValueUse.+liveReturnedFunctionCaller (live) + -> +TopLevelOptionalArgValueUse.+returnsFunction + Live (external ref) Value +TopLevelOptionalArgValueUse.+liveReturnedFunctionCaller + deps: in=0 (live=0 dead=0) out=1 + -> +TopLevelOptionalArgValueUse.+returnedFunction Live (annotated) Value +TransitiveType1.+convert Live (annotated) Value +TransitiveType1.+convertAlias Dead Value +TransitiveType2.+convertT2 @@ -5029,6 +5334,10 @@ Forward Liveness Analysis TestPromise.res:11:19-32 toPayload.result is a record label never used to read a value + Warning Dead Value + TopLevelOptionalArgValueUse.res:16:1-42 + deadEscape is never used + Warning Dead Module TransitiveType2.res:0:1 TransitiveType2 is a dead module as all its items are dead. @@ -5269,8 +5578,20 @@ Forward Liveness Analysis Unison.res:17:1-55 optional argument break_ of function group is always supplied (2 calls) + Warning Redundant Optional Argument + TopLevelOptionalArgValueUse.res:41:1-46 + optional argument fmt of function mutuallyRecursiveTarget is always supplied (1 calls) + + Warning Unused Argument + TopLevelOptionalArgValueUse.res:4:1-33 + optional argument fmt of function formatDate is never used + Warning Redundant Optional Argument OptArg.res:26:1-70 optional argument c of function wrapfourArgs is always supplied (2 calls) + + Warning Unused Argument + TopLevelOptionalArgValueUse.res:33:1-85 + optional argument fmt of function liveForwardingCaller is never used - Analysis reported 319 issues (Incorrect Dead Annotation:1, Warning Dead Exception:2, Warning Dead Module:22, Warning Dead Type:94, Warning Dead Value:177, Warning Dead Value With Side Effects:5, Warning Redundant Optional Argument:6, Warning Unused Argument:12) + Analysis reported 323 issues (Incorrect Dead Annotation:1, Warning Dead Exception:2, Warning Dead Module:22, Warning Dead Type:94, Warning Dead Value:178, Warning Dead Value With Side Effects:5, Warning Redundant Optional Argument:7, Warning Unused Argument:14) diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/src/ContextOptionalArgs.res b/tests/analysis_tests/tests-reanalyze/deadcode/src/ContextOptionalArgs.res new file mode 100644 index 0000000000..f9c4075e9d --- /dev/null +++ b/tests/analysis_tests/tests-reanalyze/deadcode/src/ContextOptionalArgs.res @@ -0,0 +1,60 @@ +module NotificationProvider = { + let dispatchNotificationContext = React.createContext(( + ~action as _: option=?, + _message: string, + ) => ()) + + module Provider = { + let make = React.Context.provider(dispatchNotificationContext) + } + + @react.component + let make = (~children) => { + let dispatchNotification = (~action=?, message) => + switch action { + | Some(action) => Console.log2(message, action) + | None => Console.log(message) + } + + {children} + } + + let useNotification = () => React.useContext(dispatchNotificationContext) +} + +module ComponentUsingAction = { + @react.component + let make = () => { + let dispatchNotification = NotificationProvider.useNotification() + + React.useEffect(() => { + dispatchNotification(~action="Some action", "This is a notification message") + None + }, []) + + React.null + } +} + +module ComponentNotUsingAction = { + @react.component + let make = () => { + let dispatchNotification = NotificationProvider.useNotification() + + React.useEffect(() => { + dispatchNotification("This is a notification message") + None + }, []) + + React.null + } +} + +@live +@react.component +let make = () => { + + + + +} diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/src/CrossFileOptionalArgProvider.res b/tests/analysis_tests/tests-reanalyze/deadcode/src/CrossFileOptionalArgProvider.res new file mode 100644 index 0000000000..7119d158f0 --- /dev/null +++ b/tests/analysis_tests/tests-reanalyze/deadcode/src/CrossFileOptionalArgProvider.res @@ -0,0 +1 @@ +let formatDate = (~fmt=?, s) => s diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/src/CrossFileOptionalArgValueUse.res b/tests/analysis_tests/tests-reanalyze/deadcode/src/CrossFileOptionalArgValueUse.res new file mode 100644 index 0000000000..ad4d73f0d9 --- /dev/null +++ b/tests/analysis_tests/tests-reanalyze/deadcode/src/CrossFileOptionalArgValueUse.res @@ -0,0 +1,5 @@ +let liveReturnCaller = () => { + CrossFileOptionalArgProvider.formatDate +} + +let _ = liveReturnCaller() diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/src/InterfaceOptionalArgEscape.res b/tests/analysis_tests/tests-reanalyze/deadcode/src/InterfaceOptionalArgEscape.res new file mode 100644 index 0000000000..1505469975 --- /dev/null +++ b/tests/analysis_tests/tests-reanalyze/deadcode/src/InterfaceOptionalArgEscape.res @@ -0,0 +1,5 @@ +let escaped = (~fmt=?, value) => value + +let takesFn = _ => () + +takesFn(escaped) diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/src/InterfaceOptionalArgEscape.resi b/tests/analysis_tests/tests-reanalyze/deadcode/src/InterfaceOptionalArgEscape.resi new file mode 100644 index 0000000000..de0b5900d0 --- /dev/null +++ b/tests/analysis_tests/tests-reanalyze/deadcode/src/InterfaceOptionalArgEscape.resi @@ -0,0 +1 @@ +let escaped: (~fmt: string=?, string) => string diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/src/InterfaceOptionalArgEscapeUse.res b/tests/analysis_tests/tests-reanalyze/deadcode/src/InterfaceOptionalArgEscapeUse.res new file mode 100644 index 0000000000..8c69690a4d --- /dev/null +++ b/tests/analysis_tests/tests-reanalyze/deadcode/src/InterfaceOptionalArgEscapeUse.res @@ -0,0 +1,3 @@ +let use = () => InterfaceOptionalArgEscape.escaped("value") + +let _ = use() diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/src/TopLevelOptionalArgValueUse.res b/tests/analysis_tests/tests-reanalyze/deadcode/src/TopLevelOptionalArgValueUse.res new file mode 100644 index 0000000000..32aba79370 --- /dev/null +++ b/tests/analysis_tests/tests-reanalyze/deadcode/src/TopLevelOptionalArgValueUse.res @@ -0,0 +1,54 @@ +/* Dead first-class escapes should not suppress optional-arg warnings, but live + first-class escapes should suppress them even when there is also a direct call. */ + +let formatDate = (~fmt=?, s) => s +let formatDateEscapes = (~fmt=?, s) => s +let formatDateReturn = (~fmt=?, s) => s +let formatDateTuple = (~fmt=?, s) => s +let formatDateForwarded = (~fmt=?, s) => s +let formatDateTopLevelEscape = (~fmt=?, s) => s +let formatDateAlias = (~fmt=?, s) => s + +let takesFn = _ => () + +takesFn(formatDateTopLevelEscape) + +let deadEscape = () => takesFn(formatDate) + +let liveCaller = () => formatDate("2024-01-01") + +let liveEscapeCaller = () => { + takesFn(formatDateEscapes) + formatDateEscapes("2024-01-01") +} + +let liveReturnCaller = () => { + formatDateReturn +} + +let liveTupleCaller = () => { + (formatDateTuple, "tuple") +} + +let liveForwardingCaller = (~fmt=?) => { + formatDateForwarded(~fmt?, "2024-01-01") +} + +let formatDateAlias2 = formatDateAlias +let liveAliasCaller = () => formatDateAlias2("2024-01-01") + +let rec mutuallyRecursiveCaller = () => mutuallyRecursiveTarget(~fmt="ISO", "2024-01-01") +and mutuallyRecursiveTarget = (~fmt=?, s) => s + +let returnsFunction = value => (~inner: option=?) => value +let returnedFunction = returnsFunction("value") +let liveReturnedFunctionCaller = () => returnedFunction() + +let _ = liveCaller() +let _ = liveEscapeCaller() +let _ = liveReturnCaller() +let _ = liveTupleCaller() +let _ = liveForwardingCaller() +let _ = liveAliasCaller() +let _ = mutuallyRecursiveCaller() +let _ = liveReturnedFunctionCaller()