Page
Library
Module
Module type
Parameter
Class
Class type
Source
# olint
Think clippy for OCaml — which is only fair, given that Rust's original compiler was written in OCaml. We're simply returning the favour.
A linter for OCaml source files. Catches antipatterns, partial function misuse, naming violations, and the kind of code that works perfectly well until a Tuesday in March at 3am when it very much doesn't. Uses compiler-libs directly,no custom parser, no PPX dependency, no build step required. Just very firmly held opinions.
opam pin add olint git+https://github.com/Zaneham/OlintOr, for those who enjoy the journey:
git clone https://github.com/Zaneham/Olint
cd olint
opam install cmdliner
dune build
dune installPoint it at things. It will find fault.
olint src/
olint lib/ bin/ test/
olint --severity warn src/ # only the serious stuff
olint --format json src/ # for machines, who judge silently
olint --list-rules # know thy accuser
olint --lang lang/fr.txt src/src/parser.ml:42:3 [W001] unused open: `open Printf` is not referenced
hint: remove the open or use a qualified name
src/eval.ml:87:5 [W003] List.length in comparison is O(n); compare against [] instead
hint: use `xs <> []` or `xs = []` for emptiness checks
src/main.ml:12:1 [W005] List.hd may raise; consider a safe alternative
hint: use List.hd_opt or pattern matching
src/util.ml:31:9 [W008] `if x then true else false` is redundant; use `x` directly
hint: remove the if/else and use the condition directlyExit codes: 0 clean, 1 warnings, 2 errors. An escalating scale of disappointment.
ID | Name | Sev | What it objects to |
|---|---|---|---|
W001 | unused-open | W |
|
W002 | redundant-match | W | Identity match — every arm returns its pattern, achieving nothing with great ceremony |
W003 | list-length-compare | W |
|
W004 | list-nth | W |
|
W005 | partial-function | W |
|
W006 | naming-convention | I | Enforces snake_case for values and PascalCase for modules, because convention is all that stands between us and barbarism |
W008 | bool-redundancy | W |
|
W009 | eta-reduce | I |
|
W010 | exn-control-flow | I |
|
Run olint --list-rules for the full catalogue of grievances.
Because the difference between a useful tool and an annoying one is the ability to say "yes, I know, shut up about it."
(* olint:disable W001 *)
open Printf (* no warning — you've made your choice *)
(* olint:enable W001 *)
(* olint:disable-next-line W005 *)
let first = List.hd xs (* just this once *)For CI pipelines, editors, and other systems that prefer their criticism in machine-readable form:
olint --format json src/[
{
"file": "src/parser.ml",
"line": 42,
"col": 3,
"rule": "W001",
"severity": "W",
"message": "unused open: `open Printf` is not referenced",
"hint": "remove the open or use a qualified name"
}
]Every diagnostic has a stable ID (W001, W003). A developer in Osaka can Google "olint W003" regardless of what language the message is in. Architecture lifted wholesale from BarraCUDA's bc_err.c, because good ideas deserve to be stolen.
olint --lang lang/fr.txt src/Translation file format (one insult per line):
W001=open inutilisé: `open %s` n'est pas référencé
W001.hint=supprimez le open ou utilisez un nom qualifiéEnglish is compiled in as the default, largely because the errors were written in English first and we haven't got round to the others yet. PR's are accepted for other languages. Spanish and French speakers are warned that once my Duolingo hits 60, badly translated error messages are coming your way (so get in before then)
Ast_iterator on the untyped AST. No .cmt files, no build step. olint src/ just works.Longident.Ldot API change, which wrapped both arguments in Location.loc for reasons best known to the compiler team.compiler-libs.common + cmdliner.Apache 2.0 — see LICENSE.