package zanuda

  1. Overview
  2. Docs
Linter for OCaml+dune projects

Install

Dune Dependency

Authors

Maintainers

Sources

v1.1.0.tar.gz
sha256=5b7deabdb016858a0e19ddfb7647f628a243065f88c5ae9f4c362500d51cea7a
sha512=ceb852103fbbb88b5eeb8130bc7aa8bffe7130df6645d3298e1bb9b8f7e8f6c7b323ccc474cf92a08d28e7b80e9a96d68fd53de2e51c7c0e7d8e3e82e436b4bc

doc/src/zanuda.core/Collected_decls.ml.html

Source file Collected_decls.ml

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
85
86
87
88
89
90
91
92
93
94
95
[@@@ocaml.text "/*"]

(** Copyright 2021-2024, Kakadu. *)

(** SPDX-License-Identifier: LGPL-3.0-or-later *)

[@@@ocaml.text "/*"]

open Utils
module StringSet = Set.Make (String)

let all_decls = Hashtbl.create 100
let used_decls = Hashtbl.create 100

let add_decl dict decl =
  if String.starts_with ~prefix:"Stdlib." decl
  then ()
  else if not (Hashtbl.mem dict decl)
  then Hashtbl.add dict decl ()
;;

let add_used_decl decl = add_decl used_decls decl

let add_just_decl decl =
  (* printfn "%s: %s" __FUNCTION__ decl; *)
  add_decl all_decls decl
;;

let print_decls info dict =
  let names = Hashtbl.to_seq_keys dict |> List.of_seq |> List.sort String.compare in
  if not (Base.List.is_empty names)
  then (
    Utils.printfn "%s:" info;
    List.iteri (fun i -> Format.printf "%2d: %s\n" i) names)
;;

let print_used_decls () = print_decls "used" used_decls
let print_all_decls () = print_decls "all" all_decls

let collect_unused () =
  Hashtbl.iter (fun k _ -> Hashtbl.remove all_decls k) used_decls;
  print_decls "Unused declarations" all_decls
;;

let not_skippable_ident id =
  let name = Ident.name id in
  (* Highly likely some function created by ppx_deriving *)
  (not (Base.String.is_prefix name ~prefix:"pp_"))
  && (not (Base.String.is_prefix name ~prefix:"show_"))
  (* TODO: detect usage of fancy operators. Currently we don't count them *)
  && (not (Base.String.equal name "let*"))
  && not (Base.String.equal name "let+")
;;

let collect_from_mli_tree (is_wrapped : Load_dune.w) filename tree =
  let module_name =
    filename
    |> String.split_on_char '/'
    |> List.rev
    |> List.hd
    |> String.split_on_char '.'
    |> List.hd
    |> String.mapi (fun i c -> if i = 0 then Char.uppercase_ascii c else c)
  in
  let __ _ =
    printfn
      "%s, modname = %s,    wrapped = %a"
      __FUNCTION__
      module_name
      Load_dune.pp_w
      is_wrapped
  in
  let rec collect_from_module seed = function
    | { Typedtree.sig_items } ->
      let open Typedtree in
      List.iter
        (function
          | { sig_desc = Tsig_value { val_id = id } } ->
            (*Format.printf "found value %s\n" (seed ^ Ident.name id);*)
            if not_skippable_ident id then add_just_decl (seed ^ "." ^ Ident.name id)
          | { sig_desc =
                Tsig_module
                  { md_id = Some id; md_type = { mty_desc = Tmty_signature sign } }
            } ->
            (*Format.printf "found module %s\n" (Ident.name id);*)
            collect_from_module (seed ^ "." ^ Ident.name id) sign
          | _ -> ())
        sig_items
  in
  collect_from_module
    (match is_wrapped with
     | Wrapped name -> name ^ "." ^ module_name
     | _ -> module_name)
    tree
;;
OCaml

Innovation. Community. Security.