22
33open DeadCommon
44
5- module BindingContext = struct
6- (* Local, encapsulated mutable state for tracking the current binding location
7- during traversal. This ref does not escape the module. *)
8- type t = Current .state ref
9-
10- let create () : t = ref Current. empty_state
11-
12- let get_binding (ctx : t ) : Location.t = ! ctx |> Current. get_last_binding
13-
14- let with_binding (ctx : t ) (loc : Location.t ) (f : unit -> 'a ) : 'a =
15- let old_state = ! ctx in
16- ctx := Current. with_last_binding loc old_state;
17- let result = f () in
18- ctx := old_state;
19- result
20- end
21-
225let checkAnyValueBindingWithNoSideEffects
236 ({vb_pat = {pat_desc} ; vb_expr = expr ; vb_loc = loc } :
247 Typedtree.value_binding ) =
@@ -123,10 +106,10 @@ let processOptionalArgs ~expType ~(locFrom : Location.t) ~locTo ~path args =
123106 (! supplied, ! suppliedMaybe)
124107 |> DeadOptionalArgs. addReferences ~loc From ~loc To ~path )
125108
126- let rec collectExpr ~(binding_ctx : BindingContext .t ) super self
109+ let rec collectExpr ~(last_binding : Location .t ) super self
127110 (e : Typedtree.expression ) =
128111 let locFrom = e.exp_loc in
129- let binding = BindingContext. get_binding binding_ctx in
112+ let binding = last_binding in
130113 (match e.exp_desc with
131114 | Texp_ident (_path , _ , {Types. val_loc = {loc_ghost = false ; _} as locTo } ) ->
132115 (* if Path.name _path = "rc" then assert false; *)
@@ -219,7 +202,7 @@ let rec collectExpr ~(binding_ctx : BindingContext.t) super self
219202 ->
220203 (* Punned field in OCaml projects has ghost location in expression *)
221204 let e = {e with exp_loc = {exp_loc with loc_ghost = false }} in
222- collectExpr ~binding_ctx super self e |> ignore
205+ collectExpr ~last_binding super self e |> ignore
223206 | _ -> () )
224207 | _ -> () );
225208 super.Tast_mapper. expr self e
@@ -301,93 +284,101 @@ let rec processSignatureItem ~doTypes ~doValues ~moduleLoc ~path
301284 ModulePath. setCurrent oldModulePath
302285
303286(* Traverse the AST *)
304- let traverseStructure ~doTypes ~doExternals =
305- let binding_ctx = BindingContext. create () in
306- let customize super =
307- let expr self e = e |> collectExpr ~binding_ctx super self in
308- let value_binding self vb =
309- let current_binding = BindingContext. get_binding binding_ctx in
310- let loc = vb |> collectValueBinding ~current_binding in
311- BindingContext. with_binding binding_ctx loc (fun () ->
312- super.Tast_mapper. value_binding self vb)
313- in
314- let pat self p = p |> collectPattern super self in
315- let structure_item self (structureItem : Typedtree.structure_item ) =
316- let oldModulePath = ModulePath. getCurrent () in
317- (match structureItem.str_desc with
318- | Tstr_module {mb_expr; mb_id; mb_loc} -> (
319- let hasInterface =
320- match mb_expr.mod_desc with
321- | Tmod_constraint _ -> true
322- | _ -> false
323- in
324- ModulePath. setCurrent
325- {
326- oldModulePath with
327- loc = mb_loc;
328- path = (mb_id |> Ident. name |> Name. create) :: oldModulePath.path;
329- };
330- if hasInterface then
331- match mb_expr.mod_type with
332- | Mty_signature signature ->
333- signature
334- |> List. iter
335- (processSignatureItem ~do Types ~do Values:false
336- ~module Loc:mb_expr.mod_loc
337- ~path:
338- ((ModulePath. getCurrent () ).path
339- @ [! Common. currentModuleName]))
340- | _ -> () )
341- | Tstr_primitive vd when doExternals && ! Config. analyzeExternals ->
342- let currentModulePath = ModulePath. getCurrent () in
343- let path = currentModulePath.path @ [! Common. currentModuleName] in
344- let exists =
345- match PosHash. find_opt decls vd.val_loc.loc_start with
346- | Some {declKind = Value _ } -> true
347- | _ -> false
348- in
349- let id = vd.val_id |> Ident. name in
350- Printf. printf " Primitive %s\n " id;
351- if
352- (not exists) && id <> " unsafe_expr"
353- (* see https://github.com/BuckleScript/bucklescript/issues/4532 *)
354- then
355- id
356- |> Name. create ~is Interface:false
357- |> addValueDeclaration ~path ~loc: vd.val_loc
358- ~module Loc:currentModulePath.loc ~side Effects:false
359- | Tstr_type (_recFlag , typeDeclarations ) when doTypes ->
360- if ! Config. analyzeTypes then
361- typeDeclarations
362- |> List. iter (fun (typeDeclaration : Typedtree.type_declaration ) ->
363- DeadType. addDeclaration ~type Id:typeDeclaration.typ_id
364- ~type Kind:typeDeclaration.typ_type.type_kind)
365- | Tstr_include {incl_mod; incl_type} -> (
366- match incl_mod.mod_desc with
367- | Tmod_ident (_path , _lid ) ->
368- let currentPath =
369- (ModulePath. getCurrent () ).path @ [! Common. currentModuleName]
370- in
371- incl_type
372- |> List. iter
373- (processSignatureItem ~do Types
374- ~do Values:false (* TODO: also values? *)
375- ~module Loc:incl_mod.mod_loc ~path: currentPath)
376- | _ -> () )
377- | Tstr_exception {ext_id = id ; ext_loc = loc } ->
378- let path =
379- (ModulePath. getCurrent () ).path @ [! Common. currentModuleName]
380- in
381- let name = id |> Ident. name |> Name. create in
382- name |> DeadException. add ~path ~loc ~str Loc:structureItem.str_loc
383- | _ -> () );
384- let result = super.structure_item self structureItem in
385- ModulePath. setCurrent oldModulePath;
386- result
287+ let traverseStructure ~doTypes ~doExternals (structure : Typedtree.structure ) :
288+ unit =
289+ let rec create_mapper (last_binding : Location.t ) =
290+ let super = Tast_mapper. default in
291+ let rec mapper =
292+ {
293+ super with
294+ expr = (fun _self e -> e |> collectExpr ~last_binding super mapper);
295+ pat = (fun _self p -> p |> collectPattern super mapper);
296+ structure_item =
297+ (fun _self (structureItem : Typedtree.structure_item ) ->
298+ let oldModulePath = ModulePath. getCurrent () in
299+ (match structureItem.str_desc with
300+ | Tstr_module {mb_expr; mb_id; mb_loc} -> (
301+ let hasInterface =
302+ match mb_expr.mod_desc with
303+ | Tmod_constraint _ -> true
304+ | _ -> false
305+ in
306+ ModulePath. setCurrent
307+ {
308+ oldModulePath with
309+ loc = mb_loc;
310+ path =
311+ (mb_id |> Ident. name |> Name. create) :: oldModulePath.path;
312+ };
313+ if hasInterface then
314+ match mb_expr.mod_type with
315+ | Mty_signature signature ->
316+ signature
317+ |> List. iter
318+ (processSignatureItem ~do Types ~do Values:false
319+ ~module Loc:mb_expr.mod_loc
320+ ~path:
321+ ((ModulePath. getCurrent () ).path
322+ @ [! Common. currentModuleName]))
323+ | _ -> () )
324+ | Tstr_primitive vd when doExternals && ! Config. analyzeExternals ->
325+ let currentModulePath = ModulePath. getCurrent () in
326+ let path = currentModulePath.path @ [! Common. currentModuleName] in
327+ let exists =
328+ match PosHash. find_opt decls vd.val_loc.loc_start with
329+ | Some {declKind = Value _ } -> true
330+ | _ -> false
331+ in
332+ let id = vd.val_id |> Ident. name in
333+ Printf. printf " Primitive %s\n " id;
334+ if
335+ (not exists) && id <> " unsafe_expr"
336+ (* see https://github.com/BuckleScript/bucklescript/issues/4532 *)
337+ then
338+ id
339+ |> Name. create ~is Interface:false
340+ |> addValueDeclaration ~path ~loc: vd.val_loc
341+ ~module Loc:currentModulePath.loc ~side Effects:false
342+ | Tstr_type (_recFlag , typeDeclarations ) when doTypes ->
343+ if ! Config. analyzeTypes then
344+ typeDeclarations
345+ |> List. iter
346+ (fun (typeDeclaration : Typedtree.type_declaration ) ->
347+ DeadType. addDeclaration ~type Id:typeDeclaration.typ_id
348+ ~type Kind:typeDeclaration.typ_type.type_kind)
349+ | Tstr_include {incl_mod; incl_type} -> (
350+ match incl_mod.mod_desc with
351+ | Tmod_ident (_path , _lid ) ->
352+ let currentPath =
353+ (ModulePath. getCurrent () ).path @ [! Common. currentModuleName]
354+ in
355+ incl_type
356+ |> List. iter
357+ (processSignatureItem ~do Types
358+ ~do Values:false (* TODO: also values? *)
359+ ~module Loc:incl_mod.mod_loc ~path: currentPath)
360+ | _ -> () )
361+ | Tstr_exception {ext_id = id ; ext_loc = loc } ->
362+ let path =
363+ (ModulePath. getCurrent () ).path @ [! Common. currentModuleName]
364+ in
365+ let name = id |> Ident. name |> Name. create in
366+ name |> DeadException. add ~path ~loc ~str Loc:structureItem.str_loc
367+ | _ -> () );
368+ let result = super.structure_item mapper structureItem in
369+ ModulePath. setCurrent oldModulePath;
370+ result);
371+ value_binding =
372+ (fun _self vb ->
373+ let loc = vb |> collectValueBinding ~current_binding: last_binding in
374+ let nested_mapper = create_mapper loc in
375+ super.Tast_mapper. value_binding nested_mapper vb);
376+ }
387377 in
388- {super with expr; pat; structure_item; value_binding}
378+ mapper
389379 in
390- customize Tast_mapper. default
380+ let mapper = create_mapper Location. none in
381+ mapper.structure mapper structure |> ignore
391382
392383(* Merge a location's references to another one's *)
393384let processValueDependency
@@ -411,7 +402,6 @@ let processValueDependency
411402
412403let processStructure ~cmt_value_dependencies ~doTypes ~doExternals
413404 (structure : Typedtree.structure ) =
414- let traverseStructure = traverseStructure ~do Types ~do Externals in
415- structure |> traverseStructure.structure traverseStructure |> ignore;
405+ traverseStructure ~do Types ~do Externals structure;
416406 let valueDependencies = cmt_value_dependencies |> List. rev in
417407 valueDependencies |> List. iter processValueDependency
0 commit comments