clj-kondo

https://github.com/clj-kondo/clj-kondo
mikejcusack 2021-03-03T08:17:30.089500Z

I'm getting a Unresolved namespace user. Are you missing a require? for referencing symbols in my user.clj. Why is this happening when there is a user namespace defined and it doesn't need a require because it's fully qualified?

mikejcusack 2021-03-03T08:23:45.089800Z

The user.clj is in a separate dev/ source directory. I have a .lsp/config.edn, which includes dev/ in the source paths. The error still is present.

mikejcusack 2021-03-03T08:30:08.090Z

Adding a .clj-kondo/config.edn with {:output {:include-files ["^src" "^dev" "^test"]}} resolved the issue. But I'm confused why this is necessary when the .lsp/config.edn is present. This is happening in vscode with Calva.

mikejcusack 2021-03-03T08:32:57.090300Z

Actually it didn't. It made the linting not work at all.

borkdude 2021-03-03T08:35:04.090500Z

Repro please.

mikejcusack 2021-03-03T08:44:36.090700Z

Define a var in the user ns. Try to reference it with user/foo

mikejcusack 2021-03-03T08:44:45.090900Z

User ns being in dev/

mikejcusack 2021-03-03T08:45:16.091100Z

So my .lsp/config.edn is

{:source-paths #{"src" "dev"}
 :project-specs [{:project-path "deps.edn"
                  :classpath-cmd ["clj" "-A:dev" "-Spath"]}]
 :semantic-tokens? true}

mikejcusack 2021-03-03T08:46:12.091300Z

The user ns does get cached in .clj-kondo

mikejcusack 2021-03-03T08:46:47.091600Z

Does the same thing in my Doom Emacs setup so it's not Calva specific

borkdude 2021-03-03T08:47:35.091800Z

Can you please make a standalone repro without LSP.

borkdude 2021-03-03T08:48:15.092Z

Something that I can run locally

borkdude 2021-03-03T08:48:24.092200Z

with clj-kondo on the command line only

mikejcusack 2021-03-03T08:48:30.092400Z

You don't use lsp?

mikejcusack 2021-03-03T08:49:48.092600Z

Running clj-kondo --lint <file> results in the same output

borkdude 2021-03-03T08:51:17.092800Z

I do use LSP but when posting an issue with clj-kondo, I don't want to use any downstream tools

borkdude 2021-03-03T08:51:35.093Z

If it's an issue with LSP, post in #lsp

mikejcusack 2021-03-03T08:51:37.093200Z

Ok. Well as I said, running it alone results in the same error

borkdude 2021-03-03T08:52:03.093400Z

ok, but that's still not a repro that I can run locally. You'll have to provide me with an actual file or repo that I can run

mikejcusack 2021-03-03T08:52:20.093600Z

...?

mikejcusack 2021-03-03T08:52:23.093800Z

I gave you the steps

mikejcusack 2021-03-03T08:52:50.094Z

Create a dev/user.clj, put any def in it. Then reference it from src/<something> as user/<def>

borkdude 2021-03-03T08:54:07.094200Z

