clojure-lsp / clojure-lsp

Clojure & ClojureScript Language Server (LSP) implementation

Home Page:https://clojure-lsp.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

False positive: unused-public-var with #(fn) and macroexpand hook

mrkam2 opened this issue · comments

Describe the bug
clojure-lsp/unused-public-var reports a function as unused when it is used in an anonymous function literal inside a macro configured with a hook.

a.clj:

(ns a)

(defn my-fn [x] x)

(defmacro my-do [& body]
  `(do ~@body))

(defn -main []
  ; Leaving only this line will trigger the unused public var message.
  (my-do (map #(my-fn %) (range 10))))

To Reproduce

  1. Unzip issue.zip
  2. Run clojure-lsp diagnostics
  3. See error
    src/a.clj:3:7: info: [clojure-lsp/unused-public-var] Unused public var 'a/my-fn'

Expected behavior
No such error should be reported.

When either :analyze-call hook is used, or #(my-fn %) is replaced with (fn [x] (my-fn [x])), unused variable is not reported.

Thanks for the detailed repro @mrkam2, that happens because clj-kondo doesn't provide the var-definition when using the :macroexpand like you mentioned in the .clj-kondo/config.edn file, I can't see anything to do on clojure-lsp, we would need to make clj-kondo export that.

@borkdude could you try that zip project and confirm it's a desired behavior?

The var is available in the analysis but has a :derived-location because #(...) cannot be represented as an s-expression, so when going through macro-expansion the position is derived. Probably lsp ignores this usage, but that's not clj-kondo's issue.

Yeah, we ignore :derived-location otherwise we will cause a breaking change on custom hooks, this was implemented here, so not sure how to fix that in clojure-lsp without breaking custom hooks that was why we ignored derived-location.

You don't need a location to know that a var is used, even if the var usage has a derived location.