Er, wait, this won't handle nested alists, I'll fix it tomorrow.

Chris


------ Original Message ------
From: "Chris Hecker" <checker@d6.com>
To: "Alan Mackenzie" <acm@muc.de>; "Philip Kaludercic" <philipk@posteo.net>
Cc: 57996@debbugs.gnu.org
Sent: 2022-10-05 06:45:05
Subject: Re[4]: bug#57996: 28.2; imenu doesn't differentiate overloaded c++ functions


Okay, I figured out a way to do this that works pretty easily, and the same idea could be integrated into imenu fairly trivially:

(defun checker-imenu-make-unique-alist (index-alist)
  "De-duplicate the imenu alist by adding indices to duplicate names."
  (let ((h (make-hash-table :test #'equal)))
    (mapc (lambda (el)
            (let* ((k (car el))
                   (v (gethash k h)))
              (if v
                  (let ((n (car v)))
                    (if (= n 1)
                        (setcar (car (cdr v)) (format "%s(1)" k)))
                    (setq n (1+ n))
                    (puthash k '(n nil) h)
                    (setcar el (format "%s(%d)" k n)))
                (puthash k (list 1 el) h))))
          index-alist)))
(advice-add 'imenu--truncate-items :filter-return #'checker-imenu-make-unique-alist)

So this just hooks the imenu--truncate-items function because it was the easiest function that was hookable on the pre-cached side of the code (meaning it doesn't get called every imenu, just on *rescan*).  It puts the function names in a hash, and if they are dupes, it puts (n) after the name.  Works great.

Chris



------ Original Message ------
From: "Chris Hecker" <checker@d6.com>
To: "Alan Mackenzie" <acm@muc.de>; "Philip Kaludercic" <philipk@posteo.net>
Cc: 57996@debbugs.gnu.org
Sent: 2022-10-05 04:15:12
Subject: Re[3]: bug#57996: 28.2; imenu doesn't differentiate overloaded c++ functions


Hmm...

item is selected by the user.  This function is called with
arguments consisting of the item name, the buffer position, and
the ARGUMENTS.

This looks like it might work...  I just opened my .emacs and found I'd already hacked my own version of the c++ matching function, so maybe I'll try this.

A few minutes later...

Okay, so this function does indeed get called, but both Function elements in the imenu list pass the marker for the first Function, so that's unfortunate...  I will look at that...

Another few minutes...

Well, it looks like imenu--generic-function generates the right alist with the two functions and the two different markers, so it's something about choosing in the buffer...

Here's the alist return, looks good:

(("Function" . #<marker at 2 in c.cpp>)
 ("Function" . #<marker at 41 in c.cpp>)
 ("Bar" . #<marker at 95 in c.cpp>))

I should sleep, but maybe there's just a bug in the code that selects the function, or it searches by name instead of by index.   I wish there was some way for the regex match to return a mangled name...I'll look into imenu next.

Chris

------ Original Message ------
From: "Chris Hecker" <checker@d6.com>
To: "Alan Mackenzie" <acm@muc.de>; "Philip Kaludercic" <philipk@posteo.net>
Cc: 57996@debbugs.gnu.org
Sent: 2022-10-05 03:47:06
Subject: Re[2]: bug#57996: 28.2; imenu doesn't differentiate overloaded c++ functions


Yeah, I should probably switch to something a little more modern, but imenu has the advantage of just being there and working most of the time across all machines and shells and stuff.  It definitely gets confused occasionally (like it doesn't find inline functions in class declarations) but this overload thing seemed like it might be a simple fix.


The scanning interface to imenu allows just function names to be
collected. It doesn't allow anything extra (such as a line number) to
be included into the alist.

I guess you could mangle the name to include the line number or match number...kinda hacky but it'd work...maybe I'll take a look.

Chris


------ Original Message ------
From: "Alan Mackenzie" <acm@muc.de>
To: "Philip Kaludercic" <philipk@posteo.net>
Sent: 2022-10-05 03:31:11
Subject: Re: bug#57996: 28.2; imenu doesn't differentiate overloaded c++ functions

Hello, Chris and Philip.
 
On Sun, Oct 02, 2022 at 13:13:16 +0000, Philip Kaludercic wrote:
"Chris Hecker" <checker@d6.com> writes:
 
> With this dumb c++ file:
> ----
> int Function( int n ) {
> return n;
> }
> int Function( float v ) {
> return (int)(v + 0.5);
> }
> ----
 
> Hitting imenu only gives a single Function entry. It should probably
> give two, maybe with a line number after them like "Function(123)" or
> whatever. Currently there's no way to get to the second Function from
> imenu.
 
imenu is old and rather simplistic. It parses a buffer, then stores the
results in an association list. It then uses the function assoc on that
list to get "the" match. What we could do with is a function which gets
_all_ the matches from an alist, and I've asked on emacs-devel about
this.
 
Note that this is not the case when using Eglot and a LSP server like
clangd.
 
Much more modern!
 
I've CC'ed Alan to see if he knows how this could be done by c++-mode
itself.
 
I'm pretty sure it couldn't be. I think it would involve enhancing
imenu. The scanning interface to imenu allows just function names to be
collected. It doesn't allow anything extra (such as a line number) to
be included into the alist.
 
I've looked at problems with imenu in C++ Mode before, but got bogged
down without coming up with a workable solution. There the problem was
identically named methods in different classes, or something like that.
 
So, maybe we can enhance imenu. But not for Emacs 29.
 
--
Alan Mackenzie (Nuremberg, Germany).