clj-kondo

https://github.com/clj-kondo/clj-kondo
2020-09-11T05:01:36.094900Z

nice to have more examples. @lee am finding yours to be particularly instructive, thanks 🙂

1😊
2020-09-11T05:27:35.100300Z

i'm looking at examples of tweaking behavior of :unresolved-symbol here: https://github.com/borkdude/clj-kondo/blob/master/src/clj_kondo/impl/config.clj#L42-L53 it looks like by using :exclude, one can ignore instances globally or within the context of a specific call (or calls). i don't suppose it's possible to ignore instances within specific files... the use case is when there is a file that has no ns form and is using in-ns instead, e.g. clojure's core_deftype.clj, core_print.clj, core_proxy.clj, etc. is there some good way to have the unresolved symbol errors turned off only within those files without modifying them? (i'd rather not turn off the unresolved symbols linting for specific symbols across all of clojure's source if possible.)

borkdude 2020-09-11T06:48:17.101600Z

@sogaiu you can ignore files in the output but that will ignore the entire file

2020-09-11T07:09:21.101800Z

ok thanks

borkdude 2020-09-11T07:24:31.102700Z

@sogaiu Maybe it might sense to also allow namespace local config in config.edn under :namespaces {clojure {pprint {:linters {...} :lint-as {}}}}

borkdude 2020-09-11T07:29:25.103200Z

but this is generally only useful for sources you don't control

borkdude 2020-09-11T07:29:38.103600Z

on the other hand, it might be nice if you don't want to have your config in the source

2020-09-11T07:33:49.104300Z

that sounds interesting -- perhaps it can be noted as a future possibility. if there are other requests for it may be it can be revisited.

borkdude 2020-09-11T07:35:01.105400Z

I'm also thinking about this in the context of REPL-assisted static analysis like https://github.com/clj-kondo/inspector. Right now it only dumps types for the :type-mismatch linter but we could have like a reverse analysis output format that clj-kondo can take in for linting.

2020-09-11T08:36:08.107600Z

@borkdude i don't see the connection yet, but hopefully will get it in a bit 🙂 btw, regarding hooks and handling macros, have you had a look at colinfleming's 2015 conj talk: https://www.youtube.com/watch?v=kt4haSH2xcs ?

borkdude 2020-09-11T08:40:39.107800Z

I've seen it yes

2020-09-11T08:40:57.108200Z

ok, was curious as it has some mention of parsing macros.

2020-09-11T08:41:15.108900Z

there is this repository that he released after too: https://github.com/cursive-ide/error-test

borkdude 2020-09-11T08:41:22.109300Z

the connection between those two issues is: inform clj-kondo about vars in your namespace. either by suppressing things or really telling it what's there

2020-09-11T08:42:26.109800Z

ah ok, thanks for the explanation.

borkdude 2020-09-11T08:43:10.110800Z

I've considered that approach, and implemented a sexpr-based solution initally, but that didn't work since not all things can carry location metadata. So preserving the rewrite-clj nodes is better for linting and having a full Clojure environment for transforming those nodes is far more powerful than some DSL

borkdude 2020-09-11T08:44:58.112700Z

We can still add clojure spec to the hooks API if you want to do validation on the sexpr directly

2020-09-11T08:45:09.112900Z

ah, too bad that didn't work out. i guess if it means i get my real-time notification from clj-kondo, the being tied to rewrite-clj is a trade-off i'm ok with. (ofc, i am a rewrite-clj* fan 🙂 )

borkdude 2020-09-11T08:46:02.113900Z

The hooks API is rather thin, so switching to some other solution than rewrite-clj might still be possible in the future (but I doubt it)

2020-09-11T08:47:02.114900Z

ok -- well, i doubt i'll come up with anything useful, but a non-library specific approach has some application to other tooling so i'm interested in other ideas.

borkdude 2020-09-11T08:47:33.115300Z

#lsp has a DSL for it

borkdude 2020-09-11T08:47:48.115700Z

but they're switching to clj-kondo now for linting and possibly also analysis

borkdude 2020-09-11T08:48:15.116100Z

I think they ran into some edge cases which couldn't be expressed in the DSL (@snoe)

2020-09-11T08:49:31.116400Z

ah i didn't know about the lsp dsl thing -- thanks for the tip.

borkdude 2020-09-11T08:50:44.117500Z

we can still support something like that as an easier thing instead of hooks which then writes the lower level hooks code for you

borkdude 2020-09-11T08:51:18.117900Z

one benefit of hooks is also that you can emit custom warnings based on your macro input

borkdude 2020-09-11T08:51:28.118400Z

there's already examples of this in the config repo

2020-09-11T08:51:32.118600Z

yes i saw that -- looks cool.

2020-09-11T08:51:59.119200Z

i have been studying the examples and trying to make something for defdirectives in clojure's source

borkdude 2020-09-11T08:53:02.120400Z

I want to add predicates api/vector?, api/symbol? etc so people rely less on api/sexpr which can be a footgun

2020-09-11T08:53:09.120600Z

in emacs-lisp, to get edebug to work with macros they have this way for macro definitions (i think) to express info about how to understand them: https://www.gnu.org/software/emacs/manual/html_node/elisp/Specification-List.html#Specification-List

2020-09-11T08:53:16.120800Z

yeah, that makes sense

2020-09-11T08:53:53.121400Z

i'm sure lread will be happier to see sexpr used less

2020-09-11T08:55:10.121700Z

this rewrite-cljc-playground issue is related, right? https://github.com/lread/rewrite-cljc-playground/issues/5

borkdude 2020-09-11T08:56:20.122100Z

https://github.com/borkdude/clj-kondo/issues/1006

borkdude 2020-09-11T08:56:53.122500Z

