diff options
| author | Stephen Leake | 2015-08-13 12:54:39 -0500 |
|---|---|---|
| committer | Stephen Leake | 2015-08-13 13:16:47 -0500 |
| commit | 0382fd42c6979bbedc9230b789503258a5e963eb (patch) | |
| tree | 989b157edeb659f5e0b2b3e8b884ec143dcbe3fd /lisp | |
| parent | 9c13a81a9e1aa74901cd958d7adb3ca71966dbef (diff) | |
| download | emacs-0382fd42c6979bbedc9230b789503258a5e963eb.tar.gz emacs-0382fd42c6979bbedc9230b789503258a5e963eb.zip | |
xref-find-definitions: Exclude more generic function items.
* lisp/emacs-lisp/cl-generic.el (cl--generic-search-method): Add doc string.
(cl--generic-find-defgeneric-regexp): New.
(find-function-regexp-alist): Add it.
* lisp/emacs-lisp/find-func.el (find-feature-regexp): Move here from
elisp-mode.el, change to search for ";;; Code:"
(find-alias-regexp): Move here from elisp-mode.el, cleaned up.
(find-function-regexp-alist): Add them.
* lisp/progmodes/elisp-mode.el:
(elisp--xref-format, elisp--xref-format-extra): Change back to defvar due
to bug#21237.
(elisp--xref-find-definitions): Exclude co-located default methods for
generic functions. Also exclude implicitly declared defgeneric.
(elisp--xref-find-definitions): Handle C source properly. Exclude minor
mode variables defined by 'define-minor-mode'.
* test/automated/elisp-mode-tests.el: Declare generic functions, add
tests for them.
(xref-elisp-test-run): Fix bug.
(emacs-test-dir): Improve initial value.
(find-defs-defun-defvar-el): Don't expect defvar.
(find-defs-feature-el): Match change to find-feature-regexp.
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/emacs-lisp/cl-generic.el | 8 | ||||
| -rw-r--r-- | lisp/emacs-lisp/find-func.el | 26 | ||||
| -rw-r--r-- | lisp/progmodes/elisp-mode.el | 115 |
3 files changed, 110 insertions, 39 deletions
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index 63cd9108410..a138697a18b 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el | |||
| @@ -791,6 +791,8 @@ Can only be used from within the lexical body of a primary or around method." | |||
| 791 | ;;; Add support for describe-function | 791 | ;;; Add support for describe-function |
| 792 | 792 | ||
| 793 | (defun cl--generic-search-method (met-name) | 793 | (defun cl--generic-search-method (met-name) |
| 794 | "For `find-function-regexp-alist'. Searches for a cl-defmethod. | ||
| 795 | MET-NAME is a cons (SYMBOL . SPECIALIZERS)." | ||
| 794 | (let ((base-re (concat "(\\(?:cl-\\)?defmethod[ \t]+" | 796 | (let ((base-re (concat "(\\(?:cl-\\)?defmethod[ \t]+" |
| 795 | (regexp-quote (format "%s" (car met-name))) | 797 | (regexp-quote (format "%s" (car met-name))) |
| 796 | "\\_>"))) | 798 | "\\_>"))) |
| @@ -806,11 +808,15 @@ Can only be used from within the lexical body of a primary or around method." | |||
| 806 | nil t) | 808 | nil t) |
| 807 | (re-search-forward base-re nil t)))) | 809 | (re-search-forward base-re nil t)))) |
| 808 | 810 | ||
| 811 | ;; WORKAROUND: This can't be a defconst due to bug#21237. | ||
| 812 | (defvar cl--generic-find-defgeneric-regexp "(\\(?:cl-\\)?defgeneric[ \t]+%s\\>") | ||
| 809 | 813 | ||
| 810 | (with-eval-after-load 'find-func | 814 | (with-eval-after-load 'find-func |
| 811 | (defvar find-function-regexp-alist) | 815 | (defvar find-function-regexp-alist) |
| 812 | (add-to-list 'find-function-regexp-alist | 816 | (add-to-list 'find-function-regexp-alist |
| 813 | `(cl-defmethod . ,#'cl--generic-search-method))) | 817 | `(cl-defmethod . ,#'cl--generic-search-method)) |
| 818 | (add-to-list 'find-function-regexp-alist | ||
| 819 | `(cl-defgeneric . cl--generic-find-defgeneric-regexp))) | ||
| 814 | 820 | ||
| 815 | (defun cl--generic-method-info (method) | 821 | (defun cl--generic-method-info (method) |
| 816 | (let* ((specializers (cl--generic-method-specializers method)) | 822 | (let* ((specializers (cl--generic-method-specializers method)) |
diff --git a/lisp/emacs-lisp/find-func.el b/lisp/emacs-lisp/find-func.el index cd23cd77f4a..4dc0596de66 100644 --- a/lisp/emacs-lisp/find-func.el +++ b/lisp/emacs-lisp/find-func.el | |||
| @@ -100,10 +100,34 @@ Please send improvements and fixes to the maintainer." | |||
| 100 | :group 'find-function | 100 | :group 'find-function |
| 101 | :version "22.1") | 101 | :version "22.1") |
| 102 | 102 | ||
| 103 | (defcustom find-feature-regexp | ||
| 104 | (concat ";;; Code:") | ||
| 105 | "The regexp used by `xref-find-definitions' when searching for a feature definition. | ||
| 106 | Note it must contain a `%s' at the place where `format' | ||
| 107 | should insert the feature name." | ||
| 108 | ;; We search for ";;; Code" rather than (feature '%s) because the | ||
| 109 | ;; former is near the start of the code, and the latter is very | ||
| 110 | ;; uninteresting. If the regexp is not found, just goes to | ||
| 111 | ;; (point-min), which is acceptable in this case. | ||
| 112 | :type 'regexp | ||
| 113 | :group 'xref | ||
| 114 | :version "25.0") | ||
| 115 | |||
| 116 | (defcustom find-alias-regexp | ||
| 117 | "(defalias +'%s" | ||
| 118 | "The regexp used by `xref-find-definitions' to search for an alias definition. | ||
| 119 | Note it must contain a `%s' at the place where `format' | ||
| 120 | should insert the feature name." | ||
| 121 | :type 'regexp | ||
| 122 | :group 'xref | ||
| 123 | :version "25.0") | ||
| 124 | |||
| 103 | (defvar find-function-regexp-alist | 125 | (defvar find-function-regexp-alist |
| 104 | '((nil . find-function-regexp) | 126 | '((nil . find-function-regexp) |
| 105 | (defvar . find-variable-regexp) | 127 | (defvar . find-variable-regexp) |
| 106 | (defface . find-face-regexp)) | 128 | (defface . find-face-regexp) |
| 129 | (feature . find-feature-regexp) | ||
| 130 | (defalias . find-alias-regexp)) | ||
| 107 | "Alist mapping definition types into regexp variables. | 131 | "Alist mapping definition types into regexp variables. |
| 108 | Each regexp variable's value should actually be a format string | 132 | Each regexp variable's value should actually be a format string |
| 109 | to be used to substitute the desired symbol name into the regexp. | 133 | to be used to substitute the desired symbol name into the regexp. |
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index 7ac5a5cb778..81314574672 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el | |||
| @@ -604,40 +604,23 @@ It can be quoted, or be inside a quoted form." | |||
| 604 | (`apropos | 604 | (`apropos |
| 605 | (elisp--xref-find-apropos id)))) | 605 | (elisp--xref-find-apropos id)))) |
| 606 | 606 | ||
| 607 | (defconst elisp--xref-format | 607 | ;; WORKAROUND: This is nominally a constant, but the text properities |
| 608 | ;; are not preserved thru dump if use defconst. See bug#21237 | ||
| 609 | (defvar elisp--xref-format | ||
| 608 | (let ((str "(%s %s)")) | 610 | (let ((str "(%s %s)")) |
| 609 | (put-text-property 1 3 'face 'font-lock-keyword-face str) | 611 | (put-text-property 1 3 'face 'font-lock-keyword-face str) |
| 610 | (put-text-property 4 6 'face 'font-lock-function-name-face str) | 612 | (put-text-property 4 6 'face 'font-lock-function-name-face str) |
| 611 | str)) | 613 | str)) |
| 612 | 614 | ||
| 613 | (defconst elisp--xref-format-extra | 615 | ;; WORKAROUND: This is nominally a constant, but the text properities |
| 616 | ;; are not preserved thru dump if use defconst. See bug#21237 | ||
| 617 | (defvar elisp--xref-format-extra | ||
| 614 | (let ((str "(%s %s %s)")) | 618 | (let ((str "(%s %s %s)")) |
| 615 | (put-text-property 1 3 'face 'font-lock-keyword-face str) | 619 | (put-text-property 1 3 'face 'font-lock-keyword-face str) |
| 616 | (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) |
| 617 | str)) | 621 | str)) |
| 618 | 622 | ||
| 619 | (defcustom find-feature-regexp | 623 | (defvar find-feature-regexp) |
| 620 | (concat "(provide +'%s)") | ||
| 621 | "The regexp used by `xref-find-definitions' to search for a feature definition. | ||
| 622 | Note it must contain a `%s' at the place where `format' | ||
| 623 | should insert the feature name." | ||
| 624 | :type 'regexp | ||
| 625 | :group 'xref | ||
| 626 | :version "25.0") | ||
| 627 | |||
| 628 | (defcustom find-alias-regexp | ||
| 629 | "(\\(defalias +'\\|def\\(const\\|face\\) +\\)%s" | ||
| 630 | "The regexp used by `xref-find-definitions' to search for an alias definition. | ||
| 631 | Note it must contain a `%s' at the place where `format' | ||
| 632 | should insert the feature name." | ||
| 633 | :type 'regexp | ||
| 634 | :group 'xref | ||
| 635 | :version "25.0") | ||
| 636 | |||
| 637 | (with-eval-after-load 'find-func | ||
| 638 | (defvar find-function-regexp-alist) | ||
| 639 | (add-to-list 'find-function-regexp-alist (cons 'feature 'find-feature-regexp)) | ||
| 640 | (add-to-list 'find-function-regexp-alist (cons 'defalias 'find-alias-regexp))) | ||
| 641 | 624 | ||
| 642 | (defun elisp--xref-make-xref (type symbol file &optional summary) | 625 | (defun elisp--xref-make-xref (type symbol file &optional summary) |
| 643 | "Return an xref for TYPE SYMBOL in FILE. | 626 | "Return an xref for TYPE SYMBOL in FILE. |
| @@ -683,9 +666,10 @@ otherwise build the summary from TYPE and SYMBOL." | |||
| 683 | (when file | 666 | (when file |
| 684 | (cond | 667 | (cond |
| 685 | ((eq file 'C-source) | 668 | ((eq file 'C-source) |
| 686 | ;; First call to find-lisp-object-file-name (for this | 669 | ;; First call to find-lisp-object-file-name for an object |
| 687 | ;; symbol?); C-source has not been cached yet. | 670 | ;; defined in C; the doc strings from the C source have |
| 688 | ;; Second call will return "src/*.c" in file; handled by 't' case below. | 671 | ;; not been loaded yet. Second call will return "src/*.c" |
| 672 | ;; in file; handled by 't' case below. | ||
| 689 | (push (elisp--xref-make-xref nil symbol (help-C-file-name (symbol-function symbol) 'subr)) xrefs)) | 673 | (push (elisp--xref-make-xref nil symbol (help-C-file-name (symbol-function symbol) 'subr)) xrefs)) |
| 690 | 674 | ||
| 691 | ((and (setq doc (documentation symbol t)) | 675 | ((and (setq doc (documentation symbol t)) |
| @@ -704,17 +688,42 @@ otherwise build the summary from TYPE and SYMBOL." | |||
| 704 | )) | 688 | )) |
| 705 | 689 | ||
| 706 | ((setq generic (cl--generic symbol)) | 690 | ((setq generic (cl--generic symbol)) |
| 691 | ;; A generic function. If there is a default method, it | ||
| 692 | ;; will appear in the method table, with no | ||
| 693 | ;; specializers. | ||
| 694 | ;; | ||
| 695 | ;; If the default method is declared by the cl-defgeneric | ||
| 696 | ;; declaration, it will have the same location as teh | ||
| 697 | ;; cl-defgeneric, so we want to exclude it from the | ||
| 698 | ;; result. In this case, it will have a null doc | ||
| 699 | ;; string. User declarations of default methods may also | ||
| 700 | ;; have null doc strings, but we hope that is | ||
| 701 | ;; rare. Perhaps this hueristic will discourage that. | ||
| 707 | (dolist (method (cl--generic-method-table generic)) | 702 | (dolist (method (cl--generic-method-table generic)) |
| 708 | (let* ((info (cl--generic-method-info method)) | 703 | (let* ((info (cl--generic-method-info method));; qual-string combined-args doconly |
| 709 | (met-name (cons symbol (cl--generic-method-specializers method))) | 704 | (specializers (cl--generic-method-specializers method)) |
| 710 | (descr (format elisp--xref-format-extra 'cl-defmethod symbol (nth 1 info))) | 705 | (met-name (cons symbol specializers)) |
| 711 | (file (find-lisp-object-file-name met-name 'cl-defmethod))) | 706 | (file (find-lisp-object-file-name met-name 'cl-defmethod))) |
| 712 | (when file | 707 | (when (and file |
| 713 | (push (elisp--xref-make-xref 'cl-defmethod met-name file descr) xrefs)) | 708 | (or specializers ;; default method has null specializers |
| 709 | (nth 2 info))) ;; assuming only co-located default has null doc string | ||
| 710 | (if specializers | ||
| 711 | (let ((summary (format elisp--xref-format-extra 'cl-defmethod symbol (nth 1 info)))) | ||
| 712 | (push (elisp--xref-make-xref 'cl-defmethod met-name file summary) xrefs)) | ||
| 713 | |||
| 714 | (let ((summary (format elisp--xref-format-extra 'cl-defmethod symbol "()"))) | ||
| 715 | (push (elisp--xref-make-xref 'cl-defmethod met-name file summary) xrefs)))) | ||
| 714 | )) | 716 | )) |
| 715 | 717 | ||
| 716 | (let ((descr (format elisp--xref-format 'cl-defgeneric symbol))) | 718 | (if (and (setq doc (documentation symbol t)) |
| 717 | (push (elisp--xref-make-xref nil symbol file descr) xrefs)) | 719 | ;; This doc string is created somewhere in |
| 720 | ;; cl--generic-make-function for an implicit | ||
| 721 | ;; defgeneric. | ||
| 722 | (string-match "\n\n(fn ARG &rest ARGS)" doc)) | ||
| 723 | ;; This symbol is an implicitly defined defgeneric, so | ||
| 724 | ;; don't return it. | ||
| 725 | nil | ||
| 726 | (push (elisp--xref-make-xref 'cl-defgeneric symbol file) xrefs)) | ||
| 718 | ) | 727 | ) |
| 719 | 728 | ||
| 720 | (t | 729 | (t |
| @@ -722,11 +731,43 @@ otherwise build the summary from TYPE and SYMBOL." | |||
| 722 | )))) | 731 | )))) |
| 723 | 732 | ||
| 724 | (when (boundp symbol) | 733 | (when (boundp symbol) |
| 734 | ;; A variable | ||
| 725 | (let ((file (find-lisp-object-file-name symbol 'defvar))) | 735 | (let ((file (find-lisp-object-file-name symbol 'defvar))) |
| 726 | (when file | 736 | (when file |
| 727 | (when (eq file 'C-source) | 737 | (cond |
| 728 | (setq file (help-C-file-name symbol 'var))) | 738 | ((eq file 'C-source) |
| 729 | (push (elisp--xref-make-xref 'defvar symbol file) xrefs)))) | 739 | ;; The doc strings from the C source have not been loaded |
| 740 | ;; yet; help-C-file-name does that. Second call will | ||
| 741 | ;; return "src/*.c" in file; handled below. | ||
| 742 | (push (elisp--xref-make-xref 'defvar symbol (help-C-file-name symbol 'var)) xrefs)) | ||
| 743 | |||
| 744 | ((string= "src/" (substring file 0 4)) | ||
| 745 | ;; The variable is defined in a C source file; don't check | ||
| 746 | ;; for define-minor-mode. | ||
| 747 | (push (elisp--xref-make-xref 'defvar symbol file) xrefs)) | ||
| 748 | |||
| 749 | ((memq symbol minor-mode-list) | ||
| 750 | ;; The symbol is a minor mode. These should be defined by | ||
| 751 | ;; "define-minor-mode", which means the variable and the | ||
| 752 | ;; function are declared in the same place. So we return only | ||
| 753 | ;; the function, arbitrarily. | ||
| 754 | ;; | ||
| 755 | ;; There is an exception, when the variable is defined in C | ||
| 756 | ;; code, as for abbrev-mode. | ||
| 757 | ;; | ||
| 758 | ;; IMPROVEME: If the user is searching for the identifier at | ||
| 759 | ;; point, we can determine whether it is a variable or | ||
| 760 | ;; function by looking at the source code near point. | ||
| 761 | ;; | ||
| 762 | ;; IMPROVEME: The user may actually be asking "do any | ||
| 763 | ;; variables by this name exist"; we need a way to specify | ||
| 764 | ;; that. | ||
| 765 | nil) | ||
| 766 | |||
| 767 | (t | ||
| 768 | (push (elisp--xref-make-xref 'defvar symbol file) xrefs)) | ||
| 769 | |||
| 770 | )))) | ||
| 730 | 771 | ||
| 731 | (when (featurep symbol) | 772 | (when (featurep symbol) |
| 732 | (let ((file (ignore-errors | 773 | (let ((file (ignore-errors |