1 ;; JDE-XREF.EL --- Class cross-reference commands for the JDEE.
2 ;; $Revision: 1.24 $ $Date: 2004/06/06 14:19:23 $
4 ;; Copyright (C) 2002, 2003 Andrew Hyatt
6 ;; Author: Andrew Hyatt <andy_jde@thehyatts.net>
7 ;; Maintainers: Andrew Hyatt and Paul Kinnucan
8 ;; Keywords: java, tools
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; A copy of the GNU General Public License can be obtained from this
22 ;; program's author (send electronic mail to
23 ;; ) or from the Free Software
24 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 ;; jde-xref|Andrew Hyatt|
28 ;; |Java class cross-referencing commands for the JDEE
29 ;; |$Date: 2004/06/06 14:19:23 $|$Revision: 1.24 $|~/packages/jde-xref.el
33 ;; This file stores all caller-related functionality, from the
34 ;; functions to find all callers of a Java method, to those that will
35 ;; do more sophisticated things like creating a call-tree
37 ;; Everything works off the database, which is split into a series of
38 ;; files, one file per package. Each package consists of three tables.
39 ;; The first is a mapping of class-function-args specifiers to a list
40 ;; of all the classes, method & linenumbers that call it, such as:
42 ;; (("org.foo.MyClass" "getName" nil "String") .
43 ;; (("org.foo.MyOtherClass" "doProcessing" nil nil 42)
44 ;; ("org.foo.YetAnotherClass" "doMoreProcessing" nil nil 32)))
46 ;; The specifier for a method (the first part of the above is a: fully
47 ;; qualified classname , function name, return type (nil for "void")
48 ;; and non-fully qualified arglist. We don't want to fully qualify
49 ;; the arglist, so that we don't have to fully qualify it when doing a
50 ;; lookup. The changes of collisions are minor, I think.
52 ;; The next table is a table of which class has which interfaces.
53 ;; This is used so that we can consider a call to IFoo.doSomething as
54 ;; a call to Foo.doSomething, is Foo implements IFoo. This
55 ;; functionality is not always wanted, so the functions that show
56 ;; caller information can either use it or not.
58 ;; The third table is a table of which class has which methods and
59 ;; fields. This is necessary to determine which references to
60 ;; subclasses really are references to a superclass because the fields
61 ;; or methods have not been overriden.
63 ;; The fourth table is a table of classes to superclasses, necessary
64 ;; to figure out when a call to superclass might be a call to a
65 ;; subclass (when the user asks about calls to the subclass).
67 ;; There is also a global table across all packages, which is a
68 ;; map of which classes are subclasses of which other classes. This
69 ;; makes it possible to investigate a class's subclasses when looking
74 (require 'jde-parse-class)
76 (require 'tree-widget)
78 (defconst jde-xref-version "1.5")
80 (defgroup jde-xref nil
81 "JDEE Class Cross-Reference (Refactoring) Options"
86 (defcustom jde-xref-db-base-directory "."
87 "The path to store the directory which contains the database of
88 which function calls which. The data directory will be called
89 \"xrefdb\" and will reside in the directory pointed to at this
94 (defcustom jde-xref-store-prefixes nil
95 "A list of what prefixes to specify what references should be
96 tracked in the caller database. Such as: '(\"org.apache\" \"jde\"),
97 to keep track of all references to classes that start with
98 \"org.apache\" or \"jde\"."
100 :type '(repeat (string :tag "Prefix")))
102 (defcustom jde-xref-cache-size 3
103 "How much package info to cache in memory at once. The higher the
104 variable is the more memory will be used, but the faster things
109 (defvar jde-xref-stack nil
110 "A list of the callers of a function, to be popped one at a time
111 and shown to the user")
113 (defvar jde-xref-modified-classes nil
114 "A list of modified classes, to be used in updating the caller table
115 when a recompile happens")
117 (defvar jde-xref-parsed-classes nil
118 "A global variable that is used to hold which classes have been parsed")
120 (defvar jde-xref-cache nil
121 "A cache holding package information that will grow to size
122 `jde-xref-cache-size'")
124 (defvar jde-xref-subclasses nil
125 "A hashtable containing a list of which classes subclass which other
128 (defun jde-xref-pickle-hash (hash filename)
129 "Store HASH in the file FILENAME. The hash can be retrieved by
130 calling `jde-xref-unpickle-hash'."
131 (when (file-exists-p filename)
132 (delete-file filename))
134 (let ((buf (find-file-noselect (jde-normalize-path filename))))
136 (goto-char (point-min))
139 (maphash (lambda (key val)
141 (insert (concat "(" (prin1-to-string key) " . "
142 (prin1-to-string val) ")\n" ))))
148 (defun jde-xref-unpickle-hash (hash filename)
149 "Populate a hash created by loading the contents of FILENAME to HASH.
150 FILENAME must be created by `jde-xref-pickle-hash'"
151 (unless (file-exists-p filename)
152 (error (concat "Cannot unpickle - file " filename " does not exist. "
153 "The xref database may need to be recreated.")))
154 (dolist (item (with-temp-buffer
155 (insert-file-contents-literally filename)
156 (read (current-buffer))))
157 (puthash (car item) (cdr item) hash)))
159 (defun jde-xref-get-db-directory ()
160 (concat (jde-normalize-path jde-xref-db-base-directory) "/xrefdb"))
162 (defun jde-xref-guess-and-set-prefixes ()
163 (let ((prefixes (jde-xref-guess-prefixes)))
165 (setq jde-xref-store-prefixes prefixes))))
167 (defun jde-xref-guess-prefixes ()
168 "Try to guess what the prefixes are. Return the prefix list if
169 correctly guessed, otherwise return NULL. This works by looking at
170 the sourcepath, and putting all the top-level packages in the list,
171 where toplevel is defined as being a package from which all the
172 other packages branch out from."
174 (labels ((get-prefix (base-path package-path)
175 ;; if the directory contains just one directory (or two,
176 ;; one being CVS), then we can recurse down it to build
177 ;; up a proper prefix before the package tree really
179 (let ((files (remove-if-not
180 (lambda (dir) (and (file-directory-p
181 (concat base-path "/" package-path "/" dir)))
182 (not (equal "CVS" dir)))
184 (concat base-path "/" package-path)
186 (if (eq (length files) 1)
187 (get-prefix base-path (concat package-path "/"
189 (subst-char-in-string ?/ ?. package-path)))))
190 (when (and (eq major-mode 'jde-mode) jde-sourcepath)
191 (let ((first-prefix (car (split-string (jde-parse-get-package-name)
193 (dolist (path (remove-if-not (lambda (path) (file-exists-p path)) jde-sourcepath) prefixes)
194 (when (member first-prefix (directory-files path nil "[^.]$"))
195 (message (concat "path = " path))
196 (add-to-list 'prefixes (get-prefix path first-prefix))))))))
199 (defun jde-xref-make-xref-db ()
200 "Create a database of caller to callee (and the reverse) from the
201 classes in `jde-built-class-path' and store the data in the location
202 specified by `jde-xref-db-file'"
204 (when (null jde-xref-db-base-directory)
205 (error "The variable `jde-xref-db-base-directory' must be defined to make a caller database"))
206 (when (null jde-built-class-path)
207 (error "The variable `jde-built-class-path' must be defined to make a caller database"))
208 (when (null jde-xref-store-prefixes)
209 (error "The variable `jde-xref-store-prefixes' must be defined to make a caller database"))
210 (unless (file-exists-p (jde-xref-get-db-directory))
211 (make-directory (jde-xref-get-db-directory)))
212 (jde-xref-update-xref-db )
213 (message "Finished creating xref database")
214 (add-hook 'after-save-hook 'jde-xref-file-saved))
216 (defun jde-xref-substring-member (str prefixlist)
217 "Like `member' but works with strings and will return true if any of
218 the prefixes in PREFIXLIST match STR"
219 (member-if (lambda (item) (string=
220 (substring str 0 (min (length item)
224 (defun jde-xref-get-package-data ()
225 (let ((data (make-hash-table :test 'equal :size 10))
226 (caller-files (directory-files (jde-xref-get-db-directory)
228 (dolist (caller-file caller-files)
229 (let* ((package (mapconcat (lambda (x) x)
231 (split-string (car (last
232 (split-string caller-file
235 (package-data (jde-xref-load-package-hashes package)))
236 (puthash package package-data data)))
239 (defun jde-xref-update-xref-db (&optional only-classes)
240 (let ((package-data (if only-classes
241 (jde-xref-get-package-data)
242 (make-hash-table :test 'equal :size 10)))
243 (subclasses (make-hash-table :test 'equal :size 500)))
244 ;; Remove all occurances of classes to be updated from the package-data's caller-hashes
246 (maphash (lambda (package single-package-data)
247 (maphash (lambda (callee callers)
249 (remove-if (lambda (item)
253 (nth 0 single-package-data)))
254 (nth 0 single-package-data)))
256 (with-all-class-infos-when (info)
258 (or (null only-classes)
259 (jde-class-path-in-classes-p
260 class-file only-classes)))
261 (jde-xref-add-class-info-to-db info package-data
263 (setq jde-xref-parsed-classes nil)
264 (jde-xref-pickle-hash subclasses (jde-xref-get-subclass-file))
265 (setq jde-xref-subclasses subclasses)
266 (maphash (lambda (package data)
267 (jde-xref-pickle-hash (nth 0 data)
268 (jde-xref-get-caller-file package))
269 (jde-xref-pickle-hash (nth 1 data)
270 (jde-xref-get-interface-file package))
271 (jde-xref-pickle-hash (nth 2 data)
272 (jde-xref-get-member-file package))
273 (jde-xref-pickle-hash (nth 3 data)
274 (jde-xref-get-superclass-file package)))
276 (setq jde-xref-cache nil)))
278 (defun jde-xref-create-package-hashes (&optional fake)
279 "Returns a list of the three hashes that are in a package's data.
280 The hashes are for the caller-hash, the interface-hash, the
281 member-hash, and the superclass hash. FAKE determines if we are just
282 creating them so that there is something to check against. In those
283 circumstance we just create tiny hashes to conserve memory."
284 (list (make-hash-table :test 'equal :size (if fake 1 100))
285 (make-hash-table :test 'equal :size (if fake 1 20))
286 (make-hash-table :test 'equal :size (if fake 1 100))
287 (make-hash-table :test 'equal :size (if fake 1 20))))
289 (defun jde-xref-load-package-hashes (package)
290 (let ((data (jde-xref-create-package-hashes)))
291 (jde-xref-unpickle-hash (nth 0 data)
292 (jde-xref-get-caller-file package))
293 (jde-xref-unpickle-hash (nth 1 data)
294 (jde-xref-get-interface-file package))
295 (jde-xref-unpickle-hash (nth 2 data)
296 (jde-xref-get-member-file package))
297 (jde-xref-unpickle-hash (nth 3 data)
298 (jde-xref-get-superclass-file package))
301 (defun jde-xref-append-hash (key value hash)
302 "Like `puthash' but appends VALUE to the HASH at KEY"
303 (puthash key (append (gethash key hash) (if (listp value)
305 (list value))) hash))
307 (defun jde-xref-add-class-info-to-db (info package-data subclasses)
308 (message (concat "Parsing class " (jde-parse-class-extract-classname info)))
309 (add-to-list 'jde-xref-parsed-classes
310 (jde-parse-class-extract-classname info))
311 (let ((package (jde-parse-get-package-from-name
312 (jde-parse-class-extract-classname info))))
313 ;; If there is no existing package data
314 (unless (gethash package package-data)
316 ;; package-data's values are (caller-hash
317 ;; interface-hash method-and-field-hash)
318 (jde-xref-create-package-hashes)
320 (destructuring-bind (caller-hash interface-hash
321 method-and-field-hash superclass-hash)
322 (gethash package package-data)
323 (puthash (jde-parse-class-extract-classname info)
324 (jde-parse-class-extract-interfaces info)
326 (puthash (jde-parse-class-extract-classname info)
327 (append (jde-parse-class-extract-method-signatures info)
328 (jde-parse-class-extract-field-signatures info))
329 method-and-field-hash)
330 (puthash (jde-parse-class-extract-classname info)
331 (jde-parse-class-extract-superclass info)
333 (jde-xref-append-hash
334 (jde-parse-class-extract-superclass info)
335 (jde-parse-class-extract-classname info) subclasses)
336 (dolist (call (nreverse
337 (jde-parse-class-extract-method-calls info)))
338 (let ((calls (car call))
339 (called (cadr call)))
340 (if (or (not jde-xref-store-prefixes)
342 (jde-xref-substring-member (car calls)
343 jde-xref-store-prefixes)
344 (jde-xref-substring-member (car called)
345 jde-xref-store-prefixes)))
346 (let* ((dqcalled (list (car called)
349 (jde-parse-get-unqualified-name
351 ;; We don't want to need to
352 ;; know the constructor args
353 ;; for anonymous classes
354 (unless (jde-xref-is-class-anonymous (car called))
355 (mapcar 'jde-parse-get-unqualified-name
357 (called-package (jde-parse-get-package-from-name
359 ;; Create the package data if needed
360 (unless (gethash called-package package-data)
361 (puthash called-package (jde-xref-create-package-hashes)
363 (let* ((called-package-hashes
364 (gethash called-package package-data))
365 (called-package-caller-hash
366 (car called-package-hashes)))
367 ;; add things to the table - making sure there are no duplicates
369 (if (member calls (gethash
371 called-package-caller-hash))
372 (gethash dqcalled called-package-caller-hash)
375 called-package-caller-hash)))
376 called-package-caller-hash)))))))))
378 (defun jde-xref-class-and-token-to-signature (class token)
379 (let ((ttype (semantic-token-type token))
380 (tclass (semantic-token-token token))
381 (tname (semantic-token-name token)))
384 (if (equal tname (jde-parse-get-unqualified-name class))
387 (when (eq tclass 'function)
388 (if (or (not ttype) (equal ttype "void"))
390 (jde-parse-get-unqualified-name ttype)))
391 (if (eq tclass 'function)
392 (mapcar (lambda (arg)
393 (jde-parse-get-unqualified-name
394 (semantic-token-type arg)))
395 (semantic-token-function-args token))
396 (list (jde-parse-get-unqualified-name ttype))))))
398 (defun jde-xref-get-current-class ()
399 (let ((package-name (jde-parse-get-package-name)))
400 (concat package-name (when package-name ".") (replace-regexp-in-string "\\." "$" (jde-parse-get-class-at-point)))))
402 (defun jde-xref-get-current-signature ()
404 (semantic-token-token (semantic-current-nonterminal))
405 '(function variable))
406 (error "The cursor must be in a function or class variable to get the callers"))
407 (jde-xref-class-and-token-to-signature
408 (jde-xref-get-current-class)
409 (semantic-current-nonterminal)))
412 (defun jde-xref-first-caller (strict)
413 "Put the list of who calls the current function on the stack and
414 display the first caller. Subsequent callers are displayed through
415 `jde-xref-show-next-caller'. STRICT should be true if the callers of
416 interfaces to a function, or calls to a superclass which may result in
417 a virtual function call to the subclass should not be considered. In
418 other words, if STRICT is true, then only calls that are definitely to
419 the requested function are considered."
421 (jde-xref-load-subclasses-table-if-necessary)
422 (setq jde-xref-stack (jde-xref-get-callers
423 (jde-xref-get-current-signature) strict))
424 (jde-xref-next-caller))
426 (defun jde-xref-goto-caller (caller)
427 (jde-find-class-source (car caller))
428 (goto-line (nth 4 caller)))
431 (defun jde-xref-next-caller ()
432 "If there are items still on the caller stack, pop the first one off
435 (if (not jde-xref-stack)
436 (message "No more calls")
437 (unless (listp (car jde-xref-stack))
438 (pop jde-xref-stack)) ;; skip over called classname
439 (jde-xref-goto-caller (pop jde-xref-stack))))
442 (defun jde-xref-load-subclasses-table-if-necessary ()
443 (unless jde-xref-subclasses
444 (setq jde-xref-subclasses (make-hash-table :test 'equal :size 500))
445 (jde-xref-unpickle-hash jde-xref-subclasses
446 (jde-xref-get-subclass-file))
447 ;; if subclasses were empty, then it's the first time this is run,
448 ;; so do our one-time initializations
449 (add-hook 'after-save-hook 'jde-xref-file-saved)))
451 (defun jde-xref-signature-to-string (sig)
452 (concat (or (nth 3 sig) "void") " " (cadr sig) "."
453 (if (equal (nth 2 sig) "<init>")
454 (jde-parse-get-unqualified-name (cadr sig))
456 (when (eq (car sig) 'function)
458 (mapconcat (lambda (x) x) (nth 4 sig) ",") ")"))))
460 (defun jde-xref-find-package-in-cache (package cache)
462 (if (equal (caar cache) package)
464 (jde-xref-find-package-in-cache package (cdr cache)))))
466 (defun jde-xref-get-caller-file (package)
467 (concat (jde-xref-get-db-directory) "/" package "-caller"))
469 (defun jde-xref-get-interface-file (package)
470 (concat (jde-xref-get-db-directory) "/" package "-interfaces"))
472 (defun jde-xref-get-member-file (package)
473 (concat (jde-xref-get-db-directory) "/" package "-members"))
475 (defun jde-xref-get-superclass-file (package)
476 (concat (jde-xref-get-db-directory) "/" package "-superclasses"))
478 (defun jde-xref-get-subclass-file ()
479 (concat (jde-xref-get-db-directory) "/subclasses"))
481 (defun jde-xref-find-or-create-package-in-cache (package)
482 (unless jde-xref-db-base-directory
483 (error "The variable `jde-xref-db-base-directory' must be specified to load the xref db"))
484 (if (file-exists-p (jde-xref-get-caller-file package))
485 (or (jde-xref-find-package-in-cache package jde-xref-cache)
486 ;; Or we need to get the new package and put it in the cache
487 (let ((data (jde-xref-load-package-hashes package)))
488 (setq jde-xref-cache (cons (cons package data)
489 (if (> (length jde-xref-cache)
494 (jde-xref-create-package-hashes t)))
496 (defun jde-xref-get-caller-hash (package)
497 (nth 0 (jde-xref-find-or-create-package-in-cache package)))
499 (defun jde-xref-get-interface-hash (package)
500 (nth 1 (jde-xref-find-or-create-package-in-cache package)))
502 (defun jde-xref-get-member-hash (package)
503 (nth 2 (jde-xref-find-or-create-package-in-cache package)))
505 (defun jde-xref-get-superclass-hash (package)
506 (nth 3 (jde-xref-find-or-create-package-in-cache package)))
508 (defun jde-xref-get-basic-caller (sig)
509 (gethash (cdr sig) (jde-xref-get-caller-hash (jde-parse-get-package-from-name
512 (defun jde-xref-get-members (class)
513 (gethash class (jde-xref-get-member-hash (jde-parse-get-package-from-name
516 (defun jde-xref-get-superclass (class)
517 (gethash class (jde-xref-get-superclass-hash (jde-parse-get-package-from-name
520 (defun jde-xref-is-class-anonymous (class)
521 (string-match "\\$[0-9]+$" class))
523 (defun jde-xref-is-caller-anonymous-class (caller)
524 (jde-xref-is-class-anonymous (nth 0 caller)))
526 (defun jde-xref-is-sig-anonymous-class (sig)
527 (jde-xref-is-class-anonymous (nth 1 sig)))
529 (defun jde-xref-get-callers (sig &optional strict)
530 (let ((typesig (car sig))
531 (classname (cadr sig)))
533 ;; if we're an anonymous class, then we want to see where we are
534 ;; created, since it kind of goes along with usage of the function.
535 (when (jde-xref-is-sig-anonymous-class sig)
536 (jde-xref-get-basic-caller (list typesig classname "<init>" nil nil)))
538 (jde-xref-get-basic-caller sig)
543 (let* ((sig `(,typesig ,classname ,@(cddr sig)))
544 (callers-for-classname (jde-xref-get-basic-caller sig)))
545 (when callers-for-classname
546 (cons classname callers-for-classname)))) ;; include classname in the usage list
547 (jde-xref-get-subs classname sig (jde-xref-get-supers classname nil))))))))
550 (defun jde-xref-get-supers (classname collect)
551 (mapc (lambda (super)
552 (unless (member super collect)
553 (setq collect (jde-xref-get-supers super (cons super collect)))))
554 (let* ((package (jde-parse-get-package-from-name classname))
555 (superclass (jde-xref-get-superclass classname))
556 (superinterfaces (gethash classname (jde-xref-get-interface-hash package))))
558 (cons superclass superinterfaces)
563 (defun jde-xref-get-subs (classname sig collect)
564 (mapc (lambda (subclass)
565 (unless (or (member subclass collect) (member (cddr sig) (jde-xref-get-members subclass)))
566 (setq collect (jde-xref-get-subs subclass sig (cons subclass collect)))))
567 (gethash classname jde-xref-subclasses))
571 (defun jde-xref-notify (widget child &optional event)
572 (jde-xref-goto-caller (widget-get widget :caller)))
574 (defun jde-xref-caller-to-sig (caller)
575 (list 'function (nth 0 caller) (nth 1 caller) (when (nth 2 caller) (jde-parse-get-unqualified-name (nth 2 caller)))
576 (mapcar 'jde-parse-get-unqualified-name (nth 3 caller))))
578 (defun jde-xref-tree-get-children (sig)
583 (let ((caller-sig (jde-xref-caller-to-sig caller)))
587 :tag ,(jde-xref-signature-to-string caller-sig)
591 :notify jde-xref-notify)
592 :dynargs 'jde-xref-tree-get-children-from-tree
595 (list 'tree-widget :tag caller))) ;; class for next set of usages
596 (jde-xref-get-callers sig))))
598 (defun jde-xref-tree-get-children-from-tree (tree)
599 (jde-xref-tree-get-children (widget-get tree :sig)))
602 (defun jde-xref-display-call-tree (strict)
603 "Display an interactive call tree of which function call the current
604 function, which can be expanded outward. STRICT should be true if
605 the callers of interfaces to a function, or calls to a superclass
606 which may result in a virtual function call to the subclass should
607 not be considered. In other words, if STRICT is true, then only
608 calls that are definitely to the requested function are considered. "
610 (jde-xref-load-subclasses-table-if-necessary)
611 (let* ((sig (jde-xref-get-current-signature))
612 (buf (get-buffer-create (concat "JDE call graph for "
613 (jde-xref-signature-to-string
615 (switch-to-buffer buf)
617 (widget-create 'tree-widget
618 :tag (jde-xref-signature-to-string sig)
619 :dynargs 'jde-xref-tree-get-children-from-tree
622 (use-local-map widget-keymap)
625 (defun jde-xref-get-class-variables (class-token)
626 (mapcan (lambda (token)
627 (when (eq (semantic-token-token token) 'variable)
629 (semantic-nonterminal-children class-token)))
632 (defun jde-xref-list-uncalled-functions (strict)
633 "Displays a simple list of function that are never called, at least
634 not directly. Do not assume that this means this code can never be
635 reached, since reflection could always call any method. Use this list
636 and your best judgement to figure out what are good candidates for
637 code cleanup. STRICT should be true if the callers of interfaces to a
638 function, or calls to a superclass which may result in a virtual
639 function call to the subclass should not be considered. In other
640 words, if STRICT is true, then only calls that are definitely to the
641 requested function are considered. This function could take a
642 while. If it does, you might want to consider increasing
643 `jde-xref-cache-size'."
645 (jde-xref-load-subclasses-table-if-necessary)
647 (flet ((get-unused-string (token)
648 (goto-char (semantic-token-start token))
649 (unless (jde-xref-get-callers
650 (jde-xref-class-and-token-to-signature
651 (jde-xref-get-current-class) token) strict)
652 (list (jde-xref-signature-to-string
653 (jde-xref-class-and-token-to-signature
654 (jde-xref-get-current-class) token))))))
655 (let ((uncalled-methods
656 (mapcan 'get-unused-string
657 (semantic-find-nonterminal-by-token 'function
660 (unreferenced-variables
661 (mapcan 'get-unused-string
662 (mapcan 'jde-xref-get-class-variables
663 (semantic-find-nonterminal-by-type "class"
666 (outbuf (get-buffer-create "Unreferenced Methods and Members")))
667 (switch-to-buffer outbuf)
669 (insert "The following is a list of methods and members that are\n")
670 (insert "uncalled directly by any Java classes that are in the\n")
671 (insert "following locations: \n")
672 (insert (mapconcat (lambda (x) x) jde-built-class-path ", "))
677 (insert "Unreferenced methods:\n")
678 (insert (mapconcat (lambda (x) x) uncalled-methods "\n")))
679 (insert "There are no uncalled methods\n\n"))
680 (if unreferenced-variables
682 (insert "\n\nUnreferenced class variables:\n")
683 (insert (mapconcat (lambda (x) x) unreferenced-variables "\n")))
684 (insert "\n\nThere are no unreferenced variables\n\n"))
688 (defun jde-xref-remove-classes-from-subclasses-table (classes)
689 (maphash (lambda (key value)
691 (remove-if (lambda (item)
692 (member item classes)) value)
693 jde-xref-subclasses))
694 jde-xref-subclasses))
697 (defun jde-xref-update (&rest ignored)
698 "Update the caller table after a recompile. This can be called by
699 the user when they recompile outside of emacs. It will update the
700 call list of all files modified in emacs"
702 (message "Updating xref tables")
703 (when jde-xref-modified-classes
704 (jde-xref-remove-classes-from-subclasses-table
705 jde-xref-modified-classes)
706 (jde-xref-update-xref-db jde-xref-modified-classes)
707 (message "Finished updateing xref database"))
708 (setq jde-xref-modified-classes nil))
710 (defun jde-xref-file-saved ()
711 (when (eq major-mode 'jde-mode)
712 (setq jde-xref-modified-classes
713 (append jde-xref-modified-classes
714 (mapcar (lambda (class-token)
715 (concat (jde-parse-get-package-name)
716 (when (jde-parse-get-package-name) ".")
717 (semantic-token-name class-token)))
718 (semantic-find-nonterminal-by-type
719 "class" (current-buffer) t))))))
722 (defun jde-xref-customize ()
723 "Display the customization buffer for the xref package."
725 (customize-group "jde-xref"))
727 (global-set-key (kbd "C-c C-v a") 'jde-xref-first-caller)
728 (global-set-key (kbd "C-c C-v n") 'jde-xref-next-caller)
731 ;; Register and initialize the customization variables defined
733 (jde-update-autoloaded-symbols)
737 ;; $Log: jde-xref.el,v $
738 ;; Revision 1.24 2004/06/06 14:19:23 ahyatt
739 ;; Fixed bug with jde-xref-next-caller - discovery and fix by Raul Acevedo
741 ;; Revision 1.23 2003/11/07 04:27:14 ahyatt
742 ;; Invalid hooks removed
744 ;; Revision 1.22 2003/10/17 03:42:57 ahyatt
745 ;; Speed improvements to jde-xref. Thanks to Suraj Acharya.
747 ;; Revision 1.21 2003/10/09 05:58:55 ahyatt
748 ;; David Ponce's fixes pertaining to the upcoming Semantic 2.0, plus
749 ;; fixes of my own to get his changes working with the existing code.
751 ;; Revision 1.20 2003/09/27 04:53:35 ahyatt
752 ;; Put in Suraj Acharya's fixes, fixed a no-prefix bug (but still don't allow no prefixes)
754 ;; Revision 1.19 2003/09/02 22:05:43 ahyatt
755 ;; We weren't doing any subclass checks! Fixed this problem, then fixed
756 ;; a problem where the subclass checks caused an infinite recursion
759 ;; Revision 1.18 2003/07/15 05:19:47 ahyatt
760 ;; Fix for bug where users could not find the callers to interface functions
762 ;; Revision 1.17 2003/07/09 06:11:20 ahyatt
763 ;; Made jde-xref-store-prefixes non-optional. I think if we didn't do
764 ;; this, most people would leave it blank, therefore significantly
765 ;; impacting both size of the database and the time and memory it takes
768 ;; Revision 1.16 2003/05/07 04:38:45 ahyatt
769 ;; Uncommenting jde-update-autoloaded-symbols
771 ;; Revision 1.15 2003/05/06 06:50:55 ahyatt
772 ;; Fixes recent regression with default-directory not getting set back after making the xref db (if the jde-built-class-path contains jars)
774 ;; Revision 1.14 2003/05/03 09:00:53 paulk
775 ;; Fixed bug in jde-xref-update-xref-db that cause incorrect resolution
776 ;; of db path specified relative to project file.
778 ;; Revision 1.13 2003/03/08 06:32:02 ahyatt
779 ;; Simplified using new jde-class functionality
781 ;; Revision 1.12 2003/01/07 15:27:37 ahyatt
782 ;; Needed to clear the cache after updating.
784 ;; Revision 1.11 2003/01/02 05:10:20 ahyatt
785 ;; Added ability for calls to superclasses to show up (under non-strict
786 ;; mode) as calls to the subclass. So if class B inherits from class A,
787 ;; then a call to a method on a class of type A (at compile time), may in
788 ;; fact call a method on B at runtime. This is turned off in STRICT mode.
790 ;; Revision 1.10 2002/12/18 04:09:15 ahyatt
791 ;; Fixes a usability problem with call-trees, and fixes a bug where some
792 ;; classes never get added to the xref database
794 ;; Revision 1.9 2002/12/06 03:24:45 ahyatt
795 ;; Fixed bug in call-tree, where no expansion could take place after the
796 ;; 2nd level. Also renamed the argument to jde-xref-goto-caller, which takes
797 ;; a caller, not a sig.
799 ;; Revision 1.8 2002/12/04 04:29:19 ahyatt
800 ;; Got the call-tree to finally work. Also made some adjustements for
801 ;; anonymous classes. These adjustments probably will disappear with
802 ;; some later rework I have planned.
804 ;; Revision 1.6 2002/12/01 02:50:48 ahyatt
805 ;; Major revision - I realized that the previous version had neglected to
806 ;; factor in subclasses of a class when computing the callers to a
807 ;; function. I added this functionality, which meant I had to now keep
808 ;; track of all subclasses and variables and functions of each class
809 ;; (because we have to walk up the subclass tree until a function or
810 ;; variable gets overriden). Also, I simultaneously totally redid the
811 ;; database storage. Instead of storing the result in a huge hash table,
812 ;; we now split the file into packages which are loaded on demand and
813 ;; cached for later use. I removed user visible variables
814 ;; `jde-xref-db-file' and `jde-xref-interface-file' and replaced it with
815 ;; `jde-xref-db-base-directory', a directory on which an "xrefdb"
816 ;; directory is created which stores everything necessary. BTW, there is
817 ;; a reason I'm not using the beanshell to get this information -
818 ;; basically I don't see how to handle arrays properly via reflection,
819 ;; and without getting the array information I need from signatures, I
820 ;; can't match the signatures I'm getting from the class files directly.
822 ;; Revision 1.5 2002/11/25 00:42:34 ahyatt
823 ;; Polished jde-xref-list-uncalled-functions, making the text make more
824 ;; sense, the buffer read-only, and converting "<init>" functions back to
825 ;; their proper names.
827 ;; Revision 1.4 2002/11/21 04:26:33 ahyatt
828 ;; Changed my e-mail address to andy_jde@thehyatts.net
830 ;; Revision 1.3 2002/11/21 04:18:41 paulk
831 ;; These packages, when autoloaded, now register and initialize the customization variables
832 ;; that they define to the values specified in the current project file.
834 ;; Revision 1.2 2002/11/21 04:03:47 ahyatt
835 ;; Fixed a bug in jde-parse-class where two functions had the same
836 ;; definition. The fix involved renamed a few classes to keep
837 ;; consistency. jde-xref had to change as well.
839 ;; Removed a (newline) function call in jde-xref and replaced it with a "\n"
841 ;; In jde-xref, rewrote the parts of jde-xref-make-db-from-path which
842 ;; dealt with keeping track of the already parsed classes. Previous
843 ;; solution was really kludgey, this solution is only somewhat kludgey.
844 ;; I'm still thinking about this problem.
846 ;; Revision 1.1 2002/11/18 07:02:18 paulk
850 ;; end of jde-xref.el