clj-kondo 2025-09-30

Is there no way to ignore categorically any form with initial element x even if x is unresolved? IOW

$ echo '(x blah 5/0 who cares)' | clj-kondo --lint -
0 errors

where does x come from and in what context is this used? more context, better answers

interned via repl

it seems this works:

$ echo '(x blah 5/0 who cares)' | clj-kondo --lint - --config '{:linters {:unresolved-symbol {:exclude [(user/x)]}}}'
<stdin>:1:9: error: Divide by zero
linting took 8ms, errors: 1, warnings: 0

but I admit the config is a bit weird and perhaps only working accidentally

it would be a lot easier if x was qualified

yeah, seems some things will even work with unqualified symbol, but only if kondo sees how it got there, eg a refer or a defmacro etc.

is there any prior art on stateful linting, to disallow new instances of a finding? Besides the state management, the other challenge is how to define what counts as the "same finding"

manually marking each existing instance with an explicit ignore option is certainly one way to go, but rather difficult to do across a large codebase (which is precisely the case where stateful linting would be most useful, I think)

There are some things that are only reported once, like unresolved symbols. But if you are using clojure-lsp, they overrode this and you can't undo this. Which imo is a bug in clojure-lsp. Can you give an example of the kind of finding you would like to ignore once and for all?

apologies for being unclear— I'm talking about a situation where we'd like to enforce "no new uses of this code pattern" via lint rule

for example, use of a deprecated class/var

there's already a linter for deprecated vars

right, but we can't make that a blocking finding in our tooling because of many existing instances which can't all be removed at once. However we would still like to block new uses of the deprecated var

i.e. "don't make things worse"

I understand the use case. Some people have programmatically filtered out new findings compared to old findings in CI. Would that be an idea?

yes as far as the state management, but that still leaves the challenge of identifying what counts as the same finding

since line numbers may shift

yes, that's a hard problem. Perhaps compare only by filename and message

probably ok for small/medium files, but seems likely to cause false positives and general confusion for large ones (of which we unfortunately have a good few...)

but I'll try it out and see. Was mostly curious if anyone had done anything clever in that space already

the other thing is it would be really nice to surface these earlier, in the IDE, because by the time a PR gets to CI the work has already been mostly done. Cursive now supports clj-kondo natively so I'm also thinking about whether we could do something there

I don't have anything clever, sorry. there are some other tricks you could do perhaps. Like rename the deprecated function. This renames all old usages. Then re-introduce the deprecated function and a wrapper with the renamed name.

Don't know if you use LLMs but I've heard someone clean up an entire big codebase based on clj-kondo warnings, he reached 0 for the first time in years

how would you prevent new uses of the renamed var?

rename it to dont-use-this-anymore-please and frown on it in a PR?

hah, sure. Although in our case it's actually entire deprecated modules rather than vars, and there are hundreds of them

or you could enforce a policy that only new files that developers touch should be free from warnings

you could also count the deprecated var usage and if it goes up for a certain var, you fail CI

possibly, yeah. But for DX I'd really like to make it specific to the offending addition. And ideally surface it in IntelliJ rather than CI. But I need to noodle on that more first

this is probably a bad idea, but can kondo hooks directly query the cache?

it can with ns-analysis but the cache data has to exist already