clj-kondo

https://github.com/clj-kondo/clj-kondo
Volodymyr Huzar 2021-03-19T11:25:09.060100Z

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?

borkdude 2021-03-19T11:27:53.060300Z

about the function db-store?

borkdude 2021-03-19T11:28:13.060600Z

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

Volodymyr Huzar 2021-03-19T11:29:09.061400Z

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

borkdude 2021-03-19T11:31:27.061800Z

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

1👍
borkdude 2021-03-19T11:31:42.062200Z

I think clj-kondo never encountered a private deftype before

yuhan 2021-03-19T12:37:00.063300Z

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

yuhan 2021-03-19T12:37:49.064Z

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

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

yuhan 2021-03-19T12:39:24.064600Z

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

borkdude 2021-03-19T12:42:23.065200Z

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

borkdude 2021-03-19T12:42:51.065600Z

I think single segment is probably a safe heuristic

yuhan 2021-03-19T12:44:56.067300Z

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

borkdude 2021-03-19T12:45:24.068Z

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

borkdude 2021-03-19T12:45:43.068500Z

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

yuhan 2021-03-19T12:45:52.068700Z

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

yuhan 2021-03-19T12:46:30.069600Z

but that's probably very discouraged

borkdude 2021-03-19T12:47:14.070Z

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

yuhan 2021-03-19T13:05:27.072700Z

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

yuhan 2021-03-19T13:05:57.073200Z

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

borkdude 2021-03-19T13:06:00.073500Z

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

yuhan 2021-03-19T13:06:06.073700Z

yeah

yuhan 2021-03-19T13:08:12.075200Z

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?

borkdude 2021-03-19T13:08:41.075400Z

Can you give an example?

yuhan 2021-03-19T13:11:33.077900Z

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

yuhan 2021-03-19T13:13:18.079100Z

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

borkdude 2021-03-19T13:14:09.079500Z

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

borkdude 2021-03-19T13:14:33.080Z

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

yuhan 2021-03-19T13:16:31.081100Z

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

yuhan 2021-03-19T13:17:16.081800Z

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

borkdude 2021-03-19T13:19:12.082400Z

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

borkdude 2021-03-19T13:19:37.082700Z

although in 99% of the cases, maybe it should

yuhan 2021-03-19T13:20:25.083200Z

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

borkdude 2021-03-19T13:21:03.083900Z

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

yuhan 2021-03-19T13:21:18.084200Z

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

yuhan 2021-03-19T13:21:56.084500Z

alright, should I open a GH issue?

borkdude 2021-03-19T13:22:46.084700Z

yeah

Volodymyr Huzar 2021-03-19T15:55:52.084800Z

Bug is created https://github.com/clj-kondo/clj-kondo/issues/1222

tanzoniteblack 2021-03-19T19:02:30.085700Z

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

borkdude 2021-03-19T19:05:35.086700Z

@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

tanzoniteblack 2021-03-19T19:14:21.086900Z

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"},

tanzoniteblack 2021-03-19T19:14:54.087100Z

~/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}}}}}}}}

borkdude 2021-03-19T19:15:23.087300Z

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

tanzoniteblack 2021-03-19T19:15:31.087500Z

oh. and I don’t

tanzoniteblack 2021-03-19T19:15:39.087700Z

gotcha, this is what I needed to debug 🙂

borkdude 2021-03-19T19:16:14.087900Z

what version of clj-kondo is this?

tanzoniteblack 2021-03-19T19:16:20.088100Z

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

tanzoniteblack 2021-03-19T19:16:21.088300Z

right?

tanzoniteblack 2021-03-19T19:16:30.088500Z

"2021.03.03"

borkdude 2021-03-19T19:16:49.088700Z

correct

tanzoniteblack 2021-03-19T19:31:39.088900Z

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

tanzoniteblack 2021-03-19T19:32:18.089400Z

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

tanzoniteblack 2021-03-19T19:33:23.089600Z

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

borkdude 2021-03-19T19:34:41.089800Z

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

tanzoniteblack 2021-03-19T19:37:17.090Z

Understood.

borkdude 2021-03-19T19:38:34.090200Z

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

tanzoniteblack 2021-03-19T19:40:48.090400Z

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