Fork me on GitHub
#clj-kondo
<
2021-03-03
>
mikejcusack08:03:30

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?

mikejcusack08:03:45

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.

mikejcusack08:03:08

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.

mikejcusack08:03:57

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

borkdude08:03:04

Repro please.

mikejcusack08:03:36

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

mikejcusack08:03:45

User ns being in dev/

mikejcusack08:03:16

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}

mikejcusack08:03:12

The user ns does get cached in .clj-kondo

mikejcusack08:03:47

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

borkdude08:03:35

Can you please make a standalone repro without LSP.

borkdude08:03:15

Something that I can run locally

borkdude08:03:24

with clj-kondo on the command line only

mikejcusack08:03:30

You don't use lsp?

mikejcusack08:03:48

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

borkdude08:03:17

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

borkdude08:03:35

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

mikejcusack08:03:37

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

borkdude08:03:03

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

mikejcusack08:03:23

I gave you the steps

mikejcusack08:03:50

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

borkdude08:03:07

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

mikejcusack08:03:28

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

borkdude08:03:45

I don't understand.

mikejcusack08:03:53

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

mikejcusack08:03:09

Code can reference a FQDN without a require

mikejcusack08:03:43

fully qualified domain name

borkdude08:03:06

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

mikejcusack09:03:08

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

mikejcusack09:03:50

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

mikejcusack09:03:50

dev/user.clj:

(ns user)

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

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

mikejcusack09:03:30

But results in linting error

mikejcusack09:03:12

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

mikejcusack09:03:30

And it returns the expected :foo

borkdude09:03:19

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

mikejcusack09:03:39

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

borkdude09:03:31

ok, can you file an issue?

borkdude09:03:37

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

borkdude09:03:01

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

borkdude09:03:46

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

mikejcusack09:03:49

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.

borkdude09:03:33

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

borkdude09:03:50

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

mikejcusack09:03:18

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.

danielneal10:03:31

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.

danielneal10:03:22

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

borkdude10:03:47

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

borkdude10:03:58

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

mikejcusack10:03:39

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 .

mikejcusack10:03:57

And fwiw Cursive analyzes this case just fine

mikejcusack10:03:26

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

borkdude10:03:45

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

mikejcusack10:03:09

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."

mikejcusack10:03:33

It does catch that

mikejcusack10:03:47

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

borkdude10:03:51

@U01NYKKE69G 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.

borkdude10:03:11

The user namespace might be an exception

mikejcusack10:03:30

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

mikejcusack10:03:47

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

borkdude10:03:49

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

mikejcusack10:03:00

Which seems like an issue in Clojure itself

borkdude10:03:12

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

mikejcusack10:03:41

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

mikejcusack10:03:50

So does your pprint example

mikejcusack10:03:05

And read the link above

borkdude10:03:16

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

mikejcusack10:03:55

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

mikejcusack10:03:08

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

borkdude10:03:57

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

mikejcusack10:03:37

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

borkdude10:03:51

Not if the namespace hasn't been loaded yet.

mikejcusack10:03:00

That's not what always means

borkdude10:03:12

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

borkdude10:03:40

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

borkdude10:03:49

I'm off to other business now

mikejcusack10:03:51

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

mikejcusack10:03:31

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.

mikejcusack10:03:02

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

borkdude10:03:13

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

mikejcusack10:03:16

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

borkdude10:03:53

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

mikejcusack10:03:04

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.

borkdude10:03:25

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

馃憤 3
borkdude09:03:06

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

imre15:03:34

@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?

borkdude15:03:53

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

imre15:03:42

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