Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support clojure-lsp/unused-public-var for custom macros #2265

Open
1 task done
mrkam2 opened this issue Feb 1, 2024 · 1 comment
Open
1 task done

Support clojure-lsp/unused-public-var for custom macros #2265

mrkam2 opened this issue Feb 1, 2024 · 1 comment

Comments

@mrkam2
Copy link
Contributor

mrkam2 commented Feb 1, 2024

  • I have read the Clojure etiquette and will respect it when communicating on this platform.

problem

clojure-lsp/unused-public-var linter is quite useful but sometimes we want to suppress it. For example, in a situation when a variable is defined by a custom macro and that's the correct behavior. For such cases, this linter has a useful :exclude-when-defined-by option. Unfortunately, when a hook is used, this option doesn't help much because the custom macro name is not propagated to the linter when a hook is used. In particular, definition parameter received by clojure-lsp.queries/exclude-public-definition? function contains the following two fields (which it then exercises):

  :defined-by clojure.core/defn,
  :defined-by->lint-as clojure.core/defn,

As Eric suggested in slack comment, when :analyze-call hook is used, it can provide additional :defined-by field on the returned map:

(defn defflow [{:keys [node]}]
  ...
    {:node ...
     :defined-by 'state-flow.cljtest/defflow}))

This causes the definition parameter to contain these values instead:

  :defined-by state-flow.cljtest/defflow,
  :defined-by->lint-as clojure.core/defn,

Unfortunately, this is not done by default and there seems to be no way to have it work for :macroexpand hooks.

I looked at the code and I figured that with a small modifications, this information can be always supplied for all the hooks.

Here is the proposed diff: master...mrkam2:clj-kondo:patch-2

Example

I have a macro that defines two variables:

(ns myns)
(defmacro mydef [db n & body]
  `(do (defn ~(str n "-foo") [] (with-open [_# ~db] ~@body))
       (defn ~(str n "-bar") [] (with-open [_# ~db] ~@body))))

I then define a :macroexpand hook with roughly the same content. There are situations when the client code only uses one of these variables and they're being flagged by unused-public-var linter. The simplest solution would be to provide the following config:

{:linters {:clojure-lsp/unused-public-var {:exclude-when-defined-by #{myns/mydef}}}}

But this wouldn't work as when this linter receives the information about these n-foo and n-bar vars their attributes show them as defined by defn and not mydef.

Slack discussion: https://clojurians.slack.com/archives/CPABC1H61/p1706756199608299?thread_ts=1688068718.797849&cid=CPABC1H61.

@borkdude
Copy link
Member

borkdude commented Feb 1, 2024

I'd be fine with that, if you could also add some tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants