clojure.tools.analyzer.query-test 自 2015-11-03 开始失败,它从未在 CI 中运行。
git bisect 确定提交 a61b1699c15911d17f834745521a9837a8916eec 导致了失败
我检查了 CI,最新的构建没有执行查询测试,可能是由于找不到 datomic.Datom。
查看
https://build.clojure.org/job/tools.analyzer/728/console
预期
(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"]}
实际
(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]))
#{}
完整 repl 复现
(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)
(元表形式)
:else 表单)
表单)
(定义宏expand-1 [表单 环境变量]
(如果 (seq? 表单)
(let [操作符 (first 表单)]
(如果 (ana/specials 操作符)
表单
(let [v (resolve-sym 操作符 环境变量)]
(如果 (并且 (not (-> 环境变量 :locations (获取 操作符))) ;; locals 不能是宏
(:macro (meta v))))
(apply v 表单 环境变量 (其余 表单)) ; (m &表单 &环境变量 & args)
(desugar-host-expr 表单)))))
表单)
(定义宏foo [] 1)
(定义e {:上下文 :ctx/expr
:局部变量 {}
:命名空间 'user})
(定义e1 (atom {:命名空间 {'user {:映射 (into (ns-map 'clojure.core)
{'foo #'foo})
:别名 {}
:命名空间 'user}
'clojure.core {:映射 (ns-map 'clojure.core)
:别名 {}
:命名空间 'clojure.core}}}))
(定义宏ast [形式]
`(绑定 [ana/macroexpand-1 macroexpand-1
ana/create-var ~(函数 [sym 环境变量]
(doto (intern (:ns 环境变量) sym)
(reset-meta! (meta sym))))
ana/parse ana/-parse
ana/var? ~var?
elides {:all #{:line :column :file :source-span}}]
(with-env e1
`(后遍历 (ana/analyze '~形式 e) elide-meta))))
(定义宏mexpand [形式]
`(with-env e1
(macroexpand-1 '~形式 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]))
数据日志查询仍然有效。
(let [ast (ast/prewalk (ast (defn x [] "misplaced docstring" 1))
index-vector-nodes)]
('--> ?fn
:where
[?def :op :def]
[?def :init ?fn]])
[ast]))
#{[:op :with-meta, :env {:context :ctx/expr, :locals {}, :ns user}, :form (fn* ([] "位置不正确的文档字符串" 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* ([] "位置不正确的文档字符串" 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 ([] "位置不正确的文档字符串" 1), :idx 0, :body {:op :do, :env {:context :ctx/return, :locals {}, :ns user, :once false, :loop-id loop_4101, :loop-locals 0}, :form (do "位置不正确的文档字符串" 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 "位置不正确的文档字符串", :form "位置不正确的文档字符串", :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 ([] "位置不正确的文档字符串" 1)))}]}