This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-03-18
Channels
- # announcements (4)
- # babashka (2)
- # beginners (72)
- # calva (2)
- # cider (18)
- # clj-kondo (30)
- # cljs-dev (2)
- # clojure (106)
- # clojure-austin (2)
- # clojure-europe (17)
- # clojure-italy (6)
- # clojure-nl (4)
- # clojure-uk (109)
- # clojurescript (31)
- # cursive (6)
- # data-science (2)
- # datomic (30)
- # events (1)
- # fulcro (20)
- # graphql (4)
- # jobs (2)
- # joker (8)
- # kaocha (2)
- # meander (31)
- # off-topic (1)
- # pathom (53)
- # re-frame (22)
- # reitit (1)
- # shadow-cljs (26)
- # specter (2)
- # sql (20)
- # testing (2)
- # tools-deps (2)
- # tree-sitter (1)
- # xtdb (20)
- # yada (6)
Is there a particular reason why clj-kondo cannot or should not evaluate macros? We have some macros that evaluate to a def ultimately, and I have to keep my config.edn up to date with the macros. If kondo could macroexpand-1 the macros, would probably solve 80% of these cases.
I can think of several problems:
• this would mean evaluating code from the project (no longer “static analysis”) • this could introduce more warnings (unused let bindings, etc)
Having said that, sci, the Clojure interpreter I wrote, does work with Graal. I've been considering using that for this purpose.
Maybe people could deliver stand-in macros via the configuration that will be evaluated using sci.
One of the challenges is to translate rewrite-clj nodes into sexprs, then transform them using the user-provided sci macro/fn, and then transform them back into rewrite-clj nodes. We can disable certain linters like redundant do / let etc, that's easy.
I'm not sure if you've looked at my static approach to macros in clojure-lsp @U04V15CAJ It's certainly not perfect but might help with ideas that stop short of eval. https://github.com/snoe/clojure-lsp/blob/3502e8e1234642543c3900f78d02477e253dc0d4/src/clojure_lsp/parser.clj#L760
@U0BUV7XSA Is this something users can also bring in as config themselves?
https://github.com/snoe/clojure-lsp#macro-defs probably some things missing still
np. there's also what cursive does which is a step back from my dsl. Cursive let's you say parse my-macro
as def|defn|let|for
and then he hardcodes those library macros that do not fall in the common buckets.
does a lint-as
feed into the analysis part? I've been thinking I could build lsp on top of kondo after looking at your analysis.
one other idea I had is to add more clj-kondo.lint-as/... macros. users can just look at the shape and then lint as that macro. but so far a lot of the custom macros can already be mapped to supported macros
sci could be used like so:
{:lint-as {'foo.core/deffoo "(fn [_ _ name & body] `(def ~name ~@body))"}}
, then sci could apply that function to the expression which invokes the macro and this will then be linted as a regular def
I don’t have time to reduce this case down, but I have an NPE in clj-kondo
from this code:
(ns circle.http.api.v2.context
(:import [circle.http.defapi :refer [defapi-with-auth]]))
Mar 18, 2020 2:18:57 PM org.eclipse.lsp4j.jsonrpc.RemoteEndpoint notify
WARNING: Failed to send notification message.
java.lang.IndexOutOfBoundsException
at clojure.lang.PersistentVector.arrayFor(PersistentVector.java:158)
at clojure.lang.PersistentVector.nth(PersistentVector.java:162)
at clojure.lang.RT.nth(RT.java:896)
at clj_kondo.lsp_server.impl.server$finding__GT_Diagnostic.invokeStatic(server.clj:71)
at clj_kondo.lsp_server.impl.server$lint_BANG_$fn__6246.invoke(server.clj:106)
at clojure.core$map$fn__5866.invoke(core.clj:2753)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:51)
at clojure.lang.RT.seq(RT.java:535)
at clojure.lang.SeqIterator.hasNext(SeqIterator.java:38)
at org.eclipse.lsp4j.jsonrpc.json.adapters.CollectionTypeAdapter.write(CollectionTypeAdapter.java:134)
at org.eclipse.lsp4j.jsonrpc.json.adapters.CollectionTypeAdapter.write(CollectionTypeAdapter.java:40)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:125)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:243)
at com.google.gson.Gson.toJson(Gson.java:669)
at org.eclipse.lsp4j.jsonrpc.json.adapters.MessageTypeAdapter.write(MessageTypeAdapter.java:434)
at org.eclipse.lsp4j.jsonrpc.json.adapters.MessageTypeAdapter.write(MessageTypeAdapter.java:55)
at com.google.gson.Gson.toJson(Gson.java:669)
at com.google.gson.Gson.toJson(Gson.java:648)
at org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler.serialize(MessageJsonHandler.java:145)
at org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler.serialize(MessageJsonHandler.java:140)
at org.eclipse.lsp4j.jsonrpc.json.StreamMessageConsumer.consume(StreamMessageConsumer.java:59)
at org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.notify(RemoteEndpoint.java:126)
at org.eclipse.lsp4j.jsonrpc.services.EndpointProxy.invoke(EndpointProxy.java:88)
at com.sun.proxy.$Proxy7.publishDiagnostics(Unknown Source)
at clj_kondo.lsp_server.impl.server$lint_BANG_.invokeStatic(server.clj:103)
at clj_kondo.lsp_server.impl.server.LSPTextDocumentService.didChange(server.clj:121)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.lambda$null$0(GenericEndpoint.java:65)
at org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.notify(GenericEndpoint.java:152)
at org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.handleNotification(RemoteEndpoint.java:220)
at org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.consume(RemoteEndpoint.java:187)
at org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.handleMessage(StreamMessageProducer.java:194)
at org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.listen(StreamMessageProducer.java:94)
at org.eclipse.lsp4j.jsonrpc.json.ConcurrentMessageProcessor.run(ConcurrentMessageProcessor.java:113)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
(I had an :import
where I should have written :require
)
awesome 👏