You will have to just put a (require 'user) in there for now. Clj-kondo expects this for any namespace you are using

mikejcusack 2021-03-03T08:54:28.094400Z

But that doesn't make sense given it's a fully qualified ns

borkdude 2021-03-03T08:55:45.094600Z

I don't understand.

mikejcusack 2021-03-03T08:55:53.094800Z

And adding in a ns require [user :as user]doesn't work either

mikejcusack 2021-03-03T08:56:09.095Z

Code can reference a FQDN without a require

borkdude 2021-03-03T08:56:20.095200Z

fqdn?

mikejcusack 2021-03-03T08:56:43.095400Z

fully qualified domain name

borkdude 2021-03-03T08:57:06.095600Z

That's not true though. You can't just (foo.bar.baz/x) without requiring foo.bar.baz in general

mikejcusack 2021-03-03T09:00:08.095800Z

Not sure what you mean. Open a fresh repl and eval (clojure.string/starts-with? "foo" "f")

mikejcusack 2021-03-03T09:00:50.096Z

And as I said, if I require [user :as user] it still doesn't work

mikejcusack 2021-03-03T09:05:50.096200Z

dev/user.clj:

(ns user)

(def foo :foo)
src/kondo.clj:
(ns kondo)

(prn user/foo)
deps.edn:
{:paths ["src" "dev"]}

mikejcusack 2021-03-03T09:07:22.096500Z

This works

mikejcusack 2021-03-03T09:07:30.096700Z

But results in linting error

mikejcusack 2021-03-03T09:08:12.096900Z

And you can start a repl and (in-ns 'kondo) and then user/foo

mikejcusack 2021-03-03T09:08:30.097100Z

And it returns the expected :foo

borkdude 2021-03-03T09:10:19.097400Z

As I said you should add a (require 'user) in your (ns kondo) file

mikejcusack 2021-03-03T09:10:39.097600Z

Not necessary as I said and it still results in the linting error

borkdude 2021-03-03T09:11:31.097800Z

ok, can you file an issue?

borkdude 2021-03-03T09:12:37.098Z

For now you can solve the problem with {:linters {:unresolved-var {:exclude [user]}}} after adding the require

borkdude 2021-03-03T09:13:01.098200Z

it is unusual what you are doing here btw, normally you will not refer to the user namespace from the code in src

borkdude 2021-03-03T09:14:46.098400Z

it's usually the other way around, you will require other namespaces from user and then use them from user

mikejcusack 2021-03-03T09:15:49.098800Z

I have dev-time vars defined there and I'm not referring to them in src/ outside of a comment block. I'm referring to them in test/ mostly.

borkdude 2021-03-03T09:16:06.099300Z

Released a new clj-kondo version 2021.03.03 with some fixes for false positives introduced by the :redundant-expression linter.

borkdude 2021-03-03T09:17:33.099500Z

you can also put a #_:clj-kondo/ignore before the comment block or before the form with the warning to disable the warning

borkdude 2021-03-03T09:18:50.099800Z

But it's still good to post an issue about this so we can improve this

mikejcusack 2021-03-03T09:19:18.100100Z

But I'm seeing the issue. The user ns is special in this case as the repl is loading it at startup. So it's aware of user/foo. But using another ns it isn't working.

danielneal 2021-03-03T10:05:31.100300Z

I wonder if it's this: just because something works, doesn't mean it should lint without errors. For example you can :refer :all and the referred symbols will give errors. I know you can use clojure.string/includes? without requiring clojure.string but for other namespaces it is imo better for the linter to suggest that you require that namespace, as it is then clearer for the next reader.

danielneal 2021-03-03T10:07:22.100700Z

Oh wait, you're saying including (:require [user]) in your ns form doesn't work?

borkdude 2021-03-03T10:08:47.101Z

What is happening (I think) is that clj-kondo overwrites the vars for the user namespace the next time it starts linting a file. Any file basically starts in the user namespace. So after adding the require, he would still get an unresolved-var

borkdude 2021-03-03T10:09:58.101300Z

Not sure what the correct thing to do is, but it really seems like a questionable edge case

mikejcusack 2021-03-03T10:23:39.101500Z

I'm not sure why it's such an edge case. There's a valid use for creating vars in the user namespace so that when you start up the repl you have those already set up. Such as defining a connvar for a db connection. Instead of calling it each time I start a repl I just already have user/conn .

mikejcusack 2021-03-03T10:23:57.101800Z

And fwiw Cursive analyzes this case just fine

mikejcusack 2021-03-03T10:24:26.102Z

clj-kondo is not working with fully qualified namespaces, which is allowed in Clojure

borkdude 2021-03-03T10:24:45.102200Z

@mike.j.cusack Out of curiosity: does Cursive also catch if you write user/foobar if foobar doesn't exist?

mikejcusack 2021-03-03T10:25:09.102400Z

https://www.clojure.org/guides/learn/namespaces#_require "While vars can always be referred to by their fully-qualified name, we rarely want to type fully-qualified names in our code."

mikejcusack 2021-03-03T10:25:33.102600Z

It does catch that

mikejcusack 2021-03-03T10:25:47.102800Z

It's not ignoring the user ns. It's analyzing the local file

borkdude 2021-03-03T10:25:51.103Z

@mike.j.cusack This is not generally true. You can only use this after you load the namespace. And generally you should not rely on other namespaces loading those namespaces for you.

borkdude 2021-03-03T10:26:11.103200Z

The user namespace might be an exception

mikejcusack 2021-03-03T10:26:30.103400Z

It's absolutely true. I already gave you an example. You can use clojure.string without requiring it

mikejcusack 2021-03-03T10:26:47.103600Z

The place where it's inconsistent is in user code, which requires loading the file as you said.

borkdude 2021-03-03T10:26:49.103800Z

@mike.j.cusack This is not true for e.g. (clojure.pprint/pprint {:a 1})

mikejcusack 2021-03-03T10:27:00.104Z

Which seems like an issue in Clojure itself

borkdude 2021-03-03T10:27:12.104200Z

You should not rely on the fact that clojure.string was already loaded by some other library

mikejcusack 2021-03-03T10:27:41.104500Z

I'm not. Literally start a fresh repl in a new dir and use it. It works

mikejcusack 2021-03-03T10:27:50.104700Z

So does your pprint example

mikejcusack 2021-03-03T10:28:05.104900Z

And read the link above

borkdude 2021-03-03T10:28:16.105100Z

$ clj -M -e "(clojure.pprint/pprint {:a 1})"
Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:471).
clojure.pprint

borkdude 2021-03-03T10:29:20.105300Z

I suggest you read this issue: https://github.com/clj-kondo/clj-kondo/issues/339

mikejcusack 2021-03-03T10:29:55.105700Z

It's just like Java. You can always refer to vars by fully qualifying them

mikejcusack 2021-03-03T10:30:08.105900Z

$ clj
Clojure 1.10.2
(clojure.pprint/pprint {:a 1})
{:a 1}
nil

borkdude 2021-03-03T10:31:57.106100Z

$ clj
Clojure 1.10.1
user=&gt; (clojure.set/union #{1 2 3} #{2 3 4})
Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:471).
clojure.set
user=&gt;

mikejcusack 2021-03-03T10:33:37.106300Z

Ok. Well this is quite confusing given the official docs stating you can refer to things by fully qualifying them always

borkdude 2021-03-03T10:33:51.106500Z

Not if the namespace hasn't been loaded yet.

mikejcusack 2021-03-03T10:34:00.106700Z

That's not what always means

borkdude 2021-03-03T10:34:12.106900Z

The fact that your clojure.pprint example works just means that it has already been loaded by some other tool

borkdude 2021-03-03T10:34:40.107100Z

I suggest you verify this in the #clojure channel and people will tell you exactly what I told you

borkdude 2021-03-03T10:34:49.107300Z

I'm off to other business now

mikejcusack 2021-03-03T10:34:51.107500Z

I'm not loading any libs so it's clj repl itself

mikejcusack 2021-03-03T10:36:31.107800Z

But in any case the repl for sure loads the user namespace and it is suggested to add dev helpers in a user.clj to be loaded by the repl automatically.

mikejcusack 2021-03-03T10:37:02.108Z

Cursive treats this correctly and reads your user.clj. clj-kondo does not

borkdude 2021-03-03T10:37:13.108200Z

Yes, I've already suggested you make an issue on Github about this, I am repeating myself.

mikejcusack 2021-03-03T10:38:16.108400Z

I'm not sure why spending all of this time explaining the issue to you is not enough.

borkdude 2021-03-03T10:39:53.108600Z

Is it too much to ask to post your issue on Github so I don't forget about it?

mikejcusack 2021-03-03T10:41:04.108800Z

Since you're talking about yourself forgetting being the issue can you not make the issue yourself with the info I've already provided? I've already taken a chunk of my time to help you when I don't even use the tool. I use Cursive. I'm just trying to be helpful.

borkdude 2021-03-03T10:45:25.109Z

OK, I will write it down somewhere if I have time. I'm kinda busy right now. Thanks for the help.

👍 1
borkdude 2021-03-03T12:21:12.109500Z

https://github.com/clj-kondo/clj-kondo/issues/1190

👍 1
imre 2021-03-03T15:11:34.111400Z

@borkdude I see the latest tag at https://hub.docker.com/r/borkdude/clj-kondo/tags?page=1&amp;ordering=last_updated is a few months old. Did you stop publishing these?

borkdude 2021-03-03T15:11:53.111700Z

@imre Docker images have moved to cljkondo/clj-kondo on Dockerhub

imre 2021-03-03T15:12:42.112200Z

Ah, thank you. The link in https://github.com/clj-kondo/clj-kondo/blob/master/doc/docker.md contains an extra - then 😉

imre 2021-03-03T15:15:29.112600Z

sent a quick pr https://github.com/clj-kondo/clj-kondo/pull/1191

borkdude 2021-03-03T15:16:32.112900Z

Thanks!