@@ -335,3 +335,216 @@ let create_focused_graph graph center_module =
335335let find_modules_with_no_dependents graph =
336336 let modules = get_modules graph in
337337 List. filter (fun m -> find_dependents graph m = [] ) modules
338+
339+ (* Count value usage in dependents of a module *)
340+ let count_value_usage_in_dependents graph ~module_name ~value_name =
341+ let open Stdlib in
342+ let open Cmt_format in
343+ let dependents = find_dependents graph module_name in
344+ let find_cmt_path file_path =
345+ let cmt_path =
346+ Parser.DependencyExtractor. get_cmt_path_for_source file_path
347+ in
348+ if Sys. file_exists cmt_path then Some cmt_path else None
349+ in
350+ let rec get_head_module_name path =
351+ match path with
352+ | Path. Pident id -> Ident. name id
353+ | Path. Pdot (p , _ , _ ) -> get_head_module_name p
354+ | _ -> Path. name path
355+ in
356+ let rec count_in_expression value_name module_name open_modules current_module
357+ expr =
358+ match expr.Typedtree. exp_desc with
359+ | Typedtree. Texp_ident (path , _ , _ ) -> (
360+ match path with
361+ | Path. Pident id ->
362+ if
363+ Ident. name id = value_name
364+ && (List. mem module_name open_modules
365+ || current_module = module_name)
366+ then 1
367+ else 0
368+ | Path. Pdot (p , id , _ ) ->
369+ if id = value_name && get_head_module_name p = module_name then 1
370+ else 0
371+ | _ -> 0 )
372+ | Typedtree. Texp_let (_ , vbs , e ) ->
373+ List. fold_left
374+ (fun acc vb ->
375+ acc
376+ + count_in_expression value_name module_name open_modules
377+ current_module vb.Typedtree. vb_expr)
378+ (count_in_expression value_name module_name open_modules
379+ current_module e)
380+ vbs
381+ | Typedtree. Texp_function { cases; _ } ->
382+ List. fold_left
383+ (fun acc c ->
384+ acc
385+ + count_in_expression value_name module_name open_modules
386+ current_module c.Typedtree. c_rhs)
387+ 0 cases
388+ | Typedtree. Texp_apply (e , args ) ->
389+ List. fold_left
390+ (fun acc (_ , eo ) ->
391+ acc
392+ +
393+ match eo with
394+ | Some e ->
395+ count_in_expression value_name module_name open_modules
396+ current_module e
397+ | None -> 0 )
398+ (count_in_expression value_name module_name open_modules
399+ current_module e)
400+ args
401+ | Typedtree. Texp_match (e , cases , cases2 , _ ) ->
402+ count_in_expression value_name module_name open_modules current_module e
403+ + List. fold_left
404+ (fun acc c ->
405+ acc
406+ + count_in_expression value_name module_name open_modules
407+ current_module c.Typedtree. c_rhs)
408+ 0 (cases @ cases2)
409+ | Typedtree. Texp_tuple elist | Typedtree. Texp_array elist ->
410+ List. fold_left
411+ (fun acc e ->
412+ acc
413+ + count_in_expression value_name module_name open_modules
414+ current_module e)
415+ 0 elist
416+ | Typedtree. Texp_construct (_ , _ , elist ) ->
417+ List. fold_left
418+ (fun acc e ->
419+ acc
420+ + count_in_expression value_name module_name open_modules
421+ current_module e)
422+ 0 elist
423+ | Typedtree. Texp_variant (_ , eo ) -> (
424+ match eo with
425+ | Some e ->
426+ count_in_expression value_name module_name open_modules
427+ current_module e
428+ | None -> 0 )
429+ | Typedtree. Texp_record { fields; extended_expression; _ } -> (
430+ let acc =
431+ Array. fold_left
432+ (fun acc (_ , fld ) ->
433+ match fld with
434+ | Typedtree. Overridden (_ , e ) ->
435+ acc
436+ + count_in_expression value_name module_name open_modules
437+ current_module e
438+ | Typedtree. Kept _ -> acc)
439+ 0 fields
440+ in
441+ match extended_expression with
442+ | Some e ->
443+ acc
444+ + count_in_expression value_name module_name open_modules
445+ current_module e
446+ | None -> acc)
447+ | Typedtree. Texp_field (e , _ , _ ) ->
448+ count_in_expression value_name module_name open_modules current_module e
449+ | Typedtree. Texp_setfield (e1 , _ , _ , e2 ) ->
450+ count_in_expression value_name module_name open_modules current_module
451+ e1
452+ + count_in_expression value_name module_name open_modules current_module
453+ e2
454+ | Typedtree. Texp_ifthenelse (e1 , e2 , eo ) -> (
455+ count_in_expression value_name module_name open_modules current_module
456+ e1
457+ + count_in_expression value_name module_name open_modules current_module
458+ e2
459+ +
460+ match eo with
461+ | Some e ->
462+ count_in_expression value_name module_name open_modules
463+ current_module e
464+ | None -> 0 )
465+ | Typedtree. Texp_sequence (e1 , e2 ) ->
466+ count_in_expression value_name module_name open_modules current_module
467+ e1
468+ + count_in_expression value_name module_name open_modules current_module
469+ e2
470+ | Typedtree. Texp_while (e1 , e2 ) ->
471+ count_in_expression value_name module_name open_modules current_module
472+ e1
473+ + count_in_expression value_name module_name open_modules current_module
474+ e2
475+ | Typedtree. Texp_for (_ , _ , e1 , e2 , _ , e3 ) ->
476+ count_in_expression value_name module_name open_modules current_module
477+ e1
478+ + count_in_expression value_name module_name open_modules current_module
479+ e2
480+ + count_in_expression value_name module_name open_modules current_module
481+ e3
482+ | Typedtree. Texp_send (e , _ , eo ) -> (
483+ count_in_expression value_name module_name open_modules current_module e
484+ +
485+ match eo with
486+ | Some e ->
487+ count_in_expression value_name module_name open_modules
488+ current_module e
489+ | None -> 0 )
490+ | Typedtree. Texp_open (open_decl , e ) ->
491+ let open_mod =
492+ match open_decl.open_expr.mod_desc with
493+ | Typedtree. Tmod_ident (path , _ ) -> Path. name path
494+ | _ -> " "
495+ in
496+ count_in_expression value_name module_name (open_mod :: open_modules)
497+ current_module e
498+ | _ -> 0
499+ in
500+ let rec count_in_structure value_name module_name current_module structure =
501+ List. fold_left
502+ (fun acc item ->
503+ match item.Typedtree. str_desc with
504+ | Typedtree. Tstr_value (_ , vbs ) ->
505+ acc
506+ + List. fold_left
507+ (fun acc vb ->
508+ acc
509+ + count_in_expression value_name module_name [] current_module
510+ vb.Typedtree. vb_expr)
511+ 0 vbs
512+ | Typedtree. Tstr_eval (e , _ ) ->
513+ acc + count_in_expression value_name module_name [] current_module e
514+ | Typedtree. Tstr_module { mb_expr = { mod_desc; _ } ; _ } -> (
515+ match mod_desc with
516+ | Typedtree. Tmod_structure s ->
517+ acc + count_in_structure value_name module_name current_module s
518+ | Typedtree. Tmod_constraint (mexpr , _ , _ , _ ) -> (
519+ match mexpr.mod_desc with
520+ | Typedtree. Tmod_structure s ->
521+ acc
522+ + count_in_structure value_name module_name current_module s
523+ | _ -> acc)
524+ | _ -> acc)
525+ | _ -> acc)
526+ 0 structure.Typedtree. str_items
527+ in
528+ List. map
529+ (fun dep ->
530+ let file_path_opt = get_module_path graph dep in
531+ if Option. is_some file_path_opt then
532+ let file_path = Option. get file_path_opt in
533+ let cmt_path_opt = find_cmt_path file_path in
534+ if Option. is_some cmt_path_opt then
535+ let cmt_path = Option. get cmt_path_opt in
536+ try
537+ let cmt_info = Cmt_format. read_cmt cmt_path in
538+ match cmt_info.cmt_annots with
539+ | Implementation structure ->
540+ let count =
541+ count_in_structure value_name module_name dep structure
542+ in
543+ (dep, count)
544+ | _ -> (dep, - 2 )
545+ (* -2: No implementation AST *)
546+ with _ -> (dep, - 3 ) (* -3: CMT read error *)
547+ else (dep, - 4 ) (* -4: No .cmt file found *)
548+ else (dep, - 5 )
549+ (* -5: No file path found *) )
550+ dependents
0 commit comments