eastwood

All things realted to eastwood - the Clojure linter
slipset 2019-06-13T05:35:22.018100Z

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.

slipset 2019-06-13T05:36:43.020300Z

From listening to your defn episode, I’m not sure it that would be interesting/possible to “share” linters across Eastwood and clj-kondo?

2019-06-13T05:39:13.022100Z

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?

2019-06-13T05:40:49.023600Z

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 🙂

borkdude 2019-06-13T07:25:17.024300Z

clj-kondo doesn’t eval anything, it operates on raw AST produced by rewrite-clj

borkdude 2019-06-13T07:25:34.024700Z

fwiw, clj-kondo can already be used as a library in the JVM 😉

borkdude 2019-06-13T07:26:17.025200Z

the reason that it doesn’t eval is that it can only do things that are possible with GraalVM

borkdude 2019-06-13T07:26:36.025500Z

so all macro-expansion must be done “manually”

2019-06-13T07:28:21.026400Z

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?

borkdude 2019-06-13T07:28:51.026800Z

@andy.fingerhut only for ->, ->> and #() at the moment

2019-06-13T07:29:00.027Z

makes sense.

borkdude 2019-06-13T07:29:33.027500Z

I plan to support more, but those were the most frequently used

2019-06-13T07:30:25.028400Z

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.

borkdude 2019-06-13T07:30:55.029100Z

yeah, I started with tools.analyzer.jvm as well, but GraalVM didn’t like it

2019-06-13T07:31:31.029800Z

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.

borkdude 2019-06-13T07:32:19.030Z

I think it also does macro-expansion

2019-06-13T07:33:21.030900Z

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.

borkdude 2019-06-13T07:35:10.032Z

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

2019-06-13T07:35:17.032200Z

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)

borkdude 2019-06-13T07:35:18.032400Z

but it can’t do eval-like things, which is limited

2019-06-13T07:36:18.033400Z

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.

borkdude 2019-06-13T07:36:37.034100Z

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 😉

slipset 2019-06-13T07:36:58.034600Z

In your defn episode, Vijay mentioned lein-yagni, and I was thinking about adding something like that to Eastwood.

slipset 2019-06-13T07:37:15.034800Z

Like an unused symbols linter.

slipset 2019-06-13T07:37:47.035400Z

Where you could specify in the eastwood-config a list of entry points to your app/library.

borkdude 2019-06-13T07:38:01.035600Z

yeah, that’s cool

borkdude 2019-06-13T07:38:17.036100Z

joker already reports private functions which are not used in the current namespace

borkdude 2019-06-13T07:38:19.036300Z

which is an easy one

2019-06-13T07:38:31.036700Z

Eastwood does have several linters with names beginning :unused-. Are you thinking of something that isn't one of those?

2019-06-13T07:39:00.037400Z

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.

slipset 2019-06-13T07:39:23.037600Z

https://github.com/venantius/yagni

slipset 2019-06-13T07:41:10.038500Z

Seems like the linters in unused.clj basically concerns itself with unused things in a rather local scope.

slipset 2019-06-13T07:41:53.040Z

lein-yagni looks at unused public vars across namespaces and also with deps

2019-06-13T07:42:06.040400Z

within a namespace mostly, yes. Agreed that it doesn't seem to have more global checks of whether things are used or not.

slipset 2019-06-13T07:42:37.041Z

so if a calls b calls c but noone calls a, a, b, and c will be flagged as unused.

slipset 2019-06-13T07:43:12.042100Z

a, b, c can be in different ns’s AFAIU

2019-06-13T07:44:19.042200Z

Unused public vars within deps? If it does that, wouldn't that get very noisy for libraries you don't use all of?

slipset 2019-06-13T07:45:09.042800Z

No, no, unused (public) vars within your code, but across namespaces.

2019-06-13T07:45:44.043200Z

ok, it was the "and also with deps" part that I probably misunderstood there.

slipset 2019-06-13T07:46:14.043700Z

Ya, my bad language, the word I was looking for I guess is transitive.

2019-06-13T07:46:20.044Z

got it