From 22a7522ef3f0f3c13618214e61f60cb01d80eef4 Mon Sep 17 00:00:00 2001
From: Justin Davis <jrcd83@gmail.com>
Date: Tue, 26 Oct 2021 13:28:16 -0400
Subject: [PATCH] Fix emacs erlang-mode: xref switched to CL-Lib

Fix for GitHub issue #5314.

Xref is a package which is also bundled with emacs:
http://elpa.gnu.org/packages/xref.html

Xref switched its own internally defined classes from EIEIO to
CL-lib (emacs-mirror/emacs@86da812afb2572c7fead2bb07570b976bffd7c55).
erlang-mode subclasses xref-file-location in order to add a function
arity slot to xrefs.

If xref-file-location is a class, use defclass to subclass it. Otherwise
use cl-defstruct. Avoids referencing make-instance, slot-value functions
from EIEIO. Only references constructor, accessor, and predicate
functions.  Updates comments that make references to classes.

Testing:
- cd into lib/tools/emacs.
- Run the tests included with erlang-mode from the shell:
  emacs -Q -batch -L . -l erlang.el -l erlang-test.el \
        -f ert-run-tests-batch-and-exit
- Copy xref.el from the xref package (>=1.3.1) into the
  lib/tools/emacs directory.
- Run the tests again. This will load xref.el automatically
  and use the new interface.
---
 lib/tools/emacs/erlang.el | 48 +++++++++++++++++++++++++--------------
 1 file changed, 31 insertions(+), 17 deletions(-)

diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 69a5fdaeb55..40fe32689e7 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -5120,8 +5120,8 @@ about Erlang modules."
 ;;
 ;; As mentioned this xref implementation is based on the etags xref
 ;; implementation.  But in the cases where arity is considered the
-;; etags information structures (class xref-etags-location) will be
-;; translated to our own structures which include arity (class
+;; etags information structures (struct xref-etags-location) will be
+;; translated to our own structures which include arity (struct
 ;; erlang-xref-location).  This translation is started in the function
 ;; `erlang-refine-xrefs'.
 
@@ -5129,6 +5129,11 @@ about Erlang modules."
 ;; with xref items with xref-etags-location and some deal with xref
 ;; items with erlang-xref-location.
 
+;; NOTE: Around Sept 2021, the xrefs package changed all of its defined types
+;; (i.e.  xref-location, xref-file-location) from EIEIO classes to CL-Lib
+;; structures. These are both supported. Older Emacsen with earlier versions of
+;; xref will continue to use defclass. Newer Emacsen will use cl-defstruct.
+
 (defun erlang-etags--xref-backend () 'erlang-etags)
 
 (defun erlang-soft-require (feature)
@@ -5137,6 +5142,7 @@ about Erlang modules."
 
 (when (and (erlang-soft-require 'xref)
            (erlang-soft-require 'cl-generic)
+           (erlang-soft-require 'cl-lib)
            (erlang-soft-require 'eieio)
            (erlang-soft-require 'etags))
   ;; The purpose of using eval here is to avoid compilation
@@ -5165,10 +5171,20 @@ about Erlang modules."
         (let ((erlang-replace-etags-tags-completion-table t))
           (tags-completion-table)))
 
-      (defclass erlang-xref-location (xref-file-location)
-        ((arity :type fixnum :initarg :arity
-                :reader erlang-xref-location-arity))
-        :documentation "An erlang location is a file location plus arity.")
+      ;; Xref 1.3.1 bundled with Emacs 28+ switched from using EIEIO classes to
+      ;; using CL-Lib structs.
+      (if (find-class 'xref-file-location)
+          (progn
+            (defclass erlang-xref-location (xref-file-location)
+              ((arity :type fixnum :initarg :arity
+                      :reader erlang-xref-location-arity))
+              :documentation "An erlang location is a file location plus arity.")
+            ;; Make a constructor with the same name that a CL structure would have.
+            (defalias 'make-erlang-xref-location 'erlang-xref-location))
+        (cl-defstruct (erlang-xref-location
+                       (:include xref-file-location))
+          "An erlang location is a file location plus arity."
+          (arity 0 :type fixnum)))
 
       ;; This method definition only calls the superclass which is
       ;; the default behaviour if it was not defined.  It is only
@@ -5331,8 +5347,7 @@ is non-nil then TAG is a regexp."
       xrefs
     (when (and xrefs
                (fboundp 'xref-item-location)
-               (fboundp 'xref-location-group)
-               (fboundp 'slot-value))
+               (fboundp 'xref-location-group))
       (let (files)
         (cl-loop for xref in xrefs
                  for loc = (xref-item-location xref)
@@ -5357,7 +5372,8 @@ is non-nil then TAG is a regexp."
            t))))
 
 (defun erlang-xrefs-in-file (file kind tag is-regexp)
-  (when (fboundp 'make-instance)
+  (when (and (fboundp 'make-erlang-xref-location)
+             (fboundp 'xref-make))
     (with-current-buffer (find-file-noselect file)
       (save-excursion
         (goto-char (point-min))
@@ -5369,17 +5385,15 @@ is non-nil then TAG is a regexp."
                    for name = (match-string-no-properties 1)
                    for arity = (save-excursion
                                  (erlang-get-arity))
-                   for loc = (make-instance 'erlang-xref-location
-                                            :file file
-                                            :line (line-number-at-pos)
-                                            :column 0
-                                            :arity arity)
+                   for loc = (make-erlang-xref-location
+                              :file file
+                              :line (line-number-at-pos)
+                              :column 0
+                              :arity arity)
                    for sum = (erlang-xref-summary kind name arity)
                    when (and arity
                              (not (eq arity last-arity)))
-                   collect (make-instance 'xref-item
-                                          :summary sum
-                                          :location loc)
+                   collect (xref-make sum loc)
                    do (setq last-arity arity)))))))
 
 (defun erlang-xref-summary (kind tag arity)
