Fork me on GitHub
Joshua Suskalo14:06:28

So I'm looking at the codebase to try and add an exclude config to use blocks. It looks like the :use lint is different from the other ns lints in that it's registered immediately rather than just associng in something new to register a finding for later. For this would it be better to try and refactor the use finding to work the same way as e.g. refer-all, or would it be better to just add an additional requirement in the and expression that gates registering the finding?

Joshua Suskalo14:06:09

The latter is most certainly easier, but it's inconsistent with the rest.


What is the problem you're trying to solve?


you're trying to unify the code for :use and :refer :all in clj-kondo's codebase?

Joshua Suskalo14:06:42

More or less. I just want the :use linter to have an :exclude config


you could also migrate to :refer :all


but that's only a workaround ;)


but I'm open to improvements, as long as the tests pass and there are no perf regressions

Joshua Suskalo14:06:18

Right. I was more or less asking if you'd prefer if I just add a one-liner that just doesn't register the use finding if the config excludes the ns, or if you'd prefer that I try to make use work like refer does


I would have to look into that, don't remember the exact code. I think :refer :all has some logic that prefetches some vars from the cache to improve linting, does :use also have that?

Joshua Suskalo14:06:19

yeah, looks like there's a call to reg-var-usage!


What it does is look at the cache in case of :refer :all so it can actually resolve names better. clj-kondo has a hard time with use and refer all because it has nothing to go by statically

Joshua Suskalo14:06:55

it just assoces stuff into the :referred-all segment and passes that on so that it would get used here

R.A. Porter14:06:46

I don't know if this is a problem with Cursive, the IJ file watcher plugin, or clj-kondo, but I'm seeing the following, where the indicator in the IDE is highlighting the fn inside the sexpr instead of either the whole sexpr or the int fn itself (what I'd expect). The output below shows the correct columns, which correspond to the open paren for the subs sexprs.


can you make a minimal repro in text? then I'd be happy to try out what it does in emacs. you could also just disable clj-kondo to see if that is or is not the problem?

R.A. Porter14:06:26

This function does it for me:

(ns alignment)

(defn foo
  (let [sub1 (subs s 0 10)
        x (int (subs sub1 0 2))
        y (int (subs sub1 3 5))]
    (+ x y)))

R.A. Porter14:06:55

With clj-kondo turned off, it doesn't highlight the subs fns; with clj-kondo turned on, it does.


The reason it highlights it is that subs returns a string but int expects a char, although in CLJS that may just work

R.A. Porter14:06:03

My expectation is that it would highlight either int or the entire function call for subs if that's not what is intended, I'll just have to adjust my expectation.


I’ll try in emacs when I get back to home


I think it's just an artifact of how the tooling works, clj-kondo does the right thing I think

👍 3

@U5NCUG8NR feedback: this kind of stuff:

(set (get-in ctx [:config :linters :use :exclude])
is done in config.clj in a way that it caches this result


I mean, getting values from the config

Joshua Suskalo15:06:49

Oh, cool. I'll try taking a look at that. This is why I wanted to make it a draft, so I'd find some things that I wouldn't have thought of otherwise. 🙂

Joshua Suskalo15:06:19

That's interesting, it looks like all the other config access in this file is just threading it through keywords

Joshua Suskalo15:06:47

But maybe I'm missing something here and the caching happens earlier, looks like it does in the linters.clj file


in config.clj


the above are just checks whether the config is enabled or not

Joshua Suskalo15:06:02

Right, I was looking for usages of it.


but sometimes more work is needed, such as the set conversion you are doing


and this should optimally only happen once


but as people can also have namespace-local config, this should be cached per version of the config

Joshua Suskalo15:06:14

Ah, makes sense. I did make a coersion function there. Actually, I'm looking at this and it appears that there may be a bug/feature which is that the config for refer-all appears to apply to both use and refer-all


that may just be a feature

Joshua Suskalo15:06:06

Then this pr should probably just update the documentation

Joshua Suskalo15:06:15

I think it's a little weird that there's two different linters and yet only one configuration, but if this is fine, then I'll just update the docs.


:refer :all and :use are very similar in their effect


whether you write (:use clojure.test) or (:require [clojure.test :refer :all]) shouldn't matter


if you want to ignore one, you probably want to ignore the other too

Joshua Suskalo15:06:42

Yeah, I agree with you, but it just seems weird that there's two different linters for it then.


not sure why that was again, but clj-kondo tries to discourage the use of both as you get worse linting with it anyway.


I personally never use either

Joshua Suskalo15:06:20

That's definitely fair. I don't under normal circumstances.


there are exceptions like DSL-like things

Joshua Suskalo15:06:14

Yup. In any case, the PR is updated, it only adds a config section to the use linter which refers back to the refer-all linter

Joshua Suskalo15:06:15

Awesome, thanks

Joshua Suskalo19:06:53

Does the lint-as clojure.core/defn have issues with multiple fn bodies?


it should not

Joshua Suskalo19:06:43

Hmm. I'm trying to mess with specter again and multi-path isn't linting correctly. I've set the lint-as for defdynamicnav to lint-as defn, but it's saying it can't resolve path1 and path2

(defdynamicnav multi-path
  "A path that branches on multiple paths. For updates,
   applies updates to the paths in order."
  ([] STAY)
  ([path] path)
  ([path1 path2]
   (late-bound-richnav [late1 (late-path path1)
                        late2 (late-path path2)]
     (select* [this vals structure next-fn]
       (let [res1 (i/exec-select* late1 vals structure next-fn)]
         (if (reduced? res1)


can you make an example I can actually try locally, so a complete form? this will make it easier for me to help you

Joshua Suskalo19:06:36

Sure, sorry about that

Joshua Suskalo19:06:32

(defdynamicnav something
  ([] nil)
  ([path] path)
  ([item1 item2]
   [item1 item2]))

Joshua Suskalo19:06:46

This recrates the error, all defdynamicnav has to be is some random macro that has lint-as set to defn

Joshua Suskalo19:06:34

Hmm. It seems like it might be something specific to this config. I want to do a little more testing.


This works:

(ns foo
  {:clj-kondo/config '{:lint-as {bar/defdynamicnav clojure.core/defn}}}
  (:require [bar :refer [defdynamicnav]]))

(defdynamicnav something
  ([] nil)
  ([path] path)
  ([item1 item2]
   [item1 item2]))

Joshua Suskalo19:06:06

Yeah, it worked fine for me just now too when I defined my own macro. Maybe it's that defdynamicnav is being created wrong or something.

Joshua Suskalo19:06:20

I need to go through this a little more slowly.