1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
open Or_error

let handle_file file ~f =
  Odoc_file.load file
  |> Result.map @@ fun unit' ->
     match unit' with
     | { Odoc_file.content = Unit_content (unit, _); _ } -> Some (f unit)
     | _ -> None

let fold_dirs ~dirs ~f ~init =
  dirs
  |> List.fold_left
       (fun acc dir ->
         acc >>= fun acc ->
         Fs.Directory.fold_files_rec_result ~ext:"odocl"
           (fun acc file ->
             file |> handle_file ~f:(f acc) >>= function
             | None -> Ok acc
             | Some acc -> Ok acc)
           acc dir)
       (Ok init)

module H = Hashtbl.Make (Odoc_model.Paths.Identifier)

let count ~dst ~warnings_options:_ directories =
  let htbl = H.create 100 in
  let f () (unit : Odoc_model.Lang.Compilation_unit.t) =
    let () =
      List.iter
        (function
          | ( Odoc_model.Lang.Source_info.Local_jmp
                (ModulePath (`Resolved p as p')),
              _ ) ->
              let id = Odoc_model.Paths.Path.Resolved.(identifier (p :> t)) in
              let old_value =
                match H.find_opt htbl id with Some n -> n | None -> 0
              in
              if not Odoc_model.Paths.Path.(is_hidden (p' : Module.t :> t)) then
                H.replace htbl id (old_value + 1)
          | Local_jmp (ValuePath (`Resolved p as p')), _ ->
              let id = Odoc_model.Paths.Path.Resolved.(identifier (p :> t)) in
              let old_value =
                match H.find_opt htbl id with Some n -> n | None -> 0
              in
              if not Odoc_model.Paths.Path.(is_hidden (p' : Value.t :> t)) then
                H.replace htbl id (old_value + 1)
          | Local_jmp (ClassPath (`Resolved p as p')), _ ->
              let id = Odoc_model.Paths.Path.Resolved.(identifier (p :> t)) in
              let old_value =
                match H.find_opt htbl id with Some n -> n | None -> 0
              in
              if not Odoc_model.Paths.Path.(is_hidden (p' : ClassType.t :> t))
              then H.replace htbl id (old_value + 1)
          | Local_jmp (MtyPath (`Resolved p as p')), _ ->
              let id = Odoc_model.Paths.Path.Resolved.(identifier (p :> t)) in
              let old_value =
                match H.find_opt htbl id with Some n -> n | None -> 0
              in
              if not Odoc_model.Paths.Path.(is_hidden (p' : ModuleType.t :> t))
              then H.replace htbl id (old_value + 1)
          | Local_jmp (TypePath (`Resolved p as p')), _ ->
              let id = Odoc_model.Paths.Path.Resolved.(identifier (p :> t)) in
              let old_value =
                match H.find_opt htbl id with Some n -> n | None -> 0
              in
              if not Odoc_model.Paths.Path.(is_hidden (p' : Type.t :> t)) then
                H.replace htbl id (old_value + 1)
          | _ -> ())
        unit.source_info.infos
    in
    ()
  in
  fold_dirs ~dirs:directories ~f ~init:() >>= fun () ->
  Fs.Directory.mkdir_p (Fs.File.dirname dst);
  let oc = open_out_bin (Fs.File.to_string dst) in
  H.iter
    (fun id occ ->
      let id = String.concat "." (Odoc_model.Paths.Identifier.fullname id) in
      Printf.fprintf oc "%s was used %d times\n" id occ)
    htbl;
  close_out oc;
  let oc = open_out_bin (Fs.File.to_string dst ^ ".bin") in
  Marshal.to_channel oc htbl [];
  Ok ()