Fork me on GitHub
#clj-kondo
<
2023-06-22
>
pyr13:06:59

Hello happy linters! I am adding hooks for some macros I wrote, and I am having issues adding a hook for this particular one: https://github.com/exoscale/ablauf/blob/master/src/ablauf/job/ast.clj#LL103C3-L111C46 I added the following hook:

(ns exoscale.ablauf-hooks)

(defn try-extract
  [sym forms]
  (if (and (list? (last forms)) (= sym (first (last forms))))
    [(vec (drop-last forms)) (drop 1 (last forms))]
    [forms]))

(defmacro try!! [& forms]
  (let [[formsf finallyf] (try-extract 'finally!! forms)
        [formsf rescuef]  (try-extract 'rescue!! formsf)]
    {:ast/type  :ast/try
     :ast/nodes [{:ast/type  :ast/seq
                  :ast/nodes (vec formsf)}
                 {:ast/type  :ast/seq
                  :ast/nodes (vec rescuef)}
                 {:ast/type  :ast/seq
                  :ast/nodes (vec finallyf)}]}))
The issue I am reaching is that while both finally!! and rescue!! are understood as valid symbols in the context of the macro, any qualified symbol used loses its qualification, leading to unused namespace errors. For instance assume the following use of the macro:
(ns my-ns (:require [ablauf.job.ast :as ast] [my-action :as action])) 

(ast/try!!
   (ast/action!! ::action/something {:payload …})
   (finally!! (ast/action!! ::action/cleanup {})))
The above would yield the following warning: warning: namespace my-action is required but never used . Is there a way I am missing to ensure qualification is preserved for the keywords used?

borkdude14:06:18

You could try to preserve the keywords and just emit it in another key of the expansion: :ast/_misc [keywords]

pyr14:06:08

The issue I have is that I don't know ahead of time (in my example, I don't know ahead of time that ::action/something will get called)

pyr14:06:48

If I prn the forms I see :action/something instead of ::action/something

borkdude14:06:09

ah this may be a bug in the macroexpand feature of clj-kondo

borkdude14:06:27

issue welcome

pyr14:06:38

ok will do, thanks!

borkdude14:06:15

I'm not sure how to solve this right now, since you can't represent ::foo/bar as a normal keyword and then turn it back into a ::foo/bar node

borkdude14:06:46

but the alternative is to write an analyze-hook hook which gives you full control over these keywords as rewrite-clj nodes. it's a problem in general though so I'll have to think more about it

pyr14:06:11

I think I have an ok alternative

borkdude14:06:44

cool, what is it?

pyr14:06:39

(still trying) In this particular case I only need the macro to walk the forms to find finally!! and rescue!! I could simply declare those as ok to be unknown and avoid the macro hook entirely

pyr14:06:01

(the root issue would remain)

borkdude14:06:17

I'll figure something out

pyr14:06:39

:linters {:unresolved-symbol {:exclude [(ablauf.job.ast/try!! [rescue!! finally!!])]}}

pyr14:06:47

this did the trick, seems I was trying to be too smart

pyr14:06:52

Another question, I am following this documentation https://github.com/clj-kondo/clj-kondo/blob/85c4b763e7a1c4563722f771243ae7e2359d17f4/doc/config.md#exporting-and-importing-configuration but I cannot get a dependent library to fetch my config, even if explicitly calling copy-configs. I checked that my JAR contains clj-kondo.exports/exoscale/ablauf/config.edn

pyr14:06:03

Well, clojure-lsp dump did the trick and fetched the configuration though, so it's all good

borkdude15:06:24

ah good to hear.

borkdude15:06:46

you should have gotten it with:

clj-kondo --copy-config --lint $(clojure -Spath) --dependencies

pyr15:06:50

I think it was due to the fact that the dependencies are in aliases, anyway thanks, I now have fully working imports and configs, I'll make sure all my public libraries expose kondo hooks for the macros now 🙂

borkdude15:06:36

cool! thanks :)

niclasnilsson09:10:53

I have a small macro that I want to be linted as fn. When I put the macro definition in the ns it’s used from, my clj-kondo linter hints works, but when I move the macro to another namespace, it doesn’t seem to pick up on the linting info. Macro

(defmacro dfn
  {:clj-kondo/config '{:lint-as {playground/dfn clojure.core/fn}}}
  [argslist & body]
  `(fn ~argslist
     (println "-> " (mapv identity ~argslist))
     (let [res# ~@body]
       (println "<- " res# "\n")
       res#)))

borkdude09:10:53

can you provide a full repro, including ns form + clj-kondo config please

borkdude09:10:15

a git repo would be even better

niclasnilsson09:10:54

Need a few minutes

niclasnilsson10:10:11

Well, I’ll be damned… When I put it in a small repo, it works as expected and a .clj-kondo/inline-configs is created… I must have something different configured in the larger context.

niclasnilsson10:10:32

Thanks for making me create a smaller example

borkdude10:10:36

but when I move the macro to another namespace it might be that the old inline config is still active or something, cleaning your cache and then re-linting might have helped

Alexander Kouznetsov20:06:24

Looks like clj-kondo isn’t correctly checking for unused nested classes imports. It highlights the following import as unused even though it is used below and this evaluates without errors in repl:

(:import
    (clojure.lang Compiler$CompilerException))

...

  (is (thrown? Compiler$CompilerException (eval `(...))))

Alexander Kouznetsov20:06:27

Nevermind, it just stopped doing so. Probably it was just a delay.