Subject: 30.1.50; Using etags, Ada and xref-find-definitions doesn't find definitions

From: Troy Brown <[email-masked]>
Date: Sun, 18 May 2025 21:37:19 -0400

For this issue, you can just load the Ada source into Fundamental
mode.  The problem doesn't appear to be with the major mode, but
instead with the etags backend for xref not fully supporting the Ada
tags generated by etags.  The following source file can be used to
reproduce the problem (named hello_world.adb):

--8<---------------cut here---------------start------------->8---
with Ada.Text_IO; use Ada.Text_IO;

procedure Hello_World is
   procedure Display_Message is
   begin
      Put_Line ("Hello, World!");
   end Display_Message;
begin  -- Hello_World
   Display_Message;
end Hello_World;
--8<---------------cut here---------------end--------------->8---

1. Generate TAGS: etags *.adb
2. emacs -Q hello_world.adb
3. Place point over Display_Message on line 9
4. M-x xref-find-definitions
5. Select TAGS file previously generated
6. Message buffer contains "No definitions found for: Display_Message"

Digging into this, it appears the reason the definition is not found
is because of the `etags-xref-find-definitions-tag-order`, or more
specifically, that `tag-exact-match-p` contained in that list does not
account for the suffix appended by etags for Ada tags.  According to
the the Emacs manual [(info "(emacs) Tag Syntax")], Ada tags will
contain a "/b", "/f", "/k", "/p", "/s" or "/t" suffix to distinguish
the type of tag.  This can be observed by looking at the contents of
the generated TAGS file.  When invoking `xref-find-definitions`, the
symbol at point (i.e., "Display_Message" in this example) will not
exactly match the tag found in the TAGS file (i.e.,
"Display_Message/p"), thus the observed "No definitions found"
message.

I assume this is just an oversight that `xref-find-definitions` does
not work out of the box with Ada tags.  The older `M-x find-tag` will
work as expected, as well as other functions which don't expect an
exact match (i.e., `M-x xref-find-apropos`).  However, It's surprising
that `xref-find-definitions` does not work out of the box with the
output that etags generates.

I've worked around this issue by creating `ada-tag-exact-match-p`
which mimics `tag-exact-match-p` but handles the Ada suffixes
generated by etags, and then adding it to
`etags-xref-find-definitions-tag-order`.

--8<---------------cut here---------------start------------->8---
(defun ada-tag-exact-match-p (tag)
  (let* ((ada-tag-suffix (rx "/" (or "b" "f" "k" "p" "s" "t")))
(ada-tag (concat (regexp-quote tag) ada-tag-suffix)))
    (or (and (looking-at (concat ada-tag-suffix (rx ?\001)))
     (eq (char-after (- (point) (length tag) 1)) ?\177))
(looking-at (concat (rx (* (not (or ?\177 ?\n))) ?\177) ada-tag (rx ?\001))))))

(with-eval-after-load 'etags
  (add-to-list 'etags-xref-find-definitions-tag-order
'ada-tag-exact-match-p 'append))
--8<---------------cut here---------------end--------------->8---

It's unclear to me how special handling like this should be handled in
the etags xref backend.