Fork me on GitHub
#clj-kondo
<
2022-04-06
>
ericdallo01:04:44

@fadrian there is this idea of this new clojure-lsp feature, a dump feature https://github.com/clojure-lsp/clojure-lsp/issues/744 That may not be what you seek yet, but something close to achieve that

fadrian11:04:10

Thank you all. I now have some starting points.

sheluchin16:04:13

Is there anything that can help with keywords that either have typos of vary slightly from what's "expected"? These types of bugs have been pretty time consuming on the odd occasion they come up.

pithyless17:04:17

There's no one solution; but there are at least a couple that tackle the problem with different trade-offs: 1. Validation with eg. malli or spec 2. Autocompletion of keywords in editor when typing 3. Find-references with lsp (so you can see you're using the exact same keyword in other places) 4. Tony Kay tried to avoid this problem to the nth-degree in Fulcro, et al. by making custom namespaced vars for each keyword. Then, you never use the keyword itself, but instead the var (which can be checked at compile time, helps with code navigation, etc.) Example namespace: https://github.com/fulcrologic/fulcro-rad/blob/develop/src/main/com/fulcrologic/rad/form_options.cljc

pithyless17:04:32

I just realized this was posted in #clj-kondo and not #clojure. Hope the advice is still useful, but would be interested to know if there is already something in clj-kondo or lsp that would help with this further.

sheluchin17:04:51

Yeah, I like the way RAD options does it as well, @U05476190. Another option is https://github.com/fulcrologic/guardrails, but it creates a fairly significant load in my ETL pipeline, so it has its own tradeoffs. Maybe something like a namespaced keyword whitelist or something might be helpful? Something that defined that :a/x and :a/y are valid, but :a/z is not. At least in some circumstances it would be useful. I am curious as well if there are any considerations towards this problem in clj-kondo.

pithyless17:04:26

I'm actually not sold on the RAD options approach myself, primarily because I'm not convinced it's a big enough problem in my own codebases. But I did want to point it out, since it is a totally legitimate approach if you do find it an annoying problem. :)

borkdude17:04:40

Right now clj-kondo doesn't have the concept of "I've seen all the files" so it's hard to say whether a keyword is a mistake or not based on the frequency. But if you analyze a whole project and take a look at the keywords analysis you can deduce this yourself. Clojure-lsp however, does have the concept of "seen the whole project" and could maybe help with this somehow based on kondo's keyword analysis.

borkdude17:04:06

Of course with a strict configuration like :a/foo is valid but :a/bar isn't, this would work with clj-kondo

snoe17:04:26

@U05476190 spell-check helps a fair bit too, if you are using full words. A useful lint in lsp, like unused-public-vars, could be single occurrence keywords.

💡 1
borkdude18:04:31

that's what I was thinking of

borkdude18:04:51

perhaps clojure-lsp could just show the frequency of each keyword, similar to vars, or would that be too expensive?

borkdude18:04:58

in lens-mode

borkdude18:04:23

I never use unused-public-var, the frequency info is sufficient for me

sheluchin18:04:05

Single occurrence notice sounds like a happy medium. Showing a frequency next to each one might get a little noisy, but some people would probably prefer that configuration.

ericdallo18:04:36

probably too verbose a lens for that

ericdallo18:04:41

but a custom linter sounds a good POC/try

sheluchin18:04:27

Maybe something along the lines of a single occurrence linter combined with what git does with typos:

$ git logg
git: 'logg' is not a git command. See 'git --help'.

The most similar command is
        log

ericdallo18:04:31

yes, there are some kondo linters that have a similar feature like refer-all , we could do similar

sheluchin18:04:53

Thanks everyone for giving it some thought 🙏

iarenaza09:04:20

@UPWHQK562 In Eastwood you have a linter for that use-case (if I understood you right): https://github.com/jonase/eastwood#keyword-typos

sheluchin09:04:44

@U8T05KBEW interesting. Thanks for the heads up on that. I do not use Eastwood, but interesting nonetheless.

borkdude09:04:52

Maybe create an issue with references to existing implementations / ideas.

sheluchin10:04:15

@U04V15CAJ indeed, I should. I'll get to that a little later today. Thanks.

snoe19:04:22

Is there a lint that exists to catch where fn params are probably mixed up. I feel this would help a lot, wdyt?

(defn foo [attrs widget cog] ...)
(foo {} cog thing) ;; lint warn `cog` is passed as arg2 but `cog` is arg3 name
The lint could compare var names passed to a fn with the param names and warn if there's a mixup. It could probably be done with :keys and literals too
(defn foo [{:keys [a b c]} {:keys [d e f]}] ...)
(foo {:d 1} {:a 2}) ;; lint warn `d` is passed to arg1 expecting a,b,c but `d` is expected by arg2 ; warn `a` ...

borkdude19:04:15

Interesting, would love to see more real world examples of this

borkdude19:04:51

How many times are arguments same-named as the arguments? Not often I assume

dpsutton19:04:34

in my experience there’s a decently high overlap of named arguments to a function and named arguments in the function declaration

snoe19:04:39

Oh I feel it's pretty often, things get passed through, I'll find some examples.

👍 1
snoe19:04:31

In clojure-lsp we often pass analysis components or db as the last arguments.

(defn find-last-order-by-project-analysis [pred? analysis db])
(find-last-order-by-project-analysis
    #(= (:name %) (:name element))
    analysis
    db)
If you're not familiar that db comes last you have to confirm by looking at signature it would be easy to accidentally mix up the order and do (find ... db analysis)

dpsutton19:04:21

in the metabase codebase we have lots of common things called driver, database, card, etc. And those will be the same for invocation and most likely for the definition

borkdude19:04:24

Maybe that's just a sign to turn it into a {:db ...} shaped argument?

borkdude19:04:35

And clj-kondo already has "type annotions" for required keys

snoe19:04:35

https://github.com/clj-kondo/clj-kondo/search?q=resolve-cache-dir I dunno, that's an argument that says always use named params..

borkdude19:04:37

yeah, there's a trade-off. can you make an issue for this and any time you find a real-world OSS example, post it there?

snoe19:04:34

Yup, what are you looking for in examples? Existing bugs with this mixup or more evidence that call sites and functions use the same names?

borkdude20:04:57

The latter. That you can make bugs with this I believe :)

borkdude20:04:55

A concept PR is also welcome. I think what should happen more or less: if a symbol call argument matches a fn arg name but the position doesn't match up, it's a warning

👍 1
snoe20:04:44

I'm not sure if I'll add too many more examples, it's hard to find a function call that doesn't pass at least one var with the same name as an arg.

borkdude20:04:53

Well, then that's a good indication that we should give this at least a try :)

borkdude20:04:54

Thanks

👍 1