clojure-emacs / cider

The Clojure Interactive Development Environment that Rocks for Emacs
https://cider.mx
GNU General Public License v3.0
3.54k stars 646 forks source link

Cider jumps to clojure.core/fn as source of stack frames for top level anonymous functions #3157

Open hugoduncan opened 4 years ago

hugoduncan commented 4 years ago

Expected behavior

Cider jumps to the correct source when clicking a stack trace frame.

Actual behavior

Cider jumps to clojure.core/fn as source of stack frames for top level anonymous functions.

Steps to reproduce the problem

(def ^{:test (fn [] (throw (ex-info "err" {})))} my-fn
  (fn []))

(defn call-my-fn []
  ((:test (meta #'my-fn))))

(call-my-fn)

Click on the first displayed stack frame - opens clojure,core/fn.

Note that this is the pattern used by deftest.

Environment & Version information

All things master head. Mac.

CIDER version information

;; CIDER 0.26.0snapshot, nREPL 0.8.0-alpha5
;; Clojure 1.10.1, Java 1.8.0_252

Emacs version

GNU Emacs 26.3 (build 1, x86_64-apple-darwin18.2.0, NS appkit-1671.20 Version 10.14.3 (Build 18D109)) of 2019-09-02
bbatsov commented 4 years ago

I'll take a look, but I have a feeling this might be tricky to solve as I doubt we can get meaningful location metadata for lambdas.

hugoduncan commented 4 years ago

When run from a compiled namespace, the displayed file name and line number are correct.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution and understanding!

stale[bot] commented 3 years ago

This issues been automatically closed due to lack of activity. Feel free to re-open it if you ever come back to it.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution and understanding!

stale[bot] commented 3 years ago

This issues been automatically closed due to lack of activity. Feel free to re-open it if you ever come back to it.

hugoduncan commented 3 years ago

I was just looking for this issue yesterday. It would be very useful to jump to test source lines from exceptions thrown in tests.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution and understanding!

opqdonut commented 2 years ago

This is hurting my workflow as well. The stack trace shows the right file & line information, so why does CIDER jump somewhere else?

vemv commented 2 years ago

Moved issue to the Orchard repo which is where I believe it belongs technically, and also where it can get best attention (as you can see in https://github.com/clojure-emacs/cider/issues, the CIDER tracker is more of mixed bag, so issues are more likely to pile up).

Will investigate when I have the chance.

vemv commented 2 years ago

Finally, it doesn't seem that there's an issue in Orchard or cider-nrepl.

The following patch can be applied to cider-nrepl:

diff --git a/test/clj/cider/nrepl/middleware/stacktrace_test.clj b/test/clj/cider/nrepl/middleware/stacktrace_test.clj
index f5660c9..11ccfa9 100644
--- a/test/clj/cider/nrepl/middleware/stacktrace_test.clj
+++ b/test/clj/cider/nrepl/middleware/stacktrace_test.clj
@@ -17,15 +17,32 @@
 (defn stack-frames
   [form]
   (analyze-stacktrace
-   (try (eval form)
-        (catch Exception e
-          e))))
+   (let [this-ns *ns*]
+     (try
+       (eval form)
+       (catch Exception e
+         e)
+       (finally
+         (-> this-ns str symbol in-ns))))))

 ;; ## Test fixtures

 (def form1 '(throw (ex-info "oops" {:x 1} (ex-info "cause" {:y 2}))))
 (def form2 '(do (defn oops [] (+ 1 "2"))
                 (oops)))
+
+(def form-issue-153 '(do
+                       (ns cider.nrepl.middleware.stacktrace-test.foo.bar.baz)
+                       (def ^{:test (fn [] (throw (ex-info "err" {})))} my-fn
+                         (fn []))
+
+                       (defn call-my-fn []
+                         ((:test (meta #'my-fn))))
+
+                       (call-my-fn)))
+
+(->> (stack-frames form-issue-153) clojure.pprint/pprint)
+
 (def form3 '(not-defined))
 (defn divi [x y] (/ x y))
 (def form4 '(divi 1 0))

Ten running lein test :only cider.nrepl.middleware.stacktrace-test will show the following pprinted stacktrace:

({:fn "fn",
  :method "invokeStatic",
  :ns "cider.nrepl.middleware.stacktrace-test.foo.bar.baz",
  :name
  "cider.nrepl.middleware.stacktrace_test.foo.bar.baz$fn__2628/invokeStatic",
  :file "stacktrace_test.clj",
  :type :clj,
  :file-url nil,
  :line 36,
  :var "cider.nrepl.middleware.stacktrace-test.foo.bar.baz/fn",
  :class "cider.nrepl.middleware.stacktrace_test.foo.bar.baz$fn__2628",
  :flags #{:tooling :clj}}
 {:fn "fn",
  :method "invoke",
  :ns "cider.nrepl.middleware.stacktrace-test.foo.bar.baz",
  :name
  "cider.nrepl.middleware.stacktrace_test.foo.bar.baz$fn__2628/invoke",
  :file "stacktrace_test.clj",
  :type :clj,
  :file-url nil,
  :line 36,
  :var "cider.nrepl.middleware.stacktrace-test.foo.bar.baz/fn",
  :class "cider.nrepl.middleware.stacktrace_test.foo.bar.baz$fn__2628",
  :flags #{:dup :tooling :clj}}
 {:fn "call-my-fn",
  :method "invokeStatic",
  :ns "cider.nrepl.middleware.stacktrace-test.foo.bar.baz",
  :name
  "cider.nrepl.middleware.stacktrace_test.foo.bar.baz$call_my_fn/invokeStatic",
  :file "stacktrace_test.clj",
  :type :clj,
  :file-url
  "file:/Users/vemv/cider-nrepl-upstream/test/clj/cider/nrepl/middleware/stacktrace_test.clj",
  :line 40,
  :var "cider.nrepl.middleware.stacktrace-test.foo.bar.baz/call-my-fn",
  :class
  "cider.nrepl.middleware.stacktrace_test.foo.bar.baz$call_my_fn",
  :flags #{:tooling :clj}}
 ,,,

In the first item, one can see a :fn "fn", :ns "cider.nrepl.middleware.stacktrace-test.foo.bar.baz" entry, with correct :line info.

So it's cider.el that isn't making sense of this info - maybe it infers from fn that it's clojure.core/fn?

vemv commented 2 years ago

The relevant cider.el code probably is https://github.com/clojure-emacs/cider/blob/956984faa1f8a5edc9eb94eacdf530cb9404850b/cider-stacktrace.el#L531-L552 . Note how it handles var/class/method info, which maps 1:1 to what cider.nrepl.middleware.stacktrace is returning (see the data in https://github.com/clojure-emacs/cider/issues/3157#issuecomment-1047892402)

Maybe (cider-resolve-java-class ...) shouldn't be used for this code path? Perhaps that's what's returning clojure.core/fn.

Because I use an old fork I'm not in a position to hack on it atm, feel free to.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution and understanding!