clj-kondo

exitsandman 2025-07-14T15:18:39.703279Z

Is there a "feature flag" to know we're in the linter? Of course there's many ways to "know" by observing behaviors, but is there a "blessed" way to do it? (best would be a reader conditional ofc)

2025-07-14T15:27:42.355579Z

what does "in the linter" mean?

exitsandman 2025-07-14T15:42:19.988899Z

I have a macro that expands almost in the same way as its hook (the actual macro performs extra steps with its knowledge of Java classes), so I figured the best thing to do would be to keep the body the same and factor out the difference in a fn. Of course I could just keep two different versions of the fn but if I could do something like:

(defn my-different-part [...]
  #?(:clj ... :kondo ...))
it would be somewhat better. It's nothing super important, almost out of curiousity more than anything.

2025-07-14T16:09:54.632719Z

oh that's clever. i don't think that's currently possible? i think even :macroexpand hooks need to be written in hook files

exitsandman 2025-07-14T16:47:24.028799Z

oh well, for the time being it's the good ol' copy and paste

2025-07-14T15:36:43.467259Z

I have https://github.com/clj-kondo/clj-kondo/pull/2567 to expand the currently disabled :condition-always-true linter to work on non-vars/functions as well. I'd love some feedback from y'all users to make sure I'm not missing/forgetting anything, see examples in thread

2025-07-14T15:37:17.424549Z

>$ bat example.clj
   1   │ (ns cool.foo)
   2   │
   3   │ (if :a 1 2)
   4   │
   5   │ (if (str :a) 1 2)
   6   │
   7   │ (when :a [1 2])
   8   │
   9   │ (if-let [a (filter even? (range 10))] a 2)
  10   │
  11   │ (if-let [{:keys [a]} {:a :b}] a 2)
  12   │
  13   │ (let [a 4 b nil]
  14   │   (cond-> {}
  15   │     a (assoc :a a)
  16   │     b (assoc :b b)))
  17   │
  18   │ (when-let [[a b] '(1 2 3)] [a b])
  19   │
  20   │ (def foo 1)
  21   │ (def bar 2)
  22   │
  23   │ (when-let [[a b] [(foo) (bar)]] [a b])

2025-07-14T15:37:31.897959Z

>$ clojure -M:clj-kondo/dev --config '^:replace {:linters {:type-mismatch {:level :error} :condition-always-true {:level :error}}}' --lint example.clj
example.clj:3:5: error: Condition always true
example.clj:5:5: error: Condition always true
example.clj:7:7: error: Condition always true
example.clj:9:12: error: Condition always true
example.clj:11:22: error: Condition always true
example.clj:15:5: error: Condition always true
example.clj:18:18: error: Condition always true
example.clj:23:18: error: Condition always true

2025-07-14T15:38:52.757919Z

I wrote it to catch sequences that should have been checked with seq, after finding it in code at my workplace, but realized it could cover all types

2025-07-14T15:39:15.492549Z

i searched a large number of code bases and found that this isn't super frequent, but it does exist in the wild

2025-07-14T15:40:35.905059Z

For example, in clojurescript's repl.browser code, the cond-> checks (complement nil?) which is just a function value: https://github.com/clojure/clojurescript/blob/26dea31110502ae718399868ad7385ffb8efe6f6/src/main/clojure/cljs/repl/browser.clj#L190-L194

2025-07-14T15:41:25.341709Z

and here's an example in a library called afterglow: https://github.com/Deep-Symmetry/afterglow/blob/16b0b4cac70433e4118038dfbfd304e22d1d9018/src/afterglow/effects/color.clj#L102, where the goal was to bind the seq of a filter call but instead always succeeds because even an empty sequence is a truthy value until checked with seq

borkdude 2025-07-14T15:42:20.804409Z

I’m aware of the PR, will look at it later this week, thanks 🙏

2025-07-14T16:07:59.350379Z

yeah sorry, not trying to ping you, was trying to ask the clj-kondo user community. i've amended my post to be more explicit

👍 1