diff options
| author | Stephen Leake | 2015-08-26 16:43:29 -0500 |
|---|---|---|
| committer | Stephen Leake | 2015-08-26 16:58:57 -0500 |
| commit | 64fbdc9825ad98ebbc8c021442c1f3c3ba0fd1b1 (patch) | |
| tree | b72f6a944fd02cf945b04060d921799f56085a85 | |
| parent | 2e8750c76940a712f0be93667c042c8987d919d4 (diff) | |
| download | emacs-64fbdc9825ad98ebbc8c021442c1f3c3ba0fd1b1.tar.gz emacs-64fbdc9825ad98ebbc8c021442c1f3c3ba0fd1b1.zip | |
Add mode local overrides to xref-find-definitions
* lisp/cedet/mode-local.el (xref-mode-local--override-present,
xref-mode-local-overload): New; add mode local overrides to
xref-find-definitions.
* test/automated/elisp-mode-tests.el: Add mode local override tests.
(xref-elisp-test-run): Handle indented defuns.
(xref-elisp-generic-*): Improve doc strings.
* lisp/progmodes/elisp-mode.el (elisp-xref-find-def-functions): New.
(elisp--xref-find-definitions): Use it.
| -rw-r--r-- | etc/NEWS | 7 | ||||
| -rw-r--r-- | lisp/cedet/mode-local.el | 98 | ||||
| -rw-r--r-- | lisp/progmodes/elisp-mode.el | 302 | ||||
| -rw-r--r-- | test/automated/elisp-mode-tests.el | 116 |
4 files changed, 367 insertions, 156 deletions
| @@ -88,9 +88,10 @@ command line when `initial-buffer-choice' is non-nil. | |||
| 88 | 88 | ||
| 89 | * Changes in Emacs 25.1 | 89 | * Changes in Emacs 25.1 |
| 90 | 90 | ||
| 91 | ** `describe-function' now displays information about mode local | 91 | ** `xref-find-definitions' and `describe-function' now display |
| 92 | overrides (defined by cedet/mode-local.el | 92 | information about mode local overrides (defined by |
| 93 | `define-overloadable-function' and `define-mode-local-overrides'. | 93 | cedet/mode-local.el `define-overloadable-function' and |
| 94 | `define-mode-local-overrides'). | ||
| 94 | 95 | ||
| 95 | ** New `display-buffer' action function `display-buffer-use-some-frame' | 96 | ** New `display-buffer' action function `display-buffer-use-some-frame' |
| 96 | This displays the buffer in an existing frame other than the current | 97 | This displays the buffer in an existing frame other than the current |
diff --git a/lisp/cedet/mode-local.el b/lisp/cedet/mode-local.el index ce30a985a79..9ee875022f8 100644 --- a/lisp/cedet/mode-local.el +++ b/lisp/cedet/mode-local.el | |||
| @@ -48,6 +48,13 @@ | |||
| 48 | 48 | ||
| 49 | (eval-when-compile (require 'cl)) | 49 | (eval-when-compile (require 'cl)) |
| 50 | 50 | ||
| 51 | (require 'find-func) | ||
| 52 | ;; For find-function-regexp-alist. It is tempting to replace this | ||
| 53 | ;; ‘require‘ by (defvar find-function-regexp-alist) and | ||
| 54 | ;; with-eval-after-load, but model-local.el is typically loaded when a | ||
| 55 | ;; semantic autoload is invoked, and something in semantic loads | ||
| 56 | ;; find-func.el before mode-local.el, so the eval-after-load is lost. | ||
| 57 | |||
| 51 | ;;; Misc utilities | 58 | ;;; Misc utilities |
| 52 | ;; | 59 | ;; |
| 53 | (defun mode-local-map-file-buffers (function &optional predicate buffers) | 60 | (defun mode-local-map-file-buffers (function &optional predicate buffers) |
| @@ -649,6 +656,97 @@ SYMBOL is a function that can be overridden." | |||
| 649 | 656 | ||
| 650 | (add-hook 'help-fns-describe-function-functions 'describe-mode-local-overload) | 657 | (add-hook 'help-fns-describe-function-functions 'describe-mode-local-overload) |
| 651 | 658 | ||
| 659 | (declare-function xref-item-location "xref" (xref)) | ||
| 660 | |||
| 661 | (defun xref-mode-local--override-present (sym xrefs) | ||
| 662 | "Return non-nil if SYM is in XREFS." | ||
| 663 | (let (result) | ||
| 664 | (while (and (null result) | ||
| 665 | xrefs) | ||
| 666 | (when (equal sym (car (xref-elisp-location-symbol (xref-item-location (pop xrefs))))) | ||
| 667 | (setq result t))) | ||
| 668 | result)) | ||
| 669 | |||
| 670 | (defun xref-mode-local-overload (symbol) | ||
| 671 | "For ‘elisp-xref-find-def-functions’; add overloads for SYMBOL." | ||
| 672 | ;; Current buffer is the buffer where xref-find-definitions was invoked. | ||
| 673 | (when (get symbol 'mode-local-overload) | ||
| 674 | (let* ((symbol-file (find-lisp-object-file-name symbol (symbol-function symbol))) | ||
| 675 | (default (intern-soft (format "%s-default" (symbol-name symbol)))) | ||
| 676 | (default-file (when default (find-lisp-object-file-name default (symbol-function default)))) | ||
| 677 | modes | ||
| 678 | xrefs) | ||
| 679 | |||
| 680 | (mapatoms | ||
| 681 | (lambda (sym) (when (get sym 'mode-local-symbol-table) (push sym modes))) | ||
| 682 | obarray) | ||
| 683 | |||
| 684 | ;; mode-local-overrides are inherited from parent modes; we | ||
| 685 | ;; don't want to list the same function twice. So order ‘modes’ | ||
| 686 | ;; with parents first, and check for duplicates. | ||
| 687 | |||
| 688 | (setq modes | ||
| 689 | (sort modes | ||
| 690 | (lambda (a b) | ||
| 691 | (not (equal b (get a 'mode-local-parent)))))) ;; a is not a child, or not a child of b | ||
| 692 | |||
| 693 | (dolist (mode modes) | ||
| 694 | (let* ((major-mode mode) | ||
| 695 | (override (fetch-overload symbol)) | ||
| 696 | (override-file (when override (find-lisp-object-file-name override (symbol-function override))))) | ||
| 697 | |||
| 698 | (when (and override override-file) | ||
| 699 | (let ((meta-name (cons override major-mode)) | ||
| 700 | ;; For the declaration: | ||
| 701 | ;; | ||
| 702 | ;;(define-mode-local-override xref-elisp-foo c-mode | ||
| 703 | ;; | ||
| 704 | ;; The override symbol name is | ||
| 705 | ;; "xref-elisp-foo-c-mode". The summary should match | ||
| 706 | ;; the declaration, so strip the mode from the | ||
| 707 | ;; symbol name. | ||
| 708 | (summary (format elisp--xref-format-extra | ||
| 709 | 'define-mode-local-override | ||
| 710 | (substring (symbol-name override) 0 (- (1+ (length (symbol-name major-mode))))) | ||
| 711 | major-mode))) | ||
| 712 | |||
| 713 | (unless (xref-mode-local--override-present override xrefs) | ||
| 714 | (push (elisp--xref-make-xref | ||
| 715 | 'define-mode-local-override meta-name override-file summary) | ||
| 716 | xrefs)))))) | ||
| 717 | |||
| 718 | ;; %s-default is interned whether it is a separate function or | ||
| 719 | ;; not, so we have to check that here. | ||
| 720 | (when (and (functionp default) default-file) | ||
| 721 | (push (elisp--xref-make-xref nil default default-file) xrefs)) | ||
| 722 | |||
| 723 | (when symbol-file | ||
| 724 | (push (elisp--xref-make-xref 'define-overloadable-function symbol symbol-file) xrefs)) | ||
| 725 | |||
| 726 | xrefs))) | ||
| 727 | |||
| 728 | (add-hook 'elisp-xref-find-def-functions 'xref-mode-local-overload) | ||
| 729 | |||
| 730 | (defconst xref-mode-local-find-overloadable-regexp | ||
| 731 | "(\\(\\(define-overloadable-function\\)\\|\\(define-overload\\)\\) +%s" | ||
| 732 | "Regexp used by ‘xref-find-definitions’ when searching for a | ||
| 733 | mode-local overloadable function definition.") | ||
| 734 | |||
| 735 | (defun xref-mode-local-find-override (meta-name) | ||
| 736 | "Function used by ‘xref-find-definitions’ when searching for an | ||
| 737 | override of a mode-local overloadable function. | ||
| 738 | META-NAME is a cons (OVERLOADABLE-SYMBOL . MAJOR-MODE)." | ||
| 739 | (let* ((override (car meta-name)) | ||
| 740 | (mode (cdr meta-name)) | ||
| 741 | (regexp (format "(define-mode-local-override +%s +%s" | ||
| 742 | (substring (symbol-name override) 0 (- (1+ (length (symbol-name mode))))) | ||
| 743 | mode))) | ||
| 744 | (re-search-forward regexp nil t) | ||
| 745 | )) | ||
| 746 | |||
| 747 | (add-to-list 'find-function-regexp-alist '(define-overloadable-function . xref-mode-local-find-overloadable-regexp)) | ||
| 748 | (add-to-list 'find-function-regexp-alist (cons 'define-mode-local-override #'xref-mode-local-find-override)) | ||
| 749 | |||
| 652 | ;; Help for mode-local bindings. | 750 | ;; Help for mode-local bindings. |
| 653 | (defun mode-local-print-binding (symbol) | 751 | (defun mode-local-print-binding (symbol) |
| 654 | "Print the SYMBOL binding." | 752 | "Print the SYMBOL binding." |
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index a96fca15cc2..e76728d0461 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el | |||
| @@ -620,7 +620,7 @@ It can be quoted, or be inside a quoted form." | |||
| 620 | (put-text-property 4 6 'face 'font-lock-function-name-face str) | 620 | (put-text-property 4 6 'face 'font-lock-function-name-face str) |
| 621 | str)) | 621 | str)) |
| 622 | 622 | ||
| 623 | (defvar find-feature-regexp) | 623 | (defvar find-feature-regexp);; in find-func.el |
| 624 | 624 | ||
| 625 | (defun elisp--xref-make-xref (type symbol file &optional summary) | 625 | (defun elisp--xref-make-xref (type symbol file &optional summary) |
| 626 | "Return an xref for TYPE SYMBOL in FILE. | 626 | "Return an xref for TYPE SYMBOL in FILE. |
| @@ -631,149 +631,167 @@ otherwise build the summary from TYPE and SYMBOL." | |||
| 631 | (format elisp--xref-format (or type 'defun) symbol)) | 631 | (format elisp--xref-format (or type 'defun) symbol)) |
| 632 | (xref-make-elisp-location symbol type file))) | 632 | (xref-make-elisp-location symbol type file))) |
| 633 | 633 | ||
| 634 | (defvar elisp-xref-find-def-functions nil | ||
| 635 | "List of functions to be run from ‘elisp--xref-find-definitions’ to add additional xrefs. | ||
| 636 | Called with one arg; the symbol whose definition is desired. | ||
| 637 | Each function should return a list of xrefs, or nil; the first | ||
| 638 | non-nil result supercedes the xrefs produced by | ||
| 639 | ‘elisp--xref-find-definitions’.") | ||
| 640 | |||
| 641 | ;; FIXME: name should be singular; match xref-find-definition | ||
| 634 | (defun elisp--xref-find-definitions (symbol) | 642 | (defun elisp--xref-find-definitions (symbol) |
| 635 | ;; The file name is not known when `symbol' is defined via interactive eval. | 643 | ;; The file name is not known when `symbol' is defined via interactive eval. |
| 636 | (let (xrefs) | 644 | (let (xrefs temp) |
| 637 | ;; alphabetical by result type symbol | 645 | |
| 638 | 646 | (let ((temp elisp-xref-find-def-functions)) | |
| 639 | ;; FIXME: advised function; list of advice functions | 647 | (while (and (null xrefs) |
| 640 | 648 | temp) | |
| 641 | ;; FIXME: aliased variable | 649 | (setq xrefs (append xrefs (funcall (pop temp) symbol))))) |
| 642 | 650 | ||
| 643 | (when (and (symbolp symbol) | 651 | (unless xrefs |
| 644 | (symbol-function symbol) | 652 | ;; alphabetical by result type symbol |
| 645 | (symbolp (symbol-function symbol))) | 653 | |
| 646 | ;; aliased function | 654 | ;; FIXME: advised function; list of advice functions |
| 647 | (let* ((alias-symbol symbol) | 655 | |
| 648 | (alias-file (symbol-file alias-symbol)) | 656 | ;; FIXME: aliased variable |
| 649 | (real-symbol (symbol-function symbol)) | 657 | |
| 650 | (real-file (find-lisp-object-file-name real-symbol 'defun))) | 658 | (when (and (symbolp symbol) |
| 651 | 659 | (symbol-function symbol) | |
| 652 | (when real-file | 660 | (symbolp (symbol-function symbol))) |
| 653 | (push (elisp--xref-make-xref nil real-symbol real-file) xrefs)) | 661 | ;; aliased function |
| 654 | 662 | (let* ((alias-symbol symbol) | |
| 655 | (when alias-file | 663 | (alias-file (symbol-file alias-symbol)) |
| 656 | (push (elisp--xref-make-xref 'defalias alias-symbol alias-file) xrefs)))) | 664 | (real-symbol (symbol-function symbol)) |
| 657 | 665 | (real-file (find-lisp-object-file-name real-symbol 'defun))) | |
| 658 | (when (facep symbol) | 666 | |
| 659 | (let ((file (find-lisp-object-file-name symbol 'defface))) | 667 | (when real-file |
| 660 | (when file | 668 | (push (elisp--xref-make-xref nil real-symbol real-file) xrefs)) |
| 661 | (push (elisp--xref-make-xref 'defface symbol file) xrefs)))) | 669 | |
| 662 | 670 | (when alias-file | |
| 663 | (when (fboundp symbol) | 671 | (push (elisp--xref-make-xref 'defalias alias-symbol alias-file) xrefs)))) |
| 664 | (let ((file (find-lisp-object-file-name symbol (symbol-function symbol))) | 672 | |
| 665 | generic doc) | 673 | (when (facep symbol) |
| 666 | (when file | 674 | (let ((file (find-lisp-object-file-name symbol 'defface))) |
| 667 | (cond | 675 | (when file |
| 668 | ((eq file 'C-source) | 676 | (push (elisp--xref-make-xref 'defface symbol file) xrefs)))) |
| 669 | ;; First call to find-lisp-object-file-name for an object | 677 | |
| 670 | ;; defined in C; the doc strings from the C source have | 678 | (when (fboundp symbol) |
| 671 | ;; not been loaded yet. Second call will return "src/*.c" | 679 | (let ((file (find-lisp-object-file-name symbol (symbol-function symbol))) |
| 672 | ;; in file; handled by 't' case below. | 680 | generic doc) |
| 673 | (push (elisp--xref-make-xref nil symbol (help-C-file-name (symbol-function symbol) 'subr)) xrefs)) | 681 | (when file |
| 674 | 682 | (cond | |
| 675 | ((and (setq doc (documentation symbol t)) | 683 | ((eq file 'C-source) |
| 676 | ;; This doc string is defined in cl-macs.el cl-defstruct | 684 | ;; First call to find-lisp-object-file-name for an object |
| 677 | (string-match "Constructor for objects of type `\\(.*\\)'" doc)) | 685 | ;; defined in C; the doc strings from the C source have |
| 678 | ;; `symbol' is a name for the default constructor created by | 686 | ;; not been loaded yet. Second call will return "src/*.c" |
| 679 | ;; cl-defstruct, so return the location of the cl-defstruct. | 687 | ;; in file; handled by 't' case below. |
| 680 | (let* ((type-name (match-string 1 doc)) | 688 | (push (elisp--xref-make-xref nil symbol (help-C-file-name (symbol-function symbol) 'subr)) xrefs)) |
| 681 | (type-symbol (intern type-name)) | 689 | |
| 682 | (file (find-lisp-object-file-name type-symbol 'define-type)) | 690 | ((and (setq doc (documentation symbol t)) |
| 683 | (summary (format elisp--xref-format-extra | 691 | ;; This doc string is defined in cl-macs.el cl-defstruct |
| 684 | 'cl-defstruct | 692 | (string-match "Constructor for objects of type `\\(.*\\)'" doc)) |
| 685 | (concat "(" type-name) | 693 | ;; `symbol' is a name for the default constructor created by |
| 686 | (concat "(:constructor " (symbol-name symbol) "))")))) | 694 | ;; cl-defstruct, so return the location of the cl-defstruct. |
| 687 | (push (elisp--xref-make-xref 'define-type type-symbol file summary) xrefs) | 695 | (let* ((type-name (match-string 1 doc)) |
| 688 | )) | 696 | (type-symbol (intern type-name)) |
| 689 | 697 | (file (find-lisp-object-file-name type-symbol 'define-type)) | |
| 690 | ((setq generic (cl--generic symbol)) | 698 | (summary (format elisp--xref-format-extra |
| 691 | ;; A generic function. If there is a default method, it | 699 | 'cl-defstruct |
| 692 | ;; will appear in the method table, with no | 700 | (concat "(" type-name) |
| 693 | ;; specializers. | 701 | (concat "(:constructor " (symbol-name symbol) "))")))) |
| 694 | ;; | 702 | (push (elisp--xref-make-xref 'define-type type-symbol file summary) xrefs) |
| 695 | ;; If the default method is declared by the cl-defgeneric | 703 | )) |
| 696 | ;; declaration, it will have the same location as the | 704 | |
| 697 | ;; cl-defgeneric, so we want to exclude it from the | 705 | ((setq generic (cl--generic symbol)) |
| 698 | ;; result. In this case, it will have a null doc | 706 | ;; FIXME: move this to elisp-xref-find-def-functions, in cl-generic.el |
| 699 | ;; string. User declarations of default methods may also | 707 | |
| 700 | ;; have null doc strings, but we hope that is | 708 | ;; A generic function. If there is a default method, it |
| 701 | ;; rare. Perhaps this heuristic will discourage that. | 709 | ;; will appear in the method table, with no |
| 702 | (dolist (method (cl--generic-method-table generic)) | 710 | ;; specializers. |
| 703 | (let* ((info (cl--generic-method-info method));; qual-string combined-args doconly | 711 | ;; |
| 704 | (specializers (cl--generic-method-specializers method)) | 712 | ;; If the default method is declared by the cl-defgeneric |
| 705 | (met-name (cons symbol specializers)) | 713 | ;; declaration, it will have the same location as the |
| 706 | (file (find-lisp-object-file-name met-name 'cl-defmethod))) | 714 | ;; cl-defgeneric, so we want to exclude it from the |
| 707 | (when (and file | 715 | ;; result. In this case, it will have a null doc |
| 708 | (or specializers ;; default method has null specializers | 716 | ;; string. User declarations of default methods may also |
| 709 | (nth 2 info))) ;; assuming only co-located default has null doc string | 717 | ;; have null doc strings, but we hope that is |
| 710 | (if specializers | 718 | ;; rare. Perhaps this heuristic will discourage that. |
| 711 | (let ((summary (format elisp--xref-format-extra 'cl-defmethod symbol (nth 1 info)))) | 719 | (dolist (method (cl--generic-method-table generic)) |
| 712 | (push (elisp--xref-make-xref 'cl-defmethod met-name file summary) xrefs)) | 720 | (let* ((info (cl--generic-method-info method));; qual-string combined-args doconly |
| 713 | 721 | (specializers (cl--generic-method-specializers method)) | |
| 714 | (let ((summary (format elisp--xref-format-extra 'cl-defmethod symbol "()"))) | 722 | (met-name (cons symbol specializers)) |
| 715 | (push (elisp--xref-make-xref 'cl-defmethod met-name file summary) xrefs)))) | 723 | (file (find-lisp-object-file-name met-name 'cl-defmethod))) |
| 716 | )) | 724 | (when (and file |
| 717 | 725 | (or specializers ;; default method has null specializers | |
| 718 | (if (and (setq doc (documentation symbol t)) | 726 | (nth 2 info))) ;; assuming only co-located default has null doc string |
| 719 | ;; This doc string is created somewhere in | 727 | (if specializers |
| 720 | ;; cl--generic-make-function for an implicit | 728 | (let ((summary (format elisp--xref-format-extra 'cl-defmethod symbol (nth 1 info)))) |
| 721 | ;; defgeneric. | 729 | (push (elisp--xref-make-xref 'cl-defmethod met-name file summary) xrefs)) |
| 722 | (string-match "\n\n(fn ARG &rest ARGS)" doc)) | 730 | |
| 723 | ;; This symbol is an implicitly defined defgeneric, so | 731 | (let ((summary (format elisp--xref-format-extra 'cl-defmethod symbol "()"))) |
| 724 | ;; don't return it. | 732 | (push (elisp--xref-make-xref 'cl-defmethod met-name file summary) xrefs)))) |
| 725 | nil | 733 | )) |
| 726 | (push (elisp--xref-make-xref 'cl-defgeneric symbol file) xrefs)) | 734 | |
| 727 | ) | 735 | (if (and (setq doc (documentation symbol t)) |
| 728 | 736 | ;; This doc string is created somewhere in | |
| 729 | (t | 737 | ;; cl--generic-make-function for an implicit |
| 730 | (push (elisp--xref-make-xref nil symbol file) xrefs)) | 738 | ;; defgeneric. |
| 731 | )))) | 739 | (string-match "\n\n(fn ARG &rest ARGS)" doc)) |
| 732 | 740 | ;; This symbol is an implicitly defined defgeneric, so | |
| 733 | (when (boundp symbol) | 741 | ;; don't return it. |
| 734 | ;; A variable | 742 | nil |
| 735 | (let ((file (find-lisp-object-file-name symbol 'defvar))) | 743 | (push (elisp--xref-make-xref 'cl-defgeneric symbol file) xrefs)) |
| 736 | (when file | 744 | ) |
| 737 | (cond | 745 | |
| 738 | ((eq file 'C-source) | 746 | (t |
| 739 | ;; The doc strings from the C source have not been loaded | 747 | (push (elisp--xref-make-xref nil symbol file) xrefs)) |
| 740 | ;; yet; help-C-file-name does that. Second call will | 748 | )))) |
| 741 | ;; return "src/*.c" in file; handled below. | 749 | |
| 742 | (push (elisp--xref-make-xref 'defvar symbol (help-C-file-name symbol 'var)) xrefs)) | 750 | (when (boundp symbol) |
| 743 | 751 | ;; A variable | |
| 744 | ((string= "src/" (substring file 0 4)) | 752 | (let ((file (find-lisp-object-file-name symbol 'defvar))) |
| 745 | ;; The variable is defined in a C source file; don't check | 753 | (when file |
| 746 | ;; for define-minor-mode. | 754 | (cond |
| 747 | (push (elisp--xref-make-xref 'defvar symbol file) xrefs)) | 755 | ((eq file 'C-source) |
| 748 | 756 | ;; The doc strings from the C source have not been loaded | |
| 749 | ((memq symbol minor-mode-list) | 757 | ;; yet; help-C-file-name does that. Second call will |
| 750 | ;; The symbol is a minor mode. These should be defined by | 758 | ;; return "src/*.c" in file; handled below. |
| 751 | ;; "define-minor-mode", which means the variable and the | 759 | (push (elisp--xref-make-xref 'defvar symbol (help-C-file-name symbol 'var)) xrefs)) |
| 752 | ;; function are declared in the same place. So we return only | 760 | |
| 753 | ;; the function, arbitrarily. | 761 | ((string= "src/" (substring file 0 4)) |
| 754 | ;; | 762 | ;; The variable is defined in a C source file; don't check |
| 755 | ;; There is an exception, when the variable is defined in C | 763 | ;; for define-minor-mode. |
| 756 | ;; code, as for abbrev-mode. | 764 | (push (elisp--xref-make-xref 'defvar symbol file) xrefs)) |
| 757 | ;; | 765 | |
| 758 | ;; IMPROVEME: If the user is searching for the identifier at | 766 | ((memq symbol minor-mode-list) |
| 759 | ;; point, we can determine whether it is a variable or | 767 | ;; The symbol is a minor mode. These should be defined by |
| 760 | ;; function by looking at the source code near point. | 768 | ;; "define-minor-mode", which means the variable and the |
| 761 | ;; | 769 | ;; function are declared in the same place. So we return only |
| 762 | ;; IMPROVEME: The user may actually be asking "do any | 770 | ;; the function, arbitrarily. |
| 763 | ;; variables by this name exist"; we need a way to specify | 771 | ;; |
| 764 | ;; that. | 772 | ;; There is an exception, when the variable is defined in C |
| 765 | nil) | 773 | ;; code, as for abbrev-mode. |
| 766 | 774 | ;; | |
| 767 | (t | 775 | ;; IMPROVEME: If the user is searching for the identifier at |
| 768 | (push (elisp--xref-make-xref 'defvar symbol file) xrefs)) | 776 | ;; point, we can determine whether it is a variable or |
| 769 | 777 | ;; function by looking at the source code near point. | |
| 770 | )))) | 778 | ;; |
| 771 | 779 | ;; IMPROVEME: The user may actually be asking "do any | |
| 772 | (when (featurep symbol) | 780 | ;; variables by this name exist"; we need a way to specify |
| 773 | (let ((file (ignore-errors | 781 | ;; that. |
| 774 | (find-library-name (symbol-name symbol))))) | 782 | nil) |
| 775 | (when file | 783 | |
| 776 | (push (elisp--xref-make-xref 'feature symbol file) xrefs)))) | 784 | (t |
| 785 | (push (elisp--xref-make-xref 'defvar symbol file) xrefs)) | ||
| 786 | |||
| 787 | )))) | ||
| 788 | |||
| 789 | (when (featurep symbol) | ||
| 790 | (let ((file (ignore-errors | ||
| 791 | (find-library-name (symbol-name symbol))))) | ||
| 792 | (when file | ||
| 793 | (push (elisp--xref-make-xref 'feature symbol file) xrefs)))) | ||
| 794 | );; 'unless xrefs' | ||
| 777 | 795 | ||
| 778 | xrefs)) | 796 | xrefs)) |
| 779 | 797 | ||
diff --git a/test/automated/elisp-mode-tests.el b/test/automated/elisp-mode-tests.el index 64b3f665a03..ec01477984c 100644 --- a/test/automated/elisp-mode-tests.el +++ b/test/automated/elisp-mode-tests.el | |||
| @@ -186,6 +186,7 @@ | |||
| 186 | (or (when (consp expected) (car expected)) expected))) | 186 | (or (when (consp expected) (car expected)) expected))) |
| 187 | 187 | ||
| 188 | (xref--goto-location (xref-item-location xref)) | 188 | (xref--goto-location (xref-item-location xref)) |
| 189 | (back-to-indentation) | ||
| 189 | (should (looking-at (or (when (consp expected) (cdr expected)) | 190 | (should (looking-at (or (when (consp expected) (cdr expected)) |
| 190 | (xref-elisp-test-descr-to-target expected))))) | 191 | (xref-elisp-test-descr-to-target expected))))) |
| 191 | )) | 192 | )) |
| @@ -258,50 +259,55 @@ to (xref-elisp-test-descr-to-target xref)." | |||
| 258 | slot-1) | 259 | slot-1) |
| 259 | 260 | ||
| 260 | (cl-defgeneric xref-elisp-generic-no-methods () | 261 | (cl-defgeneric xref-elisp-generic-no-methods () |
| 261 | "doc string no-methods" | 262 | "doc string generic no-methods" |
| 262 | ;; No default implementation, no methods, but fboundp is true for | 263 | ;; No default implementation, no methods, but fboundp is true for |
| 263 | ;; this symbol; it calls cl-no-applicable-method | 264 | ;; this symbol; it calls cl-no-applicable-method |
| 264 | ) | 265 | ) |
| 265 | 266 | ||
| 267 | ;; WORKAROUND: ‘this’ is unused, and the byte compiler complains, so | ||
| 268 | ;; it should be spelled ‘_this’. But for some unknown reason, that | ||
| 269 | ;; causes the batch mode test to fail; the symbol shows up as | ||
| 270 | ;; ‘this’. It passes in interactive tests, so I haven't been able to | ||
| 271 | ;; track down the problem. | ||
| 266 | (cl-defmethod xref-elisp-generic-no-default ((this xref-elisp-root-type)) | 272 | (cl-defmethod xref-elisp-generic-no-default ((this xref-elisp-root-type)) |
| 267 | "doc string no-default xref-elisp-root-type" | 273 | "doc string generic no-default xref-elisp-root-type" |
| 268 | "non-default for no-default") | 274 | "non-default for no-default") |
| 269 | 275 | ||
| 270 | ;; defgeneric after defmethod in file to ensure the fallback search | 276 | ;; defgeneric after defmethod in file to ensure the fallback search |
| 271 | ;; method of just looking for the function name will fail. | 277 | ;; method of just looking for the function name will fail. |
| 272 | (cl-defgeneric xref-elisp-generic-no-default () | 278 | (cl-defgeneric xref-elisp-generic-no-default () |
| 273 | "doc string no-default generic" | 279 | "doc string generic no-default generic" |
| 274 | ;; No default implementation; this function calls the cl-generic | 280 | ;; No default implementation; this function calls the cl-generic |
| 275 | ;; dispatching code. | 281 | ;; dispatching code. |
| 276 | ) | 282 | ) |
| 277 | 283 | ||
| 278 | (cl-defgeneric xref-elisp-generic-co-located-default () | 284 | (cl-defgeneric xref-elisp-generic-co-located-default () |
| 279 | "doc string co-located-default generic" | 285 | "doc string generic co-located-default" |
| 280 | "co-located default") | 286 | "co-located default") |
| 281 | 287 | ||
| 282 | (cl-defmethod xref-elisp-generic-co-located-default ((this xref-elisp-root-type)) | 288 | (cl-defmethod xref-elisp-generic-co-located-default ((this xref-elisp-root-type)) |
| 283 | "doc string co-located-default xref-elisp-root-type" | 289 | "doc string generic co-located-default xref-elisp-root-type" |
| 284 | "non-default for co-located-default") | 290 | "non-default for co-located-default") |
| 285 | 291 | ||
| 286 | (cl-defgeneric xref-elisp-generic-separate-default () | 292 | (cl-defgeneric xref-elisp-generic-separate-default () |
| 287 | "doc string separate-default generic" | 293 | "doc string generic separate-default" |
| 288 | ;; default implementation provided separately | 294 | ;; default implementation provided separately |
| 289 | ) | 295 | ) |
| 290 | 296 | ||
| 291 | (cl-defmethod xref-elisp-generic-separate-default () | 297 | (cl-defmethod xref-elisp-generic-separate-default () |
| 292 | "doc string separate-default default" | 298 | "doc string generic separate-default default" |
| 293 | "separate default") | 299 | "separate default") |
| 294 | 300 | ||
| 295 | (cl-defmethod xref-elisp-generic-separate-default ((this xref-elisp-root-type)) | 301 | (cl-defmethod xref-elisp-generic-separate-default ((this xref-elisp-root-type)) |
| 296 | "doc string separate-default xref-elisp-root-type" | 302 | "doc string generic separate-default xref-elisp-root-type" |
| 297 | "non-default for separate-default") | 303 | "non-default for separate-default") |
| 298 | 304 | ||
| 299 | (cl-defmethod xref-elisp-generic-implicit-generic () | 305 | (cl-defmethod xref-elisp-generic-implicit-generic () |
| 300 | "doc string implicit-generic default" | 306 | "doc string generic implicit-generic default" |
| 301 | "default for implicit generic") | 307 | "default for implicit generic") |
| 302 | 308 | ||
| 303 | (cl-defmethod xref-elisp-generic-implicit-generic ((this xref-elisp-root-type)) | 309 | (cl-defmethod xref-elisp-generic-implicit-generic ((this xref-elisp-root-type)) |
| 304 | "doc string implicit-generic xref-elisp-root-type" | 310 | "doc string generic implicit-generic xref-elisp-root-type" |
| 305 | "non-default for implicit generic") | 311 | "non-default for implicit generic") |
| 306 | 312 | ||
| 307 | 313 | ||
| @@ -351,7 +357,6 @@ to (xref-elisp-test-descr-to-target xref)." | |||
| 351 | (xref-make-elisp-location | 357 | (xref-make-elisp-location |
| 352 | '(xref-elisp-generic-separate-default) 'cl-defmethod | 358 | '(xref-elisp-generic-separate-default) 'cl-defmethod |
| 353 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) | 359 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) |
| 354 | |||
| 355 | (xref-make "(cl-defmethod xref-elisp-generic-separate-default ((this xref-elisp-root-type)))" | 360 | (xref-make "(cl-defmethod xref-elisp-generic-separate-default ((this xref-elisp-root-type)))" |
| 356 | (xref-make-elisp-location | 361 | (xref-make-elisp-location |
| 357 | '(xref-elisp-generic-separate-default xref-elisp-root-type) 'cl-defmethod | 362 | '(xref-elisp-generic-separate-default xref-elisp-root-type) 'cl-defmethod |
| @@ -410,6 +415,95 @@ to (xref-elisp-test-descr-to-target xref)." | |||
| 410 | (elisp--xref-find-definitions (eval '(cl-defgeneric stephe-leake-cl-defgeneric ()))) | 415 | (elisp--xref-find-definitions (eval '(cl-defgeneric stephe-leake-cl-defgeneric ()))) |
| 411 | nil) | 416 | nil) |
| 412 | 417 | ||
| 418 | ;; Define some mode-local overloadable/overridden functions for xref to find | ||
| 419 | (require 'mode-local) | ||
| 420 | |||
| 421 | (define-overloadable-function xref-elisp-overloadable-no-methods () | ||
| 422 | "doc string overloadable no-methods") | ||
| 423 | |||
| 424 | (define-overloadable-function xref-elisp-overloadable-no-default () | ||
| 425 | "doc string overloadable no-default") | ||
| 426 | |||
| 427 | ;; FIXME: byte compiler complains about unused lexical arguments | ||
| 428 | ;; generated by this macro. | ||
| 429 | (define-mode-local-override xref-elisp-overloadable-no-default c-mode | ||
| 430 | (start end &optional nonterminal depth returnonerror) | ||
| 431 | "doc string overloadable no-default c-mode." | ||
| 432 | "result overloadable no-default c-mode.") | ||
| 433 | |||
| 434 | (define-overloadable-function xref-elisp-overloadable-co-located-default () | ||
| 435 | "doc string overloadable co-located-default" | ||
| 436 | "result overloadable co-located-default.") | ||
| 437 | |||
| 438 | (define-mode-local-override xref-elisp-overloadable-co-located-default c-mode | ||
| 439 | (start end &optional nonterminal depth returnonerror) | ||
| 440 | "doc string overloadable co-located-default c-mode." | ||
| 441 | "result overloadable co-located-default c-mode.") | ||
| 442 | |||
| 443 | (define-overloadable-function xref-elisp-overloadable-separate-default () | ||
| 444 | "doc string overloadable separate-default.") | ||
| 445 | |||
| 446 | (defun xref-elisp-overloadable-separate-default-default () | ||
| 447 | "doc string overloadable separate-default default" | ||
| 448 | "result overloadable separate-default.") | ||
| 449 | |||
| 450 | (define-mode-local-override xref-elisp-overloadable-separate-default c-mode | ||
| 451 | (start end &optional nonterminal depth returnonerror) | ||
| 452 | "doc string overloadable separate-default c-mode." | ||
| 453 | "result overloadable separate-default c-mode.") | ||
| 454 | |||
| 455 | (xref-elisp-deftest find-defs-define-overload-no-methods | ||
| 456 | (elisp--xref-find-definitions 'xref-elisp-overloadable-no-methods) | ||
| 457 | (list | ||
| 458 | (xref-make "(define-overloadable-function xref-elisp-overloadable-no-methods)" | ||
| 459 | (xref-make-elisp-location | ||
| 460 | 'xref-elisp-overloadable-no-methods 'define-overloadable-function | ||
| 461 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) | ||
| 462 | )) | ||
| 463 | |||
| 464 | (xref-elisp-deftest find-defs-define-overload-no-default | ||
| 465 | (elisp--xref-find-definitions 'xref-elisp-overloadable-no-default) | ||
| 466 | (list | ||
| 467 | (xref-make "(define-overloadable-function xref-elisp-overloadable-no-default)" | ||
| 468 | (xref-make-elisp-location | ||
| 469 | 'xref-elisp-overloadable-no-default 'define-overloadable-function | ||
| 470 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) | ||
| 471 | (xref-make "(define-mode-local-override xref-elisp-overloadable-no-default c-mode)" | ||
| 472 | (xref-make-elisp-location | ||
| 473 | '(xref-elisp-overloadable-no-default-c-mode . c-mode) 'define-mode-local-override | ||
| 474 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) | ||
| 475 | )) | ||
| 476 | |||
| 477 | (xref-elisp-deftest find-defs-define-overload-co-located-default | ||
| 478 | (elisp--xref-find-definitions 'xref-elisp-overloadable-co-located-default) | ||
| 479 | (list | ||
| 480 | (xref-make "(define-overloadable-function xref-elisp-overloadable-co-located-default)" | ||
| 481 | (xref-make-elisp-location | ||
| 482 | 'xref-elisp-overloadable-co-located-default 'define-overloadable-function | ||
| 483 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) | ||
| 484 | (xref-make "(define-mode-local-override xref-elisp-overloadable-co-located-default c-mode)" | ||
| 485 | (xref-make-elisp-location | ||
| 486 | '(xref-elisp-overloadable-co-located-default-c-mode . c-mode) 'define-mode-local-override | ||
| 487 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) | ||
| 488 | )) | ||
| 489 | |||
| 490 | (xref-elisp-deftest find-defs-define-overload-separate-default | ||
| 491 | (elisp--xref-find-definitions 'xref-elisp-overloadable-separate-default) | ||
| 492 | (list | ||
| 493 | (xref-make "(define-overloadable-function xref-elisp-overloadable-separate-default)" | ||
| 494 | (xref-make-elisp-location | ||
| 495 | 'xref-elisp-overloadable-separate-default 'define-overloadable-function | ||
| 496 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) | ||
| 497 | (xref-make "(defun xref-elisp-overloadable-separate-default-default)" | ||
| 498 | (xref-make-elisp-location | ||
| 499 | 'xref-elisp-overloadable-separate-default-default nil | ||
| 500 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) | ||
| 501 | (xref-make "(define-mode-local-override xref-elisp-overloadable-separate-default c-mode)" | ||
| 502 | (xref-make-elisp-location | ||
| 503 | '(xref-elisp-overloadable-separate-default-c-mode . c-mode) 'define-mode-local-override | ||
| 504 | (expand-file-name "elisp-mode-tests.el" emacs-test-dir))) | ||
| 505 | )) | ||
| 506 | |||
| 413 | (xref-elisp-deftest find-defs-defun-el | 507 | (xref-elisp-deftest find-defs-defun-el |
| 414 | (elisp--xref-find-definitions 'xref-find-definitions) | 508 | (elisp--xref-find-definitions 'xref-find-definitions) |
| 415 | (list | 509 | (list |