I’be been thinking about some other stuff as well. Eastwood as such seem to be divided into three parts: The mechanics of starting Eastwood and figuring out what to lint, the analysis of those files, and then finally the code that does the linting. And I was thinking that the latter bit might be interesting as a library, ie, a library that contains a bunch of fns which take an ast and returns a lint result.
From listening to your defn episode, I’m not sure it that would be interesting/possible to “share” linters across Eastwood and clj-kondo?
Most Eastwood linters use the ast, which requires behaving like require, i.e. eval'ing the top level forms. Does clj-kondo already do that today?
I am guessing there are definitely ways to write useful linters that do not eval all top level forms of the code -- I just haven't thought outside of the mental box I created for myself with Eastwood to see what the differences would be 🙂
clj-kondo doesn’t eval anything, it operates on raw AST produced by rewrite-clj
fwiw, clj-kondo can already be used as a library in the JVM 😉
the reason that it doesn’t eval is that it can only do things that are possible with GraalVM
so all macro-expansion must be done “manually”
Does clj-kondo do any macro-expansion? Not that it needs to, necessarily. Just curious. If it does, does it do it only for a few selected macros built into clj-kondo, or for all macros, including user-defined ones?
@andy.fingerhut only for ->
, ->>
and #()
at the moment
makes sense.
I plan to support more, but those were the most frequently used
For better or worse, I went for "completeness" of macro evaluation in Eastwood. tools.analyzer.jvm made that possible, and has an AST with all kinds of stuff in it that Eastwood probably isn't even using.
yeah, I started with tools.analyzer.jvm as well, but GraalVM didn’t like it
or back up there a second -- tools.analyzer.jvm didn't make the macro-expansion possible. It does provide features like resolving what namespace all symbols are in, or whether they are let-bound or not, in a pretty rigorous way.
I think it also does macro-expansion
It has been a couple of years since I thought carefully about it, but yes, I think you are correct. 🙂 Complete macro-expansion can get pretty tricky to do in the same way that Clojure itself does.
it has pros and cons. clj-kondo is able to lint expressions in a file with a broken map, like {:a 1 :b}
because it just doesn’t care if one thing is broken
I doubt anybody does this in their code, but they could let-bind ->
to be something completely different:
user=> (let [-> list] (-> 5 (+ 2)))
(5 2)
but it can’t do eval-like things, which is limited
I have a vague recollection that it was realizing things like that, that led me to want to using something like tools.analyzer instead of writing it myself.
clj-kondo doesn’t interpret ->
as clojure.core/->
in that code, but it as a let-bound variable that it doesn’t know what to do with 😉
In your defn episode, Vijay mentioned lein-yagni, and I was thinking about adding something like that to Eastwood.
Like an unused symbols linter.
Where you could specify in the eastwood-config a list of entry points to your app/library.
yeah, that’s cool
joker already reports private functions which are not used in the current namespace
which is an easy one
Eastwood does have several linters with names beginning :unused-
. Are you thinking of something that isn't one of those?
Most of them are disabled by default, because when I ran with them enabled on the set of projects I often tested Eastwood with, they tended to be pretty noisy.
Seems like the linters in unused.clj
basically concerns itself with unused things in a rather local scope.
lein-yagni
looks at unused public vars across namespaces and also with deps
within a namespace mostly, yes. Agreed that it doesn't seem to have more global checks of whether things are used or not.
so if a
calls b
calls c
but noone calls a
, a
, b
, and c
will be flagged as unused.
a
, b
, c
can be in different ns’s AFAIU
Unused public vars within deps? If it does that, wouldn't that get very noisy for libraries you don't use all of?
No, no, unused (public) vars within your code, but across namespaces.
ok, it was the "and also with deps" part that I probably misunderstood there.
Ya, my bad language, the word I was looking for I guess is transitive.
got it