clojure.tools.analyzer.query-test has been failing since 2015-11-03, it never runs in CI.
git bisect determined commit a61b1699c15911d17f834745521a9837a8916eec introduced the failure
I checked CI and the latest build doesn't execute query-test, presumably because datomic.Datom isn't found.
See
https://build.clojure.org/job/tools.analyzer/728/console
Expected:
(let [ast (ast/prewalk (ast (defn x [] "misplaced docstring" 1))
index-vector-nodes)]
(q '[:find ?docstring
:where
[?def :op :def]
[?def :init ?fn]
[?fn :methods ?method]
[?method :body ?body]
[?body :statements ?statement]
[?statement :val ?docstring]
[?statement :type :string]
[?statement :idx 0]]
[ast]))
#{["misplaced docstring"]}
Actual:
(let [ast (ast/prewalk (ast (defn x [] "misplaced docstring" 1))
index-vector-nodes)]
(q '[:find ?docstring
:where
[?def :op :def]
[?def :init ?fn]
[?fn :methods ?method]
[?method :body ?body]
[?body :statements ?statement]
[?statement :val ?docstring]
[?statement :type :string]
[?statement :idx 0]]
[ast]))
#{}
full repl repro:
(require
'[clojure.tools.analyzer :as ana]
'[clojure.tools.analyzer.ast :as ast]
'[clojure.tools.analyzer.jvm :as ana.jvm]
'[clojure.tools.analyzer.env :refer [with-env]]
'[clojure.tools.analyzer.ast :refer :all]
'[clojure.test :refer [deftest is]]
'[clojure.tools.analyzer.ast.query :refer [q]]
'[clojure.tools.analyzer.ast :as ast]
'[clojure.tools.analyzer.utils :refer [compile-if]]
'[clojure.tools.analyzer.passes.index-vector-nodes :refer [index-vector-nodes]]
'[clojure.tools.analyzer.utils :refer [resolve-sym]])
(require '[clojure.tools.analyzer.passes.elide-meta :refer [elides elide-meta]])
(ns-unmap 'user 'macroexpand-1)
(defn desugar-host-expr [[op & expr :as form]]
(if (symbol? op)
(let [opname (name op)]
(cond
(= (first opname) \.) ; (.foo bar ..)
(let [[target & args] expr
args (list* (symbol (subs opname 1)) args)]
(with-meta (list '. target (if (= 1 (count args)) ;; we don't know if (.foo bar) ia
(first args) args)) ;; a method call or a field access
(meta form)))
(= (last opname) \.) ;; (class. ..)
(with-meta (list* 'new (symbol (subs opname 0 (dec (count opname)))) expr)
(meta form))
:else form))
form))
(defn macroexpand-1 [form env]
(if (seq? form)
(let [op (first form)]
(if (ana/specials op)
form
(let [v (resolve-sym op env)]
(if (and (not (-> env :locals (get op))) ;; locals cannot be macros
(:macro (meta v)))
(apply v form env (rest form)) ; (m &form &env & args)
(desugar-host-expr form)))))
form))
(defmacro foo [] 1)
(def e {:context :ctx/expr
:locals {}
:ns 'user})
(def e1 (atom {:namespaces {'user {:mappings (into (ns-map 'clojure.core)
{'foo #'foo})
:aliases {}
:ns 'user}
'clojure.core {:mappings (ns-map 'clojure.core)
:aliases {}
:ns 'clojure.core}}}))
(defmacro ast [form]
`(binding [ana/macroexpand-1 macroexpand-1
ana/create-var ~(fn [sym env]
(doto (intern (:ns env) sym)
(reset-meta! (meta sym))))
ana/parse ana/-parse
ana/var? ~var?
elides {:all #{:line :column :file :source-span}}]
(with-env e1
(postwalk (ana/analyze '~form e) elide-meta))))
(defmacro mexpand [form]
`(with-env e1
(macroexpand-1 '~form e)))
(let [ast (ast/prewalk (ast (defn x [] "misplaced docstring" 1))
index-vector-nodes)]
(q '[:find ?docstring
:where
[?def :op :def]
[?def :init ?fn]
[?fn :methods ?method]
[?method :body ?body]
[?body :statements ?statement]
[?statement :val ?docstring]
[?statement :type :string]
[?statement :idx 0]]
[ast]))
It appears the datalog query still works.
(let [ast (ast/prewalk (ast (defn x [] "misplaced docstring" 1))
index-vector-nodes)]
(q '[:find ?fn
:where
[?def :op :def]
[?def :init ?fn]]
[ast]))
#{[{:op :with-meta, :env {:context :ctx/expr, :locals {}, :ns user}, :form (fn* ([] "misplaced docstring" 1)), :meta {:op :map, :env {:context :ctx/expr, :locals {}, :ns user}, :keys [{:op :const, :env {:context :ctx/expr, :locals {}, :ns user}, :type :keyword, :literal? true, :val :rettag, :form :rettag, :idx 0}], :vals [{:op :const, :env {:context :ctx/expr, :locals {}, :ns user}, :type :nil, :literal? true, :val nil, :form nil, :idx 0}], :form {:rettag nil}, :children [:keys :vals]}, :expr {:op :fn, :env {:context :ctx/expr, :locals {}, :ns user}, :form (fn* ([] "misplaced docstring" 1)), :variadic? false, :max-fixed-arity 0, :methods [{:children [:params :body], :loop-id loop_4101, :params [], :fixed-arity 0, :op :fn-method, :env {:context :ctx/expr, :locals {}, :ns user, :once false}, :variadic? false, :form ([] "misplaced docstring" 1), :idx 0, :body {:op :do, :env {:context :ctx/return, :locals {}, :ns user, :once false, :loop-id loop_4101, :loop-locals 0}, :form (do "misplaced docstring" 1), :statements [{:op :const, :env {:context :ctx/statement, :locals {}, :ns user, :once false, :loop-id loop_4101, :loop-locals 0}, :type :string, :literal? true, :val "misplaced docstring", :form "misplaced docstring", :idx 0}], :ret {:op :const, :env {:context :ctx/return, :locals {}, :ns user, :once false, :loop-id loop_4101, :loop-locals 0}, :type :number, :literal? true, :val 1, :form 1}, :children [:statements :ret], :body? true}}], :once false, :children [:methods]}, :children [:meta :expr], :raw-forms ((clojure.core/fn ([] "misplaced docstring" 1)))}]}