Fork me on GitHub
#clj-kondo
<
2020-03-18
>
marc-omorain10:03:43

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.

marc-omorain10:03:59

I can think of several problems:

marc-omorain10:03:43

• this would mean evaluating code from the project (no longer “static analysis”) • this could introduce more warnings (unused let bindings, etc)

borkdude10:03:55

Graal does not support clojure.core/eval.

borkdude10:03:48

Having said that, sci, the Clojure interpreter I wrote, does work with Graal. I've been considering using that for this purpose.

borkdude10:03:06

But I'm unsure in how many cases it would work out well.

borkdude10:03:33

Maybe people could deliver stand-in macros via the configuration that will be evaluated using sci.

borkdude12:03:49

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.

snoe18:03:15

I'm not sure if you've looked at my static approach to macros in clojure-lsp @ 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

borkdude18:03:09

@ Is this something users can also bring in as config themselves?

borkdude18:03:14

do you have docs around this?

borkdude18:03:10

I was considering a DSL like this at one point, so thanks for the pointer

snoe18:03:03

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.

borkdude18:03:06

that's also possible using clj-kondo, it's called :lint-as.

snoe19:03:18

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.

borkdude19:03:18

not entirely sure

borkdude19:03:08

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

borkdude19:03:30

and the def-catch-all macro can be used as a last resort

borkdude19:03:12

sci could be used like so:

{:lint-as {'foo.core/deffoo "(fn [_ _ name & body] `(def ~name [email protected]))"}}
, then sci could apply that function to the expression which invokes the macro and this will then be linted as a regular def

borkdude19:03:54

that would be the ultimate DSL if you ask me, just Clojure itself

marc-omorain14:03:45

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]]))

marc-omorain14:03:45

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]]))

marc-omorain14:03:17

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)

marc-omorain14:03:21

(I had an :import where I should have written :require )

borkdude14:03:32

ah so you did reduce it down?