branch: elpa/cider
commit db1d6b98df0122646a873668e95d2e06b7ac80db
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>

    Fall back to runtime xref references outside a project
    
    `cider-xref-references-mode' defaults to `source', which scans the
    project's files. `cider-xref--project-source-files' returns nothing when
    `project-current' is nil (a standalone file, a non-VC project), so
    `xref-find-references' reported "No references" even when a connected
    REPL could answer via `cider/fn-refs'.
    
    When the source search can't run for lack of a project, fall back to the
    runtime op if a REPL is connected, so the query still returns something
    useful instead of a misleading empty result.
---
 lisp/cider-xref-backend.el       | 19 ++++++++++++++++---
 test/cider-xref-backend-tests.el | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/lisp/cider-xref-backend.el b/lisp/cider-xref-backend.el
index 7360dddc9c..08412f3a09 100644
--- a/lisp/cider-xref-backend.el
+++ b/lisp/cider-xref-backend.el
@@ -123,7 +123,11 @@ The value selects which of the two run:
 In `both' mode the source matches lead, and runtime hits for files the source
 search already scanned are dropped (they would only duplicate the precise
 occurrences at a coarser granularity).  What survives is mainly references the
-compiler generated from macros, which leave no textual trace for the scan."
+compiler generated from macros, which leave no textual trace for the scan.
+
+When `source' is selected but the buffer isn't inside a project (so there are
+no files to scan), CIDER falls back to the runtime search if a REPL is
+connected, rather than reporting no references."
   :type '(choice (const :tag "Source matches only" source)
                  (const :tag "Runtime references only" runtime)
                  (const :tag "Runtime and source matches combined" both))
@@ -198,9 +202,18 @@ The runtime side (the `fn-refs' op) only sees loaded 
namespaces; the source
 side covers code on disk that hasn't been evaluated yet.  In `both' mode the
 two are combined, with runtime hits the source search already covers dropped."
   (let* ((ns (cider-current-ns))
-         (source (when (memq cider-xref-references-mode '(source both))
+         ;; With no project.el project there are no files to scan, so a 
`source'
+         ;; search can't run - fall back to the runtime op (when a REPL is
+         ;; connected) so it still answers, instead of falsely reporting "No
+         ;; references".
+         (mode (if (and (eq cider-xref-references-mode 'source)
+                        (not (project-current))
+                        (cider-connected-p))
+                   'runtime
+                 cider-xref-references-mode))
+         (source (when (memq mode '(source both))
                    (cider-xref--var-source-references var)))
-         (runtime (when (memq cider-xref-references-mode '(runtime both))
+         (runtime (when (memq mode '(runtime both))
                     (cider--fn-refs-xrefs ns var))))
     (when (and source runtime)
       (setq runtime (cider--xref-reject-runtime-overlap runtime source)))
diff --git a/test/cider-xref-backend-tests.el b/test/cider-xref-backend-tests.el
index 81e63e37de..fe694e278d 100644
--- a/test/cider-xref-backend-tests.el
+++ b/test/cider-xref-backend-tests.el
@@ -50,6 +50,38 @@
              (kept (cider--xref-reject-runtime-overlap runtime source)))
         (expect (length kept) :to-equal 1)))))
 
+(describe "xref-backend-references reference-mode selection"
+  (before-each
+    (spy-on 'cider-current-ns :and-return-value "user")
+    (spy-on 'cider-xref--var-source-references :and-return-value nil)
+    (spy-on 'cider--fn-refs-xrefs :and-return-value nil))
+
+  (describe "in `source' mode with no project"
+    (it "falls back to the runtime search when a REPL is connected"
+      (let ((cider-xref-references-mode 'source))
+        (spy-on 'project-current :and-return-value nil)
+        (spy-on 'cider-connected-p :and-return-value t)
+        (xref-backend-references 'cider "foo")
+        (expect 'cider--fn-refs-xrefs :to-have-been-called)
+        (expect 'cider-xref--var-source-references :not :to-have-been-called)))
+
+    (it "does not fall back when no REPL is connected"
+      (let ((cider-xref-references-mode 'source))
+        (spy-on 'project-current :and-return-value nil)
+        (spy-on 'cider-connected-p :and-return-value nil)
+        (xref-backend-references 'cider "foo")
+        (expect 'cider--fn-refs-xrefs :not :to-have-been-called)
+        (expect 'cider-xref--var-source-references :to-have-been-called))))
+
+  (describe "in `source' mode inside a project"
+    (it "uses the source search, not the runtime fallback"
+      (let ((cider-xref-references-mode 'source))
+        (spy-on 'project-current :and-return-value '(vc Git "/tmp/proj/"))
+        (spy-on 'cider-connected-p :and-return-value t)
+        (xref-backend-references 'cider "foo")
+        (expect 'cider-xref--var-source-references :to-have-been-called)
+        (expect 'cider--fn-refs-xrefs :not :to-have-been-called)))))
+
 (provide 'cider-xref-backend-tests)
 
 ;;; cider-xref-backend-tests.el ends here

Reply via email to