package zanuda

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

Install

dune-project
 Dependency

Authors

Maintainers

Sources

zanuda-2.1.0.tbz
sha256=9f6f5684ff7329cf84086e6239f02060e711c369fac1553a55e1cd53d8aa8234
sha512=d90e36fc67ba2f1adc13a964a39c46ec354201ea1ff400c5dfe5ab384e07edcc8d2ec42dc053cdc091e217c4183d97a2d33ac12d3977b65defbac506a0b3418e

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

Source file Lint_filesystem.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
96
97
98
[@@@ocaml.text "/*"]

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

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

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

open Dune_project

let lint_id = "lint_filesystem"

(* type config = { mutable files_to_skip : string list }

let config = { files_to_skip = [] }

let process_switches = function
  | [ "ignore"; files ] ->
    config.files_to_skip <- Stdlib.String.split_on_char ',' files @ config.files_to_skip
  | other ->
    Printf.eprintf "Lint %s: Unsuported switches: %s\n" lint_id (String.concat " " other)
;; *)

let should_be_omitted filename = String.ends_with ~suffix:".ml-gen" filename

let on_module { impl; intf } =
  match impl, intf with
  | None, None -> failwith "Not implemented"
  | Some m, _ when String.(ends_with (lowercase_ascii m) ~suffix:"ast.ml") -> ()
  | None, Some _ | Some _, Some _ -> ()
  | Some ml, None ->
    let filename = Config.recover_filepath ml in
    if should_be_omitted filename
    then ()
    else
      Collected_lints.add
        ~loc:Location.none
        (module struct
          let filename = Config.recover_filepath ml

          let msg ppf file =
            Format.fprintf ppf "File '%s' doesn't have corresponding .mli interface" file
          ;;

          let txt ppf () = Format.fprintf ppf "%a\n" msg ml
          let rdjsonl ppf () = Utils.RDJsonl.pp ppf ~filename ~line:1 msg filename
          let is_valid () = true
          let sarif () = Utils.Report.sarif ~loc:Location.none ~filename ~msg filename
        end)
;;

let on_library { Library.modules } = List.iter on_module modules

let on_executables { modules = _ } =
  (* List.iter on_module modules *)
  ()
;;

let check db =
  if Config.is_check_filesystem ()
  then
    List.iter
      (function
        | Build_context _ | Root _ -> ()
        | Executables es -> on_executables es
        | Library l -> on_library l)
      db
;;

let docs =
  {|
### What it does
Checks that dune project tree is well formed

### Why is is important?

All modules should have .mli interfaces.
The .mli files allow to

* hide some structure items
* write documentation for modules.
* hide dependencies between modules (i.e. speedup compilation)

Without .mli files all your functions will be 'public' in the sence of C++ style OOP.
Usually people autogenerate .mli files and all defined values in that time become public.
Zanuda is able to detect this via `zanuda -unused-decls .`.
But in some cases, .mli files may be too heavy, for example, when we write many type
declarations (sort of AST) with deriving attributes.
In that case .mli file is almost identical to .ml.
To workaround this, this check allows file with a suffix `ast.ml` not to have an .mli interface file.

TODO: Add custom configuration for this.

|}
  |> Stdlib.String.trim
;;

let describe_as_json () = Utils.describe_as_clippy_json lint_id ~docs