diff options
| author | Stephen Leake | 2015-08-10 21:53:19 -0500 |
|---|---|---|
| committer | Stephen Leake | 2015-08-10 21:55:37 -0500 |
| commit | d7df36e745a5ba480559b6c8b5ebc93a18fe9bd1 (patch) | |
| tree | 736918633a929b4f88e871509b699f9a00dcf398 | |
| parent | 21e1673be3738fb79bd92cf8bd003d86ac51130b (diff) | |
| download | emacs-d7df36e745a5ba480559b6c8b5ebc93a18fe9bd1.tar.gz emacs-d7df36e745a5ba480559b6c8b5ebc93a18fe9bd1.zip | |
Rewrite elisp--xref-find-definitions to handle many more cases; add tests.
* lisp/progmodes/elisp-mode.el (elisp--xref-identifier-location): deleted
(elisp--xref-format-cl-defmethod): new
(find-feature-regexp): new
(find-alias-regexp): new
(elisp--xref-make-xref): new
(elisp--xref-find-definitions): Rewrite using the above, handle many more
cases. Always output all available definitions.
(xref-location-marker): No need for special cases.
* test/automated/elisp-mode-tests.el: Add more tests of
elisp--xref-find-definitions, improve current tests.
| -rw-r--r-- | lisp/progmodes/elisp-mode.el | 168 | ||||
| -rw-r--r-- | test/automated/elisp-mode-tests.el | 298 |
2 files changed, 393 insertions, 73 deletions
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index b7ae3c756de..41ca57f668d 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | ;;; Code: | 29 | ;;; Code: |
| 30 | 30 | ||
| 31 | (require 'cl-generic) | ||
| 31 | (require 'lisp-mode) | 32 | (require 'lisp-mode) |
| 32 | (eval-when-compile (require 'cl-lib)) | 33 | (eval-when-compile (require 'cl-lib)) |
| 33 | 34 | ||
| @@ -441,6 +442,7 @@ It can be quoted, or be inside a quoted form." | |||
| 441 | (string-match ".*$" doc) | 442 | (string-match ".*$" doc) |
| 442 | (match-string 0 doc)))) | 443 | (match-string 0 doc)))) |
| 443 | 444 | ||
| 445 | ;; can't (require 'find-func) in a preloaded file | ||
| 444 | (declare-function find-library-name "find-func" (library)) | 446 | (declare-function find-library-name "find-func" (library)) |
| 445 | (declare-function find-function-library "find-func" (function &optional l-o v)) | 447 | (declare-function find-function-library "find-func" (function &optional l-o v)) |
| 446 | 448 | ||
| @@ -598,60 +600,122 @@ It can be quoted, or be inside a quoted form." | |||
| 598 | (`apropos | 600 | (`apropos |
| 599 | (elisp--xref-find-apropos id)))) | 601 | (elisp--xref-find-apropos id)))) |
| 600 | 602 | ||
| 601 | (defun elisp--xref-identifier-location (type sym) | 603 | (defconst elisp--xref-format |
| 602 | (let ((file | ||
| 603 | (pcase type | ||
| 604 | (`defun (when (fboundp sym) | ||
| 605 | (let ((fun-lib | ||
| 606 | (find-function-library sym))) | ||
| 607 | (setq sym (car fun-lib)) | ||
| 608 | (cdr fun-lib)))) | ||
| 609 | (`defvar (and (boundp sym) | ||
| 610 | (let ((el-file (symbol-file sym 'defvar))) | ||
| 611 | (if el-file | ||
| 612 | (and | ||
| 613 | ;; Don't show minor modes twice. | ||
| 614 | ;; TODO: If TYPE ever becomes dependent on the | ||
| 615 | ;; context, move this check outside. | ||
| 616 | (not (and (fboundp sym) | ||
| 617 | (memq sym minor-mode-list))) | ||
| 618 | el-file) | ||
| 619 | (help-C-file-name sym 'var))))) | ||
| 620 | (`feature (and (featurep sym) | ||
| 621 | ;; Skip when a function with the same name | ||
| 622 | ;; is defined, because it's probably in the | ||
| 623 | ;; same file. | ||
| 624 | (not (fboundp sym)) | ||
| 625 | (ignore-errors | ||
| 626 | (find-library-name (symbol-name sym))))) | ||
| 627 | (`defface (when (facep sym) | ||
| 628 | (symbol-file sym 'defface)))))) | ||
| 629 | (when file | ||
| 630 | (when (string-match-p "\\.elc\\'" file) | ||
| 631 | (setq file (substring file 0 -1))) | ||
| 632 | (xref-make-elisp-location sym type file)))) | ||
| 633 | |||
| 634 | (defvar elisp--xref-format | ||
| 635 | (let ((str "(%s %s)")) | 604 | (let ((str "(%s %s)")) |
| 636 | (put-text-property 1 3 'face 'font-lock-keyword-face str) | 605 | (put-text-property 1 3 'face 'font-lock-keyword-face str) |
| 637 | (put-text-property 4 6 'face 'font-lock-function-name-face str) | 606 | (put-text-property 4 6 'face 'font-lock-function-name-face str) |
| 638 | str)) | 607 | str)) |
| 639 | 608 | ||
| 609 | (defconst elisp--xref-format-cl-defmethod | ||
| 610 | (let ((str "(%s %s %s)")) | ||
| 611 | (put-text-property 1 3 'face 'font-lock-keyword-face str) | ||
| 612 | (put-text-property 4 6 'face 'font-lock-function-name-face str) | ||
| 613 | str)) | ||
| 614 | |||
| 615 | (defcustom find-feature-regexp | ||
| 616 | (concat "(provide +'%s)") | ||
| 617 | "The regexp used by `xref-find-definitions' to search for a feature definition. | ||
| 618 | Note it must contain a `%s' at the place where `format' | ||
| 619 | should insert the feature name." | ||
| 620 | :type 'regexp | ||
| 621 | :group 'xref | ||
| 622 | :version "25.0") | ||
| 623 | |||
| 624 | (defcustom find-alias-regexp | ||
| 625 | "(\\(defalias +'\\|def\\(const\\|face\\) +\\)%s" | ||
| 626 | "The regexp used by `xref-find-definitions' to search for an alias definition. | ||
| 627 | Note it must contain a `%s' at the place where `format' | ||
| 628 | should insert the feature name." | ||
| 629 | :type 'regexp | ||
| 630 | :group 'xref | ||
| 631 | :version "25.0") | ||
| 632 | |||
| 633 | (with-eval-after-load 'find-func | ||
| 634 | (defvar find-function-regexp-alist) | ||
| 635 | (add-to-list 'find-function-regexp-alist (cons 'feature 'find-feature-regexp)) | ||
| 636 | (add-to-list 'find-function-regexp-alist (cons 'defalias 'find-alias-regexp))) | ||
| 637 | |||
| 638 | (defun elisp--xref-make-xref (type symbol file &optional summary) | ||
| 639 | "Return an xref for TYPE SYMBOL in FILE. | ||
| 640 | TYPE must be a type in 'find-function-regexp-alist' (use nil for | ||
| 641 | 'defun). If SUMMARY is non-nil, use it for the summary; | ||
| 642 | otherwise build the summary from TYPE and SYMBOL." | ||
| 643 | (xref-make (or summary | ||
| 644 | (format elisp--xref-format (or type 'defun) symbol)) | ||
| 645 | (xref-make-elisp-location symbol type file))) | ||
| 646 | |||
| 640 | (defun elisp--xref-find-definitions (symbol) | 647 | (defun elisp--xref-find-definitions (symbol) |
| 641 | (save-excursion | 648 | ;; The file name is not known when `symbol' is defined via interactive eval. |
| 642 | (let (lst) | 649 | (let (xrefs) |
| 643 | (dolist (type '(feature defface defvar defun)) | 650 | ;; alphabetical by result type symbol |
| 644 | (let ((loc | 651 | |
| 645 | (condition-case err | 652 | ;; FIXME: advised function; list of advice functions |
| 646 | (elisp--xref-identifier-location type symbol) | 653 | |
| 647 | (error | 654 | ;; FIXME: aliased variable |
| 648 | (xref-make-bogus-location (error-message-string err)))))) | 655 | |
| 649 | (when loc | 656 | (when (and (symbolp symbol) |
| 650 | (push | 657 | (symbol-function symbol) |
| 651 | (xref-make (format elisp--xref-format type symbol) | 658 | (symbolp (symbol-function symbol))) |
| 652 | loc) | 659 | ;; aliased function |
| 653 | lst)))) | 660 | (let* ((alias-symbol symbol) |
| 654 | lst))) | 661 | (alias-file (symbol-file alias-symbol)) |
| 662 | (real-symbol (symbol-function symbol)) | ||
| 663 | (real-file (find-lisp-object-file-name real-symbol 'defun))) | ||
| 664 | |||
| 665 | (when real-file | ||
| 666 | (push (elisp--xref-make-xref nil real-symbol real-file) xrefs)) | ||
| 667 | |||
| 668 | (when alias-file | ||
| 669 | (push (elisp--xref-make-xref 'defalias alias-symbol alias-file) xrefs)))) | ||
| 670 | |||
| 671 | (when (facep symbol) | ||
| 672 | (let ((file (find-lisp-object-file-name symbol 'defface))) | ||
| 673 | (when file | ||
| 674 | (push (elisp--xref-make-xref 'defface symbol file) xrefs)))) | ||
| 675 | |||
| 676 | (when (fboundp symbol) | ||
| 677 | (let ((file (find-lisp-object-file-name symbol (symbol-function symbol))) | ||
| 678 | generic) | ||
| 679 | (when file | ||
| 680 | (cond | ||
| 681 | ((eq file 'C-source) | ||
| 682 | ;; First call to find-lisp-object-file-name (for this | ||
| 683 | ;; symbol?); C-source has not been cached yet. | ||
| 684 | ;; Second call will return "src/*.c" in file; handled by 't' case below. | ||
| 685 | (push (elisp--xref-make-xref nil symbol (help-C-file-name (symbol-function symbol) 'subr)) xrefs)) | ||
| 686 | |||
| 687 | ((setq generic (cl--generic symbol)) | ||
| 688 | (dolist (method (cl--generic-method-table generic)) | ||
| 689 | (let* ((info (cl--generic-method-info method)) | ||
| 690 | (met-name (cons symbol (cl--generic-method-specializers method))) | ||
| 691 | (descr (format elisp--xref-format-cl-defmethod 'cl-defmethod symbol (nth 1 info))) | ||
| 692 | (file (find-lisp-object-file-name met-name 'cl-defmethod))) | ||
| 693 | (when file | ||
| 694 | (push (elisp--xref-make-xref 'cl-defmethod met-name file descr) xrefs)) | ||
| 695 | )) | ||
| 696 | |||
| 697 | (let ((descr (format elisp--xref-format 'cl-defgeneric symbol))) | ||
| 698 | (push (elisp--xref-make-xref nil symbol file descr) xrefs)) | ||
| 699 | ) | ||
| 700 | |||
| 701 | (t | ||
| 702 | (push (elisp--xref-make-xref nil symbol file) xrefs)) | ||
| 703 | )))) | ||
| 704 | |||
| 705 | (when (boundp symbol) | ||
| 706 | (let ((file (find-lisp-object-file-name symbol 'defvar))) | ||
| 707 | (when file | ||
| 708 | (when (eq file 'C-source) | ||
| 709 | (setq file (help-C-file-name symbol 'var))) | ||
| 710 | (push (elisp--xref-make-xref 'defvar symbol file) xrefs)))) | ||
| 711 | |||
| 712 | (when (featurep symbol) | ||
| 713 | (let ((file (ignore-errors | ||
| 714 | (find-library-name (symbol-name symbol))))) | ||
| 715 | (when file | ||
| 716 | (push (elisp--xref-make-xref 'feature symbol file) xrefs)))) | ||
| 717 | |||
| 718 | xrefs)) | ||
| 655 | 719 | ||
| 656 | (declare-function project-search-path "project") | 720 | (declare-function project-search-path "project") |
| 657 | (declare-function project-current "project") | 721 | (declare-function project-current "project") |
| @@ -689,13 +753,7 @@ It can be quoted, or be inside a quoted form." | |||
| 689 | 753 | ||
| 690 | (cl-defmethod xref-location-marker ((l xref-elisp-location)) | 754 | (cl-defmethod xref-location-marker ((l xref-elisp-location)) |
| 691 | (pcase-let (((cl-struct xref-elisp-location symbol type file) l)) | 755 | (pcase-let (((cl-struct xref-elisp-location symbol type file) l)) |
| 692 | (let ((buffer-point | 756 | (let ((buffer-point (find-function-search-for-symbol symbol type file))) |
| 693 | (pcase type | ||
| 694 | (`defun (find-function-search-for-symbol symbol nil file)) | ||
| 695 | ((or `defvar `defface) | ||
| 696 | (find-function-search-for-symbol symbol type file)) | ||
| 697 | (`feature | ||
| 698 | (cons (find-file-noselect file) 1))))) | ||
| 699 | (with-current-buffer (car buffer-point) | 757 | (with-current-buffer (car buffer-point) |
| 700 | (goto-char (or (cdr buffer-point) (point-min))) | 758 | (goto-char (or (cdr buffer-point) (point-min))) |
| 701 | (point-marker))))) | 759 | (point-marker))))) |
diff --git a/test/automated/elisp-mode-tests.el b/test/automated/elisp-mode-tests.el index 2581de46931..114b71cfc63 100644 --- a/test/automated/elisp-mode-tests.el +++ b/test/automated/elisp-mode-tests.el | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | ;; Copyright (C) 2015 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2015 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | ;; Author: Dmitry Gutov <dgutov@yandex.ru> | 5 | ;; Author: Dmitry Gutov <dgutov@yandex.ru> |
| 6 | ;; Author: Stephen Leake <stephen_leake@member.fsf.org> | ||
| 6 | 7 | ||
| 7 | ;; This file is part of GNU Emacs. | 8 | ;; This file is part of GNU Emacs. |
| 8 | 9 | ||
| @@ -113,26 +114,287 @@ | |||
| 113 | (should (member "backup-buffer" comps)) | 114 | (should (member "backup-buffer" comps)) |
| 114 | (should-not (member "backup-inhibited" comps))))) | 115 | (should-not (member "backup-inhibited" comps))))) |
| 115 | 116 | ||
| 116 | ;;; Navigation | 117 | ;;; xref |
| 117 | 118 | ||
| 118 | (ert-deftest elisp-xref-finds-both-function-and-variable () | 119 | (defun xref-elisp-test-descr-to-target (xref) |
| 119 | ;; "system-name" is both: a variable and a function | 120 | "Return an appropiate `looking-at' match string for XREF." |
| 120 | (let ((defs (elisp-xref-find 'definitions "system-name"))) | 121 | (let* ((loc (xref-item-location xref)) |
| 121 | (should (= (length defs) 2)) | 122 | (type (or (xref-elisp-location-type loc) |
| 122 | (should (string= (xref-item-summary (nth 0 defs)) | 123 | 'defun))) |
| 123 | "(defun system-name)")) | 124 | |
| 124 | (should (string= (xref-item-summary (nth 1 defs)) | 125 | (cl-case type |
| 125 | "(defvar system-name)"))) | 126 | (defalias |
| 127 | ;; summary: "(defalias xref)" | ||
| 128 | ;; target : "(defalias 'xref)" | ||
| 129 | (concat "(defalias '" (substring (xref-item-summary xref) 10 -1))) | ||
| 130 | |||
| 131 | (defun | ||
| 132 | (let ((summary (xref-item-summary xref)) | ||
| 133 | (file (xref-elisp-location-file loc))) | ||
| 134 | (cond | ||
| 135 | ((string= "c" (file-name-extension file)) | ||
| 136 | ;; summary: "(defun buffer-live-p)" | ||
| 137 | ;; target : "DEFUN (buffer-live-p" | ||
| 138 | (concat | ||
| 139 | (upcase (substring summary 1 6)) | ||
| 140 | " (\"" | ||
| 141 | (substring summary 7 -1) | ||
| 142 | "\"")) | ||
| 143 | |||
| 144 | (t | ||
| 145 | (substring summary 0 -1)) | ||
| 146 | ))) | ||
| 147 | |||
| 148 | (defvar | ||
| 149 | (let ((summary (xref-item-summary xref)) | ||
| 150 | (file (xref-elisp-location-file loc))) | ||
| 151 | (cond | ||
| 152 | ((string= "c" (file-name-extension file)) | ||
| 153 | ;; summary: "(defvar system-name)" | ||
| 154 | ;; target : "DEFVAR_LISP ("system-name", " | ||
| 155 | ;; summary: "(defvar abbrev-mode)" | ||
| 156 | ;; target : DEFVAR_PER_BUFFER ("abbrev-mode" | ||
| 157 | (concat | ||
| 158 | (upcase (substring summary 1 7)) | ||
| 159 | (if (bufferp (variable-binding-locus (xref-elisp-location-symbol loc))) | ||
| 160 | "_PER_BUFFER (\"" | ||
| 161 | "_LISP (\"") | ||
| 162 | (substring summary 8 -1) | ||
| 163 | "\"")) | ||
| 164 | |||
| 165 | (t | ||
| 166 | (substring summary 0 -1)) | ||
| 167 | ))) | ||
| 168 | |||
| 169 | (feature | ||
| 170 | ;; summary: "(feature xref)" | ||
| 171 | ;; target : "(provide 'xref)" | ||
| 172 | (concat "(provide '" (substring (xref-item-summary xref) 9 -1))) | ||
| 173 | |||
| 174 | (otherwise | ||
| 175 | (substring (xref-item-summary xref) 0 -1)) | ||
| 176 | ))) | ||
| 177 | |||
| 178 | |||
| 179 | (defmacro xref-elisp-test (name computed-xrefs expected-xrefs) | ||
| 180 | "Define an ert test for an xref-elisp feature. | ||
| 181 | COMPUTED-XREFS and EXPECTED-XREFS are lists of xrefs, except if | ||
| 182 | an element of EXPECTED-XREFS is a cons (XREF . TARGET), TARGET is | ||
| 183 | matched to the found location; otherwise, match | ||
| 184 | to (xref-elisp-test-descr-to-target xref)." | ||
| 185 | (declare (indent defun)) | ||
| 186 | (declare (debug (symbolp "name"))) | ||
| 187 | `(ert-deftest ,(intern (concat "xref-elisp-test-" (symbol-name name))) () | ||
| 188 | (let ((xrefs ,computed-xrefs) | ||
| 189 | (expecteds ,expected-xrefs)) | ||
| 190 | (while xrefs | ||
| 191 | (let ((xref (pop xrefs)) | ||
| 192 | (expected (pop expecteds))) | ||
| 193 | |||
| 194 | (should (equal xref | ||
| 195 | (or (when (consp expected) (car expected)) expected))) | ||
| 196 | |||
| 197 | (xref--goto-location (xref-item-location xref)) | ||
| 198 | (should (looking-at (or (when (consp expected) (cdr expected)) | ||
| 199 | (xref-elisp-test-descr-to-target expected))))) | ||
| 200 | )) | ||
| 201 | )) | ||
| 202 | |||
| 203 | ;; When tests are run from the Makefile, 'default-directory' is $HOME, | ||
| 204 | ;; so we must provide this dir to expand-file-name in the expected | ||
| 205 | ;; results. The Makefile sets EMACS_TEST_DIRECTORY. | ||
| 206 | (defconst emacs-test-dir (getenv "EMACS_TEST_DIRECTORY")) | ||
| 207 | |||
| 208 | ;; alphabetical by test name | ||
| 209 | |||
| 210 | ;; FIXME: autoload | ||
| 211 | |||
| 212 | ;; FIXME: defalias-defun-c cmpl-prefix-entry-head | ||
| 213 | ;; FIXME: defalias-defvar-el allout-mode-map | ||
| 214 | |||
| 215 | (xref-elisp-test find-defs-defalias-defun-el | ||
| 216 | (elisp--xref-find-definitions 'Buffer-menu-sort) | ||
| 217 | (list | ||
| 218 | (xref-make "(defalias Buffer-menu-sort)" | ||
| 219 | (xref-make-elisp-location | ||
| 220 | 'Buffer-menu-sort 'defalias | ||
| 221 | (expand-file-name "../../lisp/buff-menu.elc" emacs-test-dir))) | ||
| 222 | (xref-make "(defun tabulated-list-sort)" | ||
| 223 | (xref-make-elisp-location | ||
| 224 | 'tabulated-list-sort nil | ||
| 225 | (expand-file-name "../../lisp/emacs-lisp/tabulated-list.el" emacs-test-dir))) | ||
| 226 | )) | ||
| 227 | |||
| 228 | ;; FIXME: defconst | ||
| 229 | |||
| 230 | (xref-elisp-test find-defs-defgeneric-el | ||
| 231 | (elisp--xref-find-definitions 'xref-location-marker) | ||
| 232 | (list | ||
| 233 | (xref-make "(cl-defgeneric xref-location-marker)" | ||
| 234 | (xref-make-elisp-location | ||
| 235 | 'xref-location-marker nil | ||
| 236 | (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))) | ||
| 237 | (xref-make "(cl-defmethod xref-location-marker ((l xref-elisp-location)))" | ||
| 238 | (xref-make-elisp-location | ||
| 239 | '(xref-location-marker xref-elisp-location) 'cl-defmethod | ||
| 240 | (expand-file-name "../../lisp/progmodes/elisp-mode.el" emacs-test-dir))) | ||
| 241 | (xref-make "(cl-defmethod xref-location-marker ((l xref-file-location)))" | ||
| 242 | (xref-make-elisp-location | ||
| 243 | '(xref-location-marker xref-file-location) 'cl-defmethod | ||
| 244 | (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))) | ||
| 245 | (xref-make "(cl-defmethod xref-location-marker ((l xref-buffer-location)))" | ||
| 246 | (xref-make-elisp-location | ||
| 247 | '(xref-location-marker xref-buffer-location) 'cl-defmethod | ||
| 248 | (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))) | ||
| 249 | (xref-make "(cl-defmethod xref-location-marker ((l xref-bogus-location)))" | ||
| 250 | (xref-make-elisp-location | ||
| 251 | '(xref-location-marker xref-bogus-location) 'cl-defmethod | ||
| 252 | (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))) | ||
| 253 | (xref-make "(cl-defmethod xref-location-marker ((l xref-etags-location)))" | ||
| 254 | (xref-make-elisp-location | ||
| 255 | '(xref-location-marker xref-etags-location) 'cl-defmethod | ||
| 256 | (expand-file-name "../../lisp/progmodes/etags.el" emacs-test-dir))) | ||
| 257 | )) | ||
| 258 | |||
| 259 | ;; FIXME: constructor xref-make-elisp-location; location is | ||
| 260 | ;; cl-defstruct location. use :constructor in description. | ||
| 261 | |||
| 262 | (xref-elisp-test find-defs-defgeneric-eval | ||
| 263 | (elisp--xref-find-definitions (eval '(cl-defgeneric stephe-leake-cl-defgeneric ()))) | ||
| 264 | nil) | ||
| 265 | |||
| 266 | (xref-elisp-test find-defs-defun-el | ||
| 267 | (elisp--xref-find-definitions 'xref-find-definitions) | ||
| 268 | (list | ||
| 269 | (xref-make "(defun xref-find-definitions)" | ||
| 270 | (xref-make-elisp-location | ||
| 271 | 'xref-find-definitions nil | ||
| 272 | (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))))) | ||
| 273 | |||
| 274 | (xref-elisp-test find-defs-defun-eval | ||
| 275 | (elisp--xref-find-definitions (eval '(defun stephe-leake-defun ()))) | ||
| 276 | nil) | ||
| 277 | |||
| 278 | (xref-elisp-test find-defs-defun-c | ||
| 279 | (elisp--xref-find-definitions 'buffer-live-p) | ||
| 280 | (list | ||
| 281 | (xref-make "(defun buffer-live-p)" | ||
| 282 | (xref-make-elisp-location 'buffer-live-p nil "src/buffer.c")))) | ||
| 283 | |||
| 284 | ;; FIXME: deftype | ||
| 285 | |||
| 286 | (xref-elisp-test find-defs-defun-c-defvar-c | ||
| 287 | (elisp-xref-find 'definitions "system-name") | ||
| 288 | (list | ||
| 289 | (xref-make "(defvar system-name)" | ||
| 290 | (xref-make-elisp-location 'system-name 'defvar "src/editfns.c")) | ||
| 291 | (xref-make "(defun system-name)" | ||
| 292 | (xref-make-elisp-location 'system-name nil "src/editfns.c"))) | ||
| 293 | ) | ||
| 294 | |||
| 295 | (xref-elisp-test find-defs-defun-el-defvar-c | ||
| 296 | (elisp-xref-find 'definitions "abbrev-mode") | ||
| 126 | ;; It's a minor mode, but the variable is defined in buffer.c | 297 | ;; It's a minor mode, but the variable is defined in buffer.c |
| 127 | (let ((defs (elisp-xref-find 'definitions "abbrev-mode"))) | 298 | (list |
| 128 | (should (= (length defs) 2)))) | 299 | (xref-make "(defvar abbrev-mode)" |
| 129 | 300 | (xref-make-elisp-location 'abbrev-mode 'defvar "src/buffer.c")) | |
| 130 | (ert-deftest elisp-xref-finds-only-function-for-minor-mode () | 301 | (cons |
| 131 | ;; Both variable and function are defined in the same place. | 302 | (xref-make "(defun abbrev-mode)" |
| 132 | (let ((defs (elisp-xref-find 'definitions "visible-mode"))) | 303 | (xref-make-elisp-location |
| 133 | (should (= (length defs) 1)) | 304 | 'abbrev-mode nil |
| 134 | (should (string= (xref-item-summary (nth 0 defs)) | 305 | (expand-file-name "../../lisp/abbrev.el" emacs-test-dir))) |
| 135 | "(defun visible-mode)")))) | 306 | "(define-minor-mode abbrev-mode")) |
| 307 | ) | ||
| 308 | |||
| 309 | ;; Source for both variable and defun is "(define-minor-mode | ||
| 310 | ;; compilation-minor-mode". There is no way to tell that from the | ||
| 311 | ;; symbol. find-function-regexp-alist uses find-function-regexp for | ||
| 312 | ;; this, but that matches too many things for use in this test. | ||
| 313 | (xref-elisp-test find-defs-defun-defvar-el | ||
| 314 | (elisp--xref-find-definitions 'compilation-minor-mode) | ||
| 315 | (list | ||
| 316 | (cons | ||
| 317 | (xref-make "(defun compilation-minor-mode)" | ||
| 318 | (xref-make-elisp-location | ||
| 319 | 'compilation-minor-mode nil | ||
| 320 | (expand-file-name "../../lisp/progmodes/compile.el" emacs-test-dir))) | ||
| 321 | "(define-minor-mode compilation-minor-mode") | ||
| 322 | (cons | ||
| 323 | (xref-make "(defvar compilation-minor-mode)" | ||
| 324 | (xref-make-elisp-location | ||
| 325 | 'compilation-minor-mode 'defvar | ||
| 326 | (expand-file-name "../../lisp/progmodes/compile.el" emacs-test-dir))) | ||
| 327 | "(define-minor-mode compilation-minor-mode") | ||
| 328 | ) | ||
| 329 | ) | ||
| 330 | |||
| 331 | (xref-elisp-test find-defs-defvar-el | ||
| 332 | (elisp--xref-find-definitions 'xref--marker-ring) | ||
| 333 | ;; This is a defconst, which creates an alias and a variable. | ||
| 334 | ;; FIXME: try not to show the alias in this case | ||
| 335 | (list | ||
| 336 | (xref-make "(defvar xref--marker-ring)" | ||
| 337 | (xref-make-elisp-location | ||
| 338 | 'xref--marker-ring 'defvar | ||
| 339 | (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))) | ||
| 340 | (cons | ||
| 341 | (xref-make "(defalias xref--marker-ring)" | ||
| 342 | (xref-make-elisp-location | ||
| 343 | 'xref--marker-ring 'defalias | ||
| 344 | (expand-file-name "../../lisp/progmodes/xref.elc" emacs-test-dir))) | ||
| 345 | "(defvar xref--marker-ring") | ||
| 346 | )) | ||
| 347 | |||
| 348 | (xref-elisp-test find-defs-defvar-c | ||
| 349 | (elisp--xref-find-definitions 'default-directory) | ||
| 350 | (list | ||
| 351 | (cons | ||
| 352 | (xref-make "(defvar default-directory)" | ||
| 353 | (xref-make-elisp-location 'default-directory 'defvar "src/buffer.c")) | ||
| 354 | ;; IMPROVEME: we might be able to compute this target | ||
| 355 | "DEFVAR_PER_BUFFER (\"default-directory\""))) | ||
| 356 | |||
| 357 | (xref-elisp-test find-defs-defvar-eval | ||
| 358 | (elisp--xref-find-definitions (eval '(defvar stephe-leake-defvar nil))) | ||
| 359 | nil) | ||
| 360 | |||
| 361 | (xref-elisp-test find-defs-face-el | ||
| 362 | (elisp--xref-find-definitions 'font-lock-keyword-face) | ||
| 363 | ;; 'font-lock-keyword-face is both a face and a var | ||
| 364 | ;; defface creates both a face and an alias | ||
| 365 | ;; FIXME: try to not show the alias in this case | ||
| 366 | (list | ||
| 367 | (xref-make "(defvar font-lock-keyword-face)" | ||
| 368 | (xref-make-elisp-location | ||
| 369 | 'font-lock-keyword-face 'defvar | ||
| 370 | (expand-file-name "../../lisp/font-lock.el" emacs-test-dir))) | ||
| 371 | (xref-make "(defface font-lock-keyword-face)" | ||
| 372 | (xref-make-elisp-location | ||
| 373 | 'font-lock-keyword-face 'defface | ||
| 374 | (expand-file-name "../../lisp/font-lock.el" emacs-test-dir))) | ||
| 375 | (cons | ||
| 376 | (xref-make "(defalias font-lock-keyword-face)" | ||
| 377 | (xref-make-elisp-location | ||
| 378 | 'font-lock-keyword-face 'defalias | ||
| 379 | (expand-file-name "../../lisp/font-lock.elc" emacs-test-dir))) | ||
| 380 | "(defface font-lock-keyword-face") | ||
| 381 | )) | ||
| 382 | |||
| 383 | (xref-elisp-test find-defs-face-eval | ||
| 384 | (elisp--xref-find-definitions (eval '(defface stephe-leake-defface nil ""))) | ||
| 385 | nil) | ||
| 386 | |||
| 387 | (xref-elisp-test find-defs-feature-el | ||
| 388 | (elisp--xref-find-definitions 'xref) | ||
| 389 | (list | ||
| 390 | (xref-make "(feature xref)" | ||
| 391 | (xref-make-elisp-location | ||
| 392 | 'xref 'feature | ||
| 393 | (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))))) | ||
| 394 | |||
| 395 | (xref-elisp-test find-defs-feature-eval | ||
| 396 | (elisp--xref-find-definitions (eval '(provide 'stephe-leake-feature))) | ||
| 397 | nil) | ||
| 136 | 398 | ||
| 137 | (provide 'elisp-mode-tests) | 399 | (provide 'elisp-mode-tests) |
| 138 | ;;; elisp-mode-tests.el ends here | 400 | ;;; elisp-mode-tests.el ends here |