Ah yes, thanks

1👍
borkdude 2020-09-11T08:58:43.123800Z

Initially in the hooks API I called api/sexpr on the node, while also adding location as metadata. So people could write hooks directly on the sexpr. After transformation I printed this to a string including metadata and then read this in again using rewrite-clj

borkdude 2020-09-11T08:59:07.124400Z

It works for a lot of the code, but not when you had expressions like (inc 1) in your macro arguments

borkdude 2020-09-11T09:00:02.124800Z

That's mostly why I abandoned that approach

borkdude 2020-09-11T09:00:23.125200Z

else you could have almost used your macro as is for expansion

2020-09-11T09:03:55.125400Z

the current approach sounds safer

2020-09-11T09:04:51.126Z

i need to think a lot more about this -- was mostly curious about background. sorry i was so late to the party 🙂

borkdude 2020-09-11T09:05:28.126500Z

no problem. I think it's pretty cool that we can now run a Clojure interpreter in a binary version of clj-kondo :)

2020-09-11T09:05:39.126800Z

yes, i thought was pretty neat too!

2020-09-11T09:35:26.127400Z

@borkdude so i don't see map-node here: https://github.com/borkdude/clj-kondo/blob/master/src/clj_kondo/impl/hooks.clj is that something that would be ok to add? or may be it's available some other way?

borkdude 2020-09-11T09:36:56.128400Z

I think we could add that, but so far I've often found other ways of dealing with this

borkdude 2020-09-11T09:37:08.128800Z

maybe you could give the example

borkdude 2020-09-11T09:37:25.129100Z

of what's the input and how you are rewriting it

2020-09-11T09:38:09.130Z

so defdirectives i think is supposed to expand to:

(def directive-table {,,,})

borkdude 2020-09-11T09:38:27.130300Z

why is it important that you expand exactly like that macro

borkdude 2020-09-11T09:38:34.130600Z

clj-kondo doesn't do anything with that right

2020-09-11T09:39:01.131200Z

lol -- no idea actually. may be it will be fine to do just (def directive-table nil)?

2020-09-11T09:39:52.131400Z

happier to do less work 🙂

borkdude 2020-09-11T09:40:10.131700Z

I would probably do this:

(defdirectives
  (\A
   [:mincol [0 Integer]
    :colinc [1 Integer]
    :minpad [0 Integer]
    :padchar [\space Character]]
   #{:at :colon :both}
   {}
   #(format-ascii print-str %1 %2 %3))
  )

;; =>

[[\A
  [:mincol [0 Integer]
   :colinc [1 Integer]
   :minpad [0 Integer]
   :padchar [\space Character]]]
 #{:at :colon :both}
 {}
 #(format-ascii print-str %1 %2 %3)]

borkdude 2020-09-11T09:40:29.132Z

it's important that all usages are still visible to clj-kondo

borkdude 2020-09-11T09:40:40.132400Z

else you'll get warnings about unused imports, etc.

2020-09-11T09:41:08.133Z

i think i get what you're saying -- though perhaps it's sensible to wrap the bottom thing in a def form?

borkdude 2020-09-11T09:41:36.133200Z

sure

2020-09-11T09:41:43.133400Z

ok, i'll give that a try. thanks!

borkdude 2020-09-11T09:42:28.134Z

that's one of the 💡 in writing hooks: you don't have to conform to the semantics of the original macro at all

2020-09-11T09:46:03.134600Z

yes, i was noticing that in lread's example but i guess there were two parts of my brain that weren't communicating well 🙂

2020-09-11T09:46:13.134800Z

should make things faster

borkdude 2020-09-11T09:47:10.135100Z

there's also a time macro to measure performance

2020-09-11T09:51:48.135300Z

thanks for the tip

2020-09-11T10:43:58.138100Z

@borkdude ok, your suggested approach is mostly working out. there is one type of thing though that seems to lead to warnings: https://github.com/clojure/clojure/blob/master/src/clj/clojure/pprint/cl_format.clj#L1373-L1379 those bits get wrapped in a fn form -- https://github.com/clojure/clojure/blob/master/src/clj/clojure/pprint/cl_format.clj#L1326 using a list-node with a fn token node and a vector followed by the form to wrap seems to work ok. does that sound sane?

borkdude 2020-09-11T10:44:20.138600Z

very

borkdude 2020-09-11T10:45:01.138900Z

what kind of warning did you get?

2020-09-11T10:52:20.139200Z

one example is:

src/clj/clojure/pprint/cl_format.clj:1375:22: error: unresolved symbol params

borkdude 2020-09-11T10:59:55.140200Z

right, so it expects some fixed set of named args it seems. someone went really wild with their macros there..

2020-09-11T11:06:33.140400Z

ha ha ha

2020-09-11T11:06:58.140900Z

i think with this, the number of errors when linting cl_format.clj are reduced: https://gist.github.com/sogaiu/2be50c906e52a686699c154d4423c91d

2020-09-11T11:07:40.141300Z

i guess cl_format.clj is from a long while back -- it has defstruct

borkdude 2020-09-11T11:08:02.141500Z

about 20 lines of code, doesn't seem that bad: https://gist.github.com/sogaiu/2be50c906e52a686699c154d4423c91d#file-defdirectives-clj-L80-L99

2020-09-11T11:08:29.141700Z

thanks to your tip!

borkdude 2020-09-11T15:28:21.142100Z

Rum hooks for defc and defcs now support multi-arity definitions at https://github.com/clj-kondo/config

borkdude 2020-09-11T18:28:25.143Z

Cool, someone wrote a hook to suggest turning long ->> chains into transducer equivalents: https://github.com/borkdude/clj-kondo/issues/323#issuecomment-691247062