[ANN] Zanuda -- OCaml linter experiment

I developed a linter for my FP course in my local university. It analyzed (mostly) typed tree and performs various checks (a.k.a. lints). The list of available lints could be found here.

The discussion about a absence of litner arise from time to time
How possible is a clippy-like linter for OCaml?
and somewhere in What are the biggest reasons newcomers give up on OCaml? I’m not sure that usage of OCaml linter for non-teaching purposes is wise, but if my work will gain some traction, nobody will be able to accuse OCaml that it doesn’t have a linter.

Questions, user reports and PRs will be appreciated.

25 Likes

I’m using this linter for teaching for two years, and I’m very happy that I implemented it. Student’s code is much less annoying to read :slight_smile:

Release 1.1.0

  • #22: Add ‘reviewer’ tool to report lint’s a Github review.
  • #13: Discourage matching a tuple using ‘match’ expression with single branch
    match x with (a,b) -> ...
    
  • #18: Warn about unneeded mutually recursive types
  • #23: Implement a trial version of the Fix module for auto-correction of lints.
    It produces a diff that could be applied later. Dune support is lacking
  • Add command line switch ‘-skip-level-allow ’ to enable/disable lints
    with level=Allow. False has higher priority than per-lint command line switch
    (for example, -no-string_concat)
  • #28: Warn about too many nested if expressions.
  • #32: Warn about constructor names that hide default constructor names
  • #35: Detect manual implementations of List.map/fold functions
  • #50: Propose eta reduction when available
  • #51: Warn about pattern matching on boolean values
  • #53: Warn about "%s" in formatted strings
  • #54: Detection of unused public declarations in .mli file.
  • #56: Simplify lint about missing license. We look for required doc-comments anywhere in the file, not only in the beginning.
  • #60: Skip some checks for some source files (configured via ‘.zanuda’ config file).
  • #15: Split ‘string_concat’ lint to check separately patterns ‘a^b^c’ (level=Allow) and ‘List.fold_left (^)’ (level=Warn).
9 Likes

I’m wondering why you are singling out tuples here, instead of generalising to any and all single-branch matches?

I guess for constructors, there is a chance that a single-constructor type can grow later and you want the diff for that growth to be small? Maybe that’s the reason?

I will add this in TODO list

1 Like

Looks like a great tool. Do you know when it will possible to build it with OCaml 5.x?

Looks great. Can I use it without Dune?

I’m not sure, @adl. The issue is that I’m using first class pattern matching to match typed tree, but with 5.x changes in the typed tree unifying interface for 4.14.2 and 5.3 would be tricky.

@mobileink, At the moment, no. I use dune to parse dune describe output and get information of cmt* files for project modules. If Bazel could provide me something like this, it should be easy to integrate.

So, you use dune as a tool to get cmt* files so you can get typedtree etc? IOW you don’t directly need dune, you need the results of a build? Or rather, results of a build with -bin-annot everywhere. (I ask because I don’t know much about linters.)

Basically, Yes. There are some analysis on non typed parse tree, but it should be easier to get them

Hello hello,
I can’t pledge time to this right now, but would it be worth just making a fork to support OCaml5? I still believe that this tool could be fantastically useful to the ecosystem and newcomers, and it’s a bit sad for such a potentially-impactful tool to be blocked by a version of OCaml.

I’d love to have a checker for variable name conventions :sweat_smile:

On a more design-y decision, I feel like some of the current lints are “too” education-oriented. I.e. more student-friendly than programmer friendly.
For instance, pointing to academic papers in lint messages or mentioning things such as “free theorems”. I don’t think these are necessarily out of place in the OCaml ecosystem, but parts of these messages could probably be hidden behind a --academic flag for the linter?

I have a compilable work-in-progress for OCaml 5.3 in a branch, but currently is prints different messages modulo indentation and all tests are failing crazily. Maybe Format module has changed a bit, maybe a new interface for alerts reporting is a little bit different. It seems that if I won’t find a solution soon, I will create separate tests for 5.3 and 4.14.

There is a config file to enable/disable lints. It should work.

2 Likes

Thank you for your work!!

There is a config file to enable/disable lints. It should work.

I meant, e.g. the list_fusion lint, it’s valuable independently of academic context, but some parts of its explanation (specifically, starting “It’s recommended”) could be adapted to a non-academic audience, e.g. “it is recommended to rewrite this expression using a single application of List.map with a function Fun.compose f g” or something similar. For an academic/student audience, it’s still valuable to have mentions of free theorems and Wadler papers.

Zanuda 2.0.0 with OCaml 5.3 support have hit opam.

7 Likes