clj-kondo 2025-07-01

i'm writing a complex hook for #splint's patterns, and i need to postwalk the clj-kondo nodes. has anyone written a postwalk for clj-kondo nodes?

✅ 1

Are you writing a hook for a macro in splint or ..?

maybe it's easier to use :macroexpand hook so you can use normal postwalk? it's not as accurate but a lot easier

well, i don't want to macroexpand, i want to call api/reg-finding! for mistakes

the macroexpansion would be......... very big

I see. do you have an example perhaps, so I can better understand your use case?

(defrule performance/into-transducer
  "..."
  {:pattern '(into [] ((? trans transducers) ?f ?coll))
   ...}

and what is an example of a finding you want to catch?

:pattern doesn't need to be quoted but i do quote it because that stops clj-kondo for yelling. i'd like to lint it.

one sec while i write an example

since it's a macro you can also do the check in your macro :)

but why do you need postwalk for this?

oh i do, i throw lots of errors, but i use clj-kondo and want the faster linting as well

yes understood, why not both

the :pattern is like a sexpr regex, where it matches literal forms in the given shape, except for symbols that start with ? (like ?coll), or lists that start with ? (like (? trans transducers)). the symbols are just captures which are stored in a context map, but the lists have special rules about them

(? trans transducers) binds x to ?trans if it matches the predicate (transducers x) , so it requires transducers to exist.

ok, so it's more than just the quote, right

that you want to lint

right, i need to walk the form and find the lists that start with ? (or other special forms i won't get into), and then check if they're broken in some way lol

What I meant with the :macroexpand hook is that this may be way easier to implement. :macroexpand isn't just about macroexpansion, you can still return nil and call findings/reg-finding!

but you get to operate on normal s-expressions

and it all carries metadata?

in sofar possible. numbers can't carry metadata but symbols will

👍 1

(defn walk
  [inner outer form]
  (cond
    (:children form) (outer (assoc form :children (mapv inner (:children form))))
    :else (outer form)))

(defn postwalk
  [f form]
  (walk #(postwalk f %) f form))
did what i need it to do lol

much simpler than clojure.walk's impl

I think this might mess up some nodes that don't have a :tag keyword on them but implement the protocol in a different way

but I'm not sure about that

i'm merely using this as a way to step through the whole thing, i return the original object each time

ah then it's ok for sure

👍 1

(postwalk (fn [obj] (...) obj) node)

i have a bunch of s/def specs for a macro i have, which validates things like "is this a number?" and "either pattern OR patterns but not both". is it possible to get clj-kondo to use the specs to check my macro without writing a hook?

✅ 1

unfortunately not since specs usually aren't very static in nature

👍 1