Fork me on GitHub
#clj-kondo
<
2021-03-19
>
Volodymyr Huzar11:03:09

Hello! I am getting an :unused-private-var error for the code below:

(deftype ^:private SessionStore
         [session-service] ...)

(defn db-store [this]
  (SessionStore. this))
Is it something wrong with code on linter is false positive in this case?

borkdude11:03:53

about the function db-store?

borkdude11:03:13

I can't infer from your snippet that this function is used anywhere or not

Volodymyr Huzar11:03:09

sorry, corrected the example, about ns.some/->SessionStore

borkdude11:03:27

This is a false positive. Feel free to post an issue

👍 4
borkdude11:03:42

I think clj-kondo never encountered a private deftype before

yuhan12:03:00

would it make sense for clj-kondo to resolve ns aliases in syntax-quoted forms?

yuhan12:03:49

eg. this compiles even though there's no str alias in the namespace

(defmacro m [coll]
  `(str/join ~(conj coll "hello")))

yuhan12:03:24

when called from another namespace, it expands to the literal symbol str/join which is unresolved

borkdude12:03:23

I think that makes sense, but how can clj-kondo know str is not a fully qualified namespace in general - heuristics?

borkdude12:03:51

I think single segment is probably a safe heuristic

yuhan12:03:56

Yeah, that was what I thought - or anything that's not explicitly :required by the namespace?

borkdude12:03:24

ok, so warning: "Missing alias: str" maybe then? yeah

borkdude12:03:43

I think this can work in general. Right now clj-kondo warns about "Unresolved namespace str" , but I think we could also change that to "Unresolved alias" instead in case of single segment

yuhan12:03:52

I can imagine a strange unhygenic macro which behaves differently according to the aliases of the ns which calls it

yuhan12:03:30

but that's probably very discouraged

borkdude12:03:14

yeah, in that case you can use #_:clj-kondo/ignore

yuhan13:03:27

The bug I ran into actually involved a multi-segment alias (`c2d.c` for clojure2d.color) but I think that's a reasonable heuristic

yuhan13:03:57

eg. a macro-defining ns might want to use fully qualified vars without requiring the ns in advance

borkdude13:03:00

hmm, so this would still not have been caught for you right

yuhan13:03:12

Right now clj-kondo lets you use fully-qualified vars anywhere even though that might lead to subtle breakages with ns loading order - was that an explicit decision?

borkdude13:03:41

Can you give an example?

yuhan13:03:33

eg namespace A requires B and C, B requires D C refers to D/foo without explicitly requiring it, this works because D has been loaded in advance. Later on B drops the D requirement, causing A to break the next time you load it in a repl

yuhan13:03:18

(I've encountered this several times due to long-running repl sessions and shuffling namespaces around)

borkdude13:03:09

clj-kondo warns about namespaces that you have not explicitly required

borkdude13:03:33

e.g. when you type (clojure.string/join [:foo :bar]) without a require, you get a warning

yuhan13:03:31

oh..:face_palm: for some reason I didn't see that warning, might have been editor lag

yuhan13:03:16

could it just extend that analysis into syntax-quoted positions then?

borkdude13:03:12

I don't think that would be correct, since the namespace defining the macro isn't always the one who should require the namespace used in the macro expansion

borkdude13:03:37

although in 99% of the cases, maybe it should

yuhan13:03:25

hmm yeah, I wonder how often that happens in the wild

borkdude13:03:03

we can implement it as an optional linter and then see how much false positives we get

yuhan13:03:18

probably where a utility namespace is defining macros and would otherwise lead to circular requires

yuhan13:03:56

alright, should I open a GH issue?

tanzoniteblack19:03:30

is there a way to have clj-kondo print out the fully merged config it’s made? Trying to debug why my malli generated extra configs aren’t working & want to make sure they’re even being included

borkdude19:03:35

@tanzoniteblack you can view this from the REPL, when you invoke (clj-kondo.core/run! {:lint ["src"]}), the return value will give you a map with :config in it

tanzoniteblack19:03:21

hm…as far as I can tell this is correct, but the linter in the malli directory doesn’t actually seem to be running

:config {:config-paths ["configs/malli"],
          :linters {:type-mismatch {:level :error},
                    :format {:level :warning},
                    :redundant-let {:level :warning},
                    :misplaced-docstring {:level :warning},
                    :missing-test-assertion {:level :warning},
                    :duplicate-set-key {:level :error},
                    :duplicate-map-key {:level :error},
                    :missing-clause-in-try {:level :warning},
                    :inline-def {:level :warning},
                    :missing-body-in-when {:level :warning},
                    :missing-docstring {:level :off},
                    :conflicting-alias {:level :error},
                    :unused-import {:level :warning},
                    :unbound-destructuring-default {:level :warning},
                    :syntax {:level :error},
                    :unused-namespace {:level :warning, :exclude ["taoensso.timbre"]},
                    :not-a-function {:level :error, :skip-args [korma.core/aggregate]},
                    :unresolved-namespace {:level :error},
                    :invalid-arity {:level :error,
                                    :skip-args [yummly.util.korma-util/defentity-tagged
                                                korma.core/defentity
                                                yummly.mobile-util.moustache/app
                                                korma.core/select
                                                korma.core/update
                                                korma.core/delete]},
                    :constant-test-assertion {:level :warning},
                    :missing-map-value {:level :error},
                    :unreachable-code {:level :warning},
                    :redefined-var {:level :warning},
                    :unused-binding {:level :off}},
          :lint-as {taoensso.timbre/debugf clojure.tools.logging/debugf,
                    taoensso.timbre/infof clojure.tools.logging/infof,
                    taoensso.timbre/warnf clojure.tools.logging/warnf,
                    taoensso.timbre/errorf clojure.tools.logging/errorf,
                    clojure.core.async/go-loop clojure.core/loop,
                    potemkin/defrecord+ clojure.core/defrecord},
          :output {:exclude-files ["./test/yummly/util/tracing.clj"]},
          :cfg-dir "/Users/ryan/Code/api/.clj-kondo"},

tanzoniteblack19:03:54

~/Code/api(introduce-malli:zap:)» cat .clj-kondo/configs/malli/config.edn -p
{:lint-as #:malli.schema{defn schema.core/defn}, :linters {:type-mismatch {:namespaces {yummly.data.recipe-collection {get-sort-by-order-hugsql {:arities {1 {:args [:string], :ret :string}}}}}}}}

borkdude19:03:23

if things are merged correctly, you should see the malli config in that returned config

tanzoniteblack19:03:31

oh. and I don’t

tanzoniteblack19:03:39

gotcha, this is what I needed to debug 🙂

borkdude19:03:14

what version of clj-kondo is this?

tanzoniteblack19:03:20

:config-paths ["configs/malli"] at the top level does imply that I have a directory called .clj-kondo/configs/malli

tanzoniteblack19:03:39

figured it out. I’m using a custom config .clj-kondo/config-ci.edn; but it looks like :config-paths only gets picked up if .clj-kondo/config.edn exists & specifies the key

tanzoniteblack19:03:18

so if I do

(clj-kondo.core/run! {:lint ["src"]
                      :config "/Users/ryan/Code/api/.clj-kondo/config-ci.edn"})
with :config-paths in it, they don’t get picked up

tanzoniteblack19:03:23

if we specify custom config paths, is there a reason we shouldn’t resolve and merge in this specified in :config-paths? I can probably make a PR today or next week to handle that situation if you think it’s the right behavior

borkdude19:03:41

Can you lay this out step by step in an issue? I'm kind of swamped in all kinds of slack threads

borkdude19:03:34

I think you're on to something and it probably should be fixed, but github issue is best with some kind of small repro

tanzoniteblack19:03:48

Lunch and bunch of meetings first, then I'll make an issue for it