Subject: bug#39972: 28.0.50; which-function no longer returning current Java method in Emacs 27

From: Alan Mackenzie <[email-masked]>
Date: Sun, 19 Apr 2020 14:03:25 +0000

Hello, Philipp.

On Sat, Mar 07, 2020 at 14:07:42 +0100, Philipp Stephani wrote:

> Assume there's a file /tmp/Foo.java:

> $ cat /tmp/Foo.java 
> class Foo {
>   void bar() {
>     // body
>   }
> }

> Emacs 26:

> $ emacs -Q -batch -l which-func /tmp/Foo.java -eval '(progn (search-forward "// body") (print (which-function)))'

> "bar"

> Emacs 27 pretest:

> $ emacs -Q -batch -l which-func /tmp/Foo.java -eval '(progn (search-forward "// body") (print (which-function)))'

> "class Foo"

> That is, Emacs 27 now prints the clas name instead of the method name.
> I think the Emacs 26 behavior is preferrable.

Yes, indeed.

Just in passing, lisp/progmodes/which-func.el could do with a serious
amount of tender loving care.  I reported a bug about it this morning,
and enclose a rough workaround fix to another one in this post.

> In GNU Emacs 28.0.50 (build 10, x86_64-pc-linux-gnu, GTK+ Version 3.24.12, cairo version 1.16.0)
>  of 2020-02-25
> Repository revision: 03c07c88d90b5747456b9d286bace2dd4a713aac
> Repository branch: master
> Windowing system distributor 'The X.Org Foundation', version 11.0.12004000
> System Description: Debian GNU/Linux rodete

CC Mode's support for "name of function at point" is somewhat
bedraggled, too.  It gets mixed up with c-defun-tactic, the option which
instructs CC Mode to use the current function within the next enclosing
class, etc., rather than the top level thing.

CC Mode's support includes two different functionalities: one intended
for interactive display (triggered by C-c C-z), the other intended for
add-change-log-entry-other-window (C-x 4 a).  I can't actually see why
the second of these is different from the first.  However,
which-function has been using this second of these.

A rough patch to CC Mode is as follows:

diff -r 2c9f4cff0753 cc-mode.el
--- a/cc-mode.el	Fri Apr 03 20:04:29 2020 +0000
+++ b/cc-mode.el	Sun Apr 19 13:37:22 2020 +0000
@@ -778,7 +778,8 @@
     (make-local-variable 'add-log-current-defun-function)
     (setq add-log-current-defun-function
 	  (lambda ()
-	    (or (c-cpp-define-name) (c-defun-name)))))
+	    (or (c-cpp-define-name) 
+		(car (c-defun-name-and-limits nil))))))
 
   (let ((rfn (assq mode c-require-final-newline)))
     (when rfn

However, there is a problem in which-function, where when one puts point
after the final } in your test file, it reports "bar" on the mode line.
It really should indicate "no function" or, at a pinch, "class Foo".
The problem here is in `which-function', where it keeps trying different
methods until it finds one which returns non-nil.  The last of these
methods is a search of the imode list, which contains only "bar".

Here is a very rough workaround, which might form the basis of a proper
fix at some stage.

diff --git a/lisp/progmodes/which-func.el b/lisp/progmodes/which-func.el
index 1cee552b0c..9be629dafd 100644
--- a/lisp/progmodes/which-func.el
+++ b/lisp/progmodes/which-func.el
@@ -282,6 +282,11 @@ which-function
     (when (null name)
       (setq name (add-log-current-defun)))
     ;; If Imenu is loaded, try to make an index alist with it.
+;;;; NEW STOUGH, 2020-04-19
+    ;; If `add-log-current-defun' ran and gave nil, accept this.
+    (when (and (null name)
+               (null add-log-current-defun-function))
+;;;; END OF NEW STOUGH
     (when (and (null name)
 	       (boundp 'imenu--index-alist)
                (or (null imenu--index-alist)
@@ -328,6 +333,9 @@ which-function
                              (funcall
                               which-func-imenu-joiner-function
                               (reverse (cons (car pair) namestack))))))))))))
+;;;; NEW STOUGH, 2020-04-19
+    )
+;;;; END OF NEW STOUGH
     ;; Filter the name if requested.
     (when name
       (if which-func-cleanup-function

-- 
Alan Mackenzie (Nuremberg, Germany).