aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Leake2015-08-11 14:28:17 -0500
committerStephen Leake2015-08-11 14:29:34 -0500
commit85f7e5115f9f409126d355997e8103ea5126ada2 (patch)
treea70e6c131fa45969de0efd7dca0eca681581f7df
parent6171d5b1f9edb09ca43c219f08e7a372de8740b2 (diff)
downloademacs-85f7e5115f9f409126d355997e8103ea5126ada2.tar.gz
emacs-85f7e5115f9f409126d355997e8103ea5126ada2.zip
elisp--xref-find-definitions handle cl-defstuct default constructor
* lisp/progmodes/elisp-mode.el (elisp-xref-find): Add FIXME. (elisp--xref-format-extra): Rename from elisp--xref-format-cl-defmethod. (elisp--xref-find-definitions): Handle cl-defstuct default constructor. * test/automated/elisp-mode-tests.el (xref-elisp-test-run): Split out from xref-elisp-test for ease of debugging. (xref-elisp-deftest): Rename from xref-elisp-test. (find-defs-constructor): New test. (find-defs-defgeneric-el): Match batch test config. (compile): Required for find-defs compilation-minor-mode test. (find-defs-defvar-el): Match code change. (find-defs-face-el): Match code change. * lisp/progmodes/xref.el (xref-find-function, xref-find-definitions): Improve doc string.
-rw-r--r--lisp/progmodes/elisp-mode.el25
-rw-r--r--lisp/progmodes/xref.el15
-rw-r--r--test/automated/elisp-mode-tests.el121
3 files changed, 92 insertions, 69 deletions
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 41ca57f668d..7ac5a5cb778 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -590,6 +590,10 @@ It can be quoted, or be inside a quoted form."
590 590
591(defun elisp-xref-find (action id) 591(defun elisp-xref-find (action id)
592 (require 'find-func) 592 (require 'find-func)
593 ;; FIXME: use information in source near point to filter results:
594 ;; (dvc-log-edit ...) - exclude 'feature
595 ;; (require 'dvc-log-edit) - only 'feature
596 ;; Semantic may provide additional information
593 (pcase action 597 (pcase action
594 (`definitions 598 (`definitions
595 (let ((sym (intern-soft id))) 599 (let ((sym (intern-soft id)))
@@ -606,7 +610,7 @@ It can be quoted, or be inside a quoted form."
606 (put-text-property 4 6 'face 'font-lock-function-name-face str) 610 (put-text-property 4 6 'face 'font-lock-function-name-face str)
607 str)) 611 str))
608 612
609(defconst elisp--xref-format-cl-defmethod 613(defconst elisp--xref-format-extra
610 (let ((str "(%s %s %s)")) 614 (let ((str "(%s %s %s)"))
611 (put-text-property 1 3 'face 'font-lock-keyword-face str) 615 (put-text-property 1 3 'face 'font-lock-keyword-face str)
612 (put-text-property 4 6 'face 'font-lock-function-name-face str) 616 (put-text-property 4 6 'face 'font-lock-function-name-face str)
@@ -675,7 +679,7 @@ otherwise build the summary from TYPE and SYMBOL."
675 679
676 (when (fboundp symbol) 680 (when (fboundp symbol)
677 (let ((file (find-lisp-object-file-name symbol (symbol-function symbol))) 681 (let ((file (find-lisp-object-file-name symbol (symbol-function symbol)))
678 generic) 682 generic doc)
679 (when file 683 (when file
680 (cond 684 (cond
681 ((eq file 'C-source) 685 ((eq file 'C-source)
@@ -684,11 +688,26 @@ otherwise build the summary from TYPE and SYMBOL."
684 ;; Second call will return "src/*.c" in file; handled by 't' case below. 688 ;; 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)) 689 (push (elisp--xref-make-xref nil symbol (help-C-file-name (symbol-function symbol) 'subr)) xrefs))
686 690
691 ((and (setq doc (documentation symbol t))
692 ;; This doc string is defined in cl-macs.el cl-defstruct
693 (string-match "Constructor for objects of type `\\(.*\\)'" doc))
694 ;; `symbol' is a name for the default constructor created by
695 ;; cl-defstruct, so return the location of the cl-defstruct.
696 (let* ((type-name (match-string 1 doc))
697 (type-symbol (intern type-name))
698 (file (find-lisp-object-file-name type-symbol 'define-type))
699 (summary (format elisp--xref-format-extra
700 'cl-defstruct
701 (concat "(" type-name)
702 (concat "(:constructor " (symbol-name symbol) "))"))))
703 (push (elisp--xref-make-xref 'define-type type-symbol file summary) xrefs)
704 ))
705
687 ((setq generic (cl--generic symbol)) 706 ((setq generic (cl--generic symbol))
688 (dolist (method (cl--generic-method-table generic)) 707 (dolist (method (cl--generic-method-table generic))
689 (let* ((info (cl--generic-method-info method)) 708 (let* ((info (cl--generic-method-info method))
690 (met-name (cons symbol (cl--generic-method-specializers method))) 709 (met-name (cons symbol (cl--generic-method-specializers method)))
691 (descr (format elisp--xref-format-cl-defmethod 'cl-defmethod symbol (nth 1 info))) 710 (descr (format elisp--xref-format-extra 'cl-defmethod symbol (nth 1 info)))
692 (file (find-lisp-object-file-name met-name 'cl-defmethod))) 711 (file (find-lisp-object-file-name met-name 'cl-defmethod)))
693 (when file 712 (when file
694 (push (elisp--xref-make-xref 'cl-defmethod met-name file descr) xrefs)) 713 (push (elisp--xref-make-xref 'cl-defmethod met-name file descr) xrefs))
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 68f6cfffd2a..b0a8eb7a316 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -202,8 +202,10 @@ LOCATION is an `xref-location'."
202It can be called in several ways: 202It can be called in several ways:
203 203
204 (definitions IDENTIFIER): Find definitions of IDENTIFIER. The 204 (definitions IDENTIFIER): Find definitions of IDENTIFIER. The
205result must be a list of xref objects. If no definitions can be 205result must be a list of xref objects. If IDENTIFIER contains
206found, return nil. 206sufficient information to determine a unique definition, returns
207only that definition. If there are multiple possible definitions,
208return all of them. If no definitions can be found, return nil.
207 209
208 (references IDENTIFIER): Find references of IDENTIFIER. The 210 (references IDENTIFIER): Find references of IDENTIFIER. The
209result must be a list of xref objects. If no references can be 211result must be a list of xref objects. If no references can be
@@ -751,7 +753,14 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
751(defun xref-find-definitions (identifier) 753(defun xref-find-definitions (identifier)
752 "Find the definition of the identifier at point. 754 "Find the definition of the identifier at point.
753With prefix argument or when there's no identifier at point, 755With prefix argument or when there's no identifier at point,
754prompt for it." 756prompt for it.
757
758If the backend has sufficient information to determine a unique
759definition for IDENTIFIER, it returns only that definition. If
760there are multiple possible definitions, it returns all of them.
761
762If the backend returns one definition, jump to it; otherwise,
763display the list in a buffer."
755 (interactive (list (xref--read-identifier "Find definitions of: "))) 764 (interactive (list (xref--read-identifier "Find definitions of: ")))
756 (xref--find-definitions identifier nil)) 765 (xref--find-definitions identifier nil))
757 766
diff --git a/test/automated/elisp-mode-tests.el b/test/automated/elisp-mode-tests.el
index 114b71cfc63..9b4014a8a55 100644
--- a/test/automated/elisp-mode-tests.el
+++ b/test/automated/elisp-mode-tests.el
@@ -176,28 +176,30 @@
176 ))) 176 )))
177 177
178 178
179(defmacro xref-elisp-test (name computed-xrefs expected-xrefs) 179(defun xref-elisp-test-run (xrefs expecteds)
180 (while xrefs
181 (should (= (length xrefs) (length expecteds)))
182 (let ((xref (pop xrefs))
183 (expected (pop expecteds)))
184
185 (should (equal xref
186 (or (when (consp expected) (car expected)) expected)))
187
188 (xref--goto-location (xref-item-location xref))
189 (should (looking-at (or (when (consp expected) (cdr expected))
190 (xref-elisp-test-descr-to-target expected)))))
191 ))
192
193(defmacro xref-elisp-deftest (name computed-xrefs expected-xrefs)
180 "Define an ert test for an xref-elisp feature. 194 "Define an ert test for an xref-elisp feature.
181COMPUTED-XREFS and EXPECTED-XREFS are lists of xrefs, except if 195COMPUTED-XREFS and EXPECTED-XREFS are lists of xrefs, except if
182an element of EXPECTED-XREFS is a cons (XREF . TARGET), TARGET is 196an element of EXPECTED-XREFS is a cons (XREF . TARGET), TARGET is
183matched to the found location; otherwise, match 197matched to the found location; otherwise, match
184to (xref-elisp-test-descr-to-target xref)." 198to (xref-elisp-test-descr-to-target xref)."
185 (declare (indent defun)) 199 (declare (indent defun)
186 (declare (debug (symbolp "name"))) 200 (debug (symbolp "name")))
187 `(ert-deftest ,(intern (concat "xref-elisp-test-" (symbol-name name))) () 201 `(ert-deftest ,(intern (concat "xref-elisp-test-" (symbol-name name))) ()
188 (let ((xrefs ,computed-xrefs) 202 (xref-elisp-test-run ,computed-xrefs ,expected-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 )) 203 ))
202 204
203;; When tests are run from the Makefile, 'default-directory' is $HOME, 205;; When tests are run from the Makefile, 'default-directory' is $HOME,
@@ -212,7 +214,22 @@ to (xref-elisp-test-descr-to-target xref)."
212;; FIXME: defalias-defun-c cmpl-prefix-entry-head 214;; FIXME: defalias-defun-c cmpl-prefix-entry-head
213;; FIXME: defalias-defvar-el allout-mode-map 215;; FIXME: defalias-defvar-el allout-mode-map
214 216
215(xref-elisp-test find-defs-defalias-defun-el 217(xref-elisp-deftest find-defs-constructor
218 (elisp--xref-find-definitions 'xref-make-elisp-location)
219 ;; 'xref-make-elisp-location' is just a name for the default
220 ;; constructor created by the cl-defstruct, so the location is the
221 ;; cl-defstruct location.
222 (list
223 (cons
224 (xref-make "(cl-defstruct (xref-elisp-location (:constructor xref-make-elisp-location)))"
225 (xref-make-elisp-location
226 'xref-elisp-location 'define-type
227 (expand-file-name "../../lisp/progmodes/elisp-mode.el" emacs-test-dir)))
228 ;; It's not worth adding another special case to `xref-elisp-test-descr-to-target' for this
229 "(cl-defstruct (xref-elisp-location")
230 ))
231
232(xref-elisp-deftest find-defs-defalias-defun-el
216 (elisp--xref-find-definitions 'Buffer-menu-sort) 233 (elisp--xref-find-definitions 'Buffer-menu-sort)
217 (list 234 (list
218 (xref-make "(defalias Buffer-menu-sort)" 235 (xref-make "(defalias Buffer-menu-sort)"
@@ -227,7 +244,7 @@ to (xref-elisp-test-descr-to-target xref)."
227 244
228;; FIXME: defconst 245;; FIXME: defconst
229 246
230(xref-elisp-test find-defs-defgeneric-el 247(xref-elisp-deftest find-defs-defgeneric-el
231 (elisp--xref-find-definitions 'xref-location-marker) 248 (elisp--xref-find-definitions 'xref-location-marker)
232 (list 249 (list
233 (xref-make "(cl-defgeneric xref-location-marker)" 250 (xref-make "(cl-defgeneric xref-location-marker)"
@@ -250,20 +267,14 @@ to (xref-elisp-test-descr-to-target xref)."
250 (xref-make-elisp-location 267 (xref-make-elisp-location
251 '(xref-location-marker xref-bogus-location) 'cl-defmethod 268 '(xref-location-marker xref-bogus-location) 'cl-defmethod
252 (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))) 269 (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir)))
253 (xref-make "(cl-defmethod xref-location-marker ((l xref-etags-location)))" 270 ;; etags is not loaded at test time
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 )) 271 ))
258 272
259;; FIXME: constructor xref-make-elisp-location; location is 273(xref-elisp-deftest find-defs-defgeneric-eval
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 ()))) 274 (elisp--xref-find-definitions (eval '(cl-defgeneric stephe-leake-cl-defgeneric ())))
264 nil) 275 nil)
265 276
266(xref-elisp-test find-defs-defun-el 277(xref-elisp-deftest find-defs-defun-el
267 (elisp--xref-find-definitions 'xref-find-definitions) 278 (elisp--xref-find-definitions 'xref-find-definitions)
268 (list 279 (list
269 (xref-make "(defun xref-find-definitions)" 280 (xref-make "(defun xref-find-definitions)"
@@ -271,11 +282,11 @@ to (xref-elisp-test-descr-to-target xref)."
271 'xref-find-definitions nil 282 'xref-find-definitions nil
272 (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))))) 283 (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir)))))
273 284
274(xref-elisp-test find-defs-defun-eval 285(xref-elisp-deftest find-defs-defun-eval
275 (elisp--xref-find-definitions (eval '(defun stephe-leake-defun ()))) 286 (elisp--xref-find-definitions (eval '(defun stephe-leake-defun ())))
276 nil) 287 nil)
277 288
278(xref-elisp-test find-defs-defun-c 289(xref-elisp-deftest find-defs-defun-c
279 (elisp--xref-find-definitions 'buffer-live-p) 290 (elisp--xref-find-definitions 'buffer-live-p)
280 (list 291 (list
281 (xref-make "(defun buffer-live-p)" 292 (xref-make "(defun buffer-live-p)"
@@ -283,7 +294,7 @@ to (xref-elisp-test-descr-to-target xref)."
283 294
284;; FIXME: deftype 295;; FIXME: deftype
285 296
286(xref-elisp-test find-defs-defun-c-defvar-c 297(xref-elisp-deftest find-defs-defun-c-defvar-c
287 (elisp-xref-find 'definitions "system-name") 298 (elisp-xref-find 'definitions "system-name")
288 (list 299 (list
289 (xref-make "(defvar system-name)" 300 (xref-make "(defvar system-name)"
@@ -292,7 +303,7 @@ to (xref-elisp-test-descr-to-target xref)."
292 (xref-make-elisp-location 'system-name nil "src/editfns.c"))) 303 (xref-make-elisp-location 'system-name nil "src/editfns.c")))
293 ) 304 )
294 305
295(xref-elisp-test find-defs-defun-el-defvar-c 306(xref-elisp-deftest find-defs-defun-el-defvar-c
296 (elisp-xref-find 'definitions "abbrev-mode") 307 (elisp-xref-find 'definitions "abbrev-mode")
297 ;; It's a minor mode, but the variable is defined in buffer.c 308 ;; It's a minor mode, but the variable is defined in buffer.c
298 (list 309 (list
@@ -310,42 +321,34 @@ to (xref-elisp-test-descr-to-target xref)."
310;; compilation-minor-mode". There is no way to tell that from the 321;; compilation-minor-mode". There is no way to tell that from the
311;; symbol. find-function-regexp-alist uses find-function-regexp for 322;; symbol. find-function-regexp-alist uses find-function-regexp for
312;; this, but that matches too many things for use in this test. 323;; this, but that matches too many things for use in this test.
313(xref-elisp-test find-defs-defun-defvar-el 324(require 'compile) ;; not loaded by default at test time
325(xref-elisp-deftest find-defs-defun-defvar-el
314 (elisp--xref-find-definitions 'compilation-minor-mode) 326 (elisp--xref-find-definitions 'compilation-minor-mode)
315 (list 327 (list
316 (cons 328 (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)" 329 (xref-make "(defvar compilation-minor-mode)"
324 (xref-make-elisp-location 330 (xref-make-elisp-location
325 'compilation-minor-mode 'defvar 331 'compilation-minor-mode 'defvar
326 (expand-file-name "../../lisp/progmodes/compile.el" emacs-test-dir))) 332 (expand-file-name "../../lisp/progmodes/compile.el" emacs-test-dir)))
327 "(define-minor-mode compilation-minor-mode") 333 "(define-minor-mode compilation-minor-mode")
328 ) 334 (cons
329 ) 335 (xref-make "(defun compilation-minor-mode)"
336 (xref-make-elisp-location
337 'compilation-minor-mode nil
338 (expand-file-name "../../lisp/progmodes/compile.el" emacs-test-dir)))
339 "(define-minor-mode compilation-minor-mode")
340 ))
330 341
331(xref-elisp-test find-defs-defvar-el 342(xref-elisp-deftest find-defs-defvar-el
332 (elisp--xref-find-definitions 'xref--marker-ring) 343 (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 344 (list
336 (xref-make "(defvar xref--marker-ring)" 345 (xref-make "(defvar xref--marker-ring)"
337 (xref-make-elisp-location 346 (xref-make-elisp-location
338 'xref--marker-ring 'defvar 347 'xref--marker-ring 'defvar
339 (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))) 348 (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 )) 349 ))
347 350
348(xref-elisp-test find-defs-defvar-c 351(xref-elisp-deftest find-defs-defvar-c
349 (elisp--xref-find-definitions 'default-directory) 352 (elisp--xref-find-definitions 'default-directory)
350 (list 353 (list
351 (cons 354 (cons
@@ -354,15 +357,13 @@ to (xref-elisp-test-descr-to-target xref)."
354 ;; IMPROVEME: we might be able to compute this target 357 ;; IMPROVEME: we might be able to compute this target
355 "DEFVAR_PER_BUFFER (\"default-directory\""))) 358 "DEFVAR_PER_BUFFER (\"default-directory\"")))
356 359
357(xref-elisp-test find-defs-defvar-eval 360(xref-elisp-deftest find-defs-defvar-eval
358 (elisp--xref-find-definitions (eval '(defvar stephe-leake-defvar nil))) 361 (elisp--xref-find-definitions (eval '(defvar stephe-leake-defvar nil)))
359 nil) 362 nil)
360 363
361(xref-elisp-test find-defs-face-el 364(xref-elisp-deftest find-defs-face-el
362 (elisp--xref-find-definitions 'font-lock-keyword-face) 365 (elisp--xref-find-definitions 'font-lock-keyword-face)
363 ;; 'font-lock-keyword-face is both a face and a var 366 ;; '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 (list
367 (xref-make "(defvar font-lock-keyword-face)" 368 (xref-make "(defvar font-lock-keyword-face)"
368 (xref-make-elisp-location 369 (xref-make-elisp-location
@@ -372,19 +373,13 @@ to (xref-elisp-test-descr-to-target xref)."
372 (xref-make-elisp-location 373 (xref-make-elisp-location
373 'font-lock-keyword-face 'defface 374 'font-lock-keyword-face 'defface
374 (expand-file-name "../../lisp/font-lock.el" emacs-test-dir))) 375 (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 )) 376 ))
382 377
383(xref-elisp-test find-defs-face-eval 378(xref-elisp-deftest find-defs-face-eval
384 (elisp--xref-find-definitions (eval '(defface stephe-leake-defface nil ""))) 379 (elisp--xref-find-definitions (eval '(defface stephe-leake-defface nil "")))
385 nil) 380 nil)
386 381
387(xref-elisp-test find-defs-feature-el 382(xref-elisp-deftest find-defs-feature-el
388 (elisp--xref-find-definitions 'xref) 383 (elisp--xref-find-definitions 'xref)
389 (list 384 (list
390 (xref-make "(feature xref)" 385 (xref-make "(feature xref)"
@@ -392,7 +387,7 @@ to (xref-elisp-test-descr-to-target xref)."
392 'xref 'feature 387 'xref 'feature
393 (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir))))) 388 (expand-file-name "../../lisp/progmodes/xref.el" emacs-test-dir)))))
394 389
395(xref-elisp-test find-defs-feature-eval 390(xref-elisp-deftest find-defs-feature-eval
396 (elisp--xref-find-definitions (eval '(provide 'stephe-leake-feature))) 391 (elisp--xref-find-definitions (eval '(provide 'stephe-leake-feature)))
397 nil) 392 nil)
398 393