samedi 6 juin 2020

Clojure's disappearing reflection warnings

A simple reflection warning example:

lein repl
user=> (set! *warn-on-reflection* true)
true
user=> (eval '(fn [x] (.length x)))
Reflection warning, NO_SOURCE_PATH:1:16 - reference to field length can't be resolved.
#object[user$eval2009$fn__2010 0x487ba4b8 "user$eval2009$fn__2010@487ba4b8"]

I want to make this into a function. But where do reflection warnings go?

//clojure/compile.java 63
RT.errPrintWriter()
                .format("Reflection warning, %s:%d:%d - reference to field %s can't be resolved.\n",
                                SOURCE_PATH.deref(), line, column, fieldName);

//clojure/RT.java 269
public static PrintWriter errPrintWriter(){
    Writer w = (Writer) ERR.deref();

//clojure/RT.java 188
final static public Var ERR =
    Var.intern(CLOJURE_NS, Symbol.intern("*err*"),
               new PrintWriter(new OutputStreamWriter(System.err), true)).setDynamic();

Ok so they go to System.err. Lets capture it's output:

(def pipe-in (PipedInputStream.))
(def pipe-out (PipedOutputStream. pipe-in))
(System/setErr (PrintStream. pipe-out))

(defn reflection-check [fn-code]
  (binding [*warn-on-reflection* true]
    (let [x (eval fn-code)
          ;_ (.println (System/err) "foo") ; This correctly makes us return "foo".
          n (.available pipe-in)

          ^bytes b (make-array Byte/TYPE n)
          _ (.read pipe-in b)
          s (apply str (mapv char b))]
      s)))

However, calling it gives no warning, and no flushing seems to be useful:

(println "Reflection check:" (reflection-check '(fn [x] (.length x)))) ; no warning.

How can I extract the reflection warning?





Aucun commentaire:

Enregistrer un commentaire