This package creates a call-tree – a data structure saying which function calls which function.
Use ‘M-x simple-call-tree-analyze’ to run it on a buffer. This uses ‘font-lock-function-name’ to identify function names. Therefore, you might have to wait for a bit until the stealth font lock has actually fontified all of the buffer, not only the visible part. Alternatively you might want to call ‘jit-lock-fontify-now’ explicitly (e.g. by inserting `(when jit-lock-mode (jit-lock-fontify-now))’ right after `(interactive)’ in ‘simple-call-tree-alist’ below), especially if you use jit-lock-mode and your Jit Lock Stealth Time is “never” (what is the default, I think).
For CPerl, some keywords like -f are also hilighted using font-lock-function-name. In order to exclude these, use ‘M-x simple-call-tree-analyze-perl’.
For any kind of literate programs consider calling ‘simple-call-tree-analyze’ on the "tangled" code.
The output in ielm (see InferiorEmacsLispMode):
ELISP> simple-call-tree-alist
(("DoShowVisitors")
("AddUserToRecentVisitors" "T" "GetParam" "UpdateRecentVisitors")
("UpdateRecentVisitors" "T" "ReadRecentVisitors" "WriteRecentVisitors")
("WriteRecentVisitors" "T" "WriteStringToFile")
("ReadRecentVisitors" "T" "ReadFile")
("DoShowVersion" "T" "GetHeader" "GetCommonFooter")
...
To see which functions are called at all:
ELISP> (setq simple-call-tree-used (mapcar 'car (simple-call-tree-invert simple-call-tree-alist)))
("DoOtherRequest" "DoBrowseRequest" "InitRequest" "DoCacheBrowse" "InitLinkPatterns" ...
To see which functions are not called:
ELISP> (set-difference (mapcar 'car simple-call-tree-alist) simple-call-tree-used)
("DoWikiRequest")
Anything is a candidate selection framework.
Start with ‘M-x anything-simple-call-tree’, narrow the list by typing some patterns(multiple patterns are space-delimited string), select with up/down/pgup/pgdown/C-p/C-n/C-v/M-v, choose with enter,
With C-z function definitions (by rotation) are displayed without quitting anything session.
Hm, could be that the last function is not analyzed correctly… – AlexSchroeder
Somebody make it write out dotty files please! :-) (see http://www.research.att.com/sw/tools/graphviz/)
For a simple graphviz solution (with dot), see my suggestion below in the Visualization part – PeterTury?
I can’t get this to work properly for me. It will only recognize functions if they have already been displayed in a window. I suppose that emacs only updates the text-properties when it needs to (i.e. when the text is displayed in a window). Is there any way to force emacs to evaluate the text properties of a buffer? – Aleblanc
Aleblanc, please check my suggestion with ‘jit-lock-fontify-now’ above – PeterTury?
See ‘font-lock-support-mode’. Instant fontification could be slow for large buffers, though. That’s why it is not usually used as a source of syntax information. - anon
As we need to call ‘jit-lock-fontify-now’, why not adding it in simple-call-tree-analyse, just before the ‘let’ ? – DanielDehennin
Shouldn’t you call ‘font-lock-fontify-buffer’ if you want the buffer to be fontified right now? – LennartBorgman
To show a pretty-printed representation of functions and their callers, you could use something like:
(defun simple-call-tree-list-functions-and-callers ()
"List functions and callers in `simple-call-tree-alist'."
(interactive)
(let ((list (simple-call-tree-invert simple-call-tree-alist)))
(switch-to-buffer (get-buffer-create "*simple-call-tree*"))
(erase-buffer)
(dolist (entry list)
(let ((callers (mapconcat #'identity (cdr entry) ", ")))
(insert (car entry) " is called by "
(if (string= callers "")
"no functions."
callers)
".\n")))))
Alternatively, if you wanted to list which callers and the functions they call, you could use something like:
(defun simple-call-tree-list-callers-and-functions ()
"List callers and functions in `simple-call-tree-alist'."
(interactive)
(let ((list simple-call-tree-alist))
(switch-to-buffer (get-buffer-create "*simple-call-tree*"))
(erase-buffer)
(dolist (entry list)
(let ((functions (mapconcat #'identity (cdr entry) ", ")))
(insert (car entry) " calls "
(if (string= functions "")
"no functions"
functions)
".\n")))))
A simple (and rather manual) way (using http://www.graphviz.org/) can be:
‘jit-lock-fontify-now’)‘simple-call-tree-analyze’‘sct-dot’ (see below)‘M-:’): `(insert (sct-dot))’Evaluate this expression (C-M-x) to create function ‘sct-dot’:
(defun sct-dot ()
"Generate dot file for graphviz from `simple-call-tree-alist'.
After calling `simple-call-tree-analyze', use `sct-dot' in an
empty buffer via `(insert (sct-dot))'.
Then save the file as \"my-file.dot\" and run
\"dot -Tjpg /path/to/my-file.dot -o result.jpg\" from command line."
(concat "digraph G {\n" ;; default beginning of a dot file
(mapconcat 'identity ;; end each line with a ";"
(mapcar
(lambda (defun-list)
"Called for each elemet (list) of `simple-call-tree-alist',
create all the 'caller -> callee;' strings."
(let ((caller (car defun-list))
(callees (cdr defun-list)))
(if (null callees)
(concat "\"" caller "\"")
(mapconcat (lambda (callee)
"Called with each callee, create 'caller -> callee' pairs."
(concat "\"" caller "\"" " -> " "\"" callee "\""))
callees
";\n"))))
simple-call-tree-alist)
";\n")
";\n}"))
The following library is based on simple-call-tree.el and provides a major mode for displaying and navigating the call tree. You can invert the tree, change the depth, narrow to a particular branch, perform query replacements on functions (useful for refactoring), and it also works with follow mode if you have that installed (http://www.damtp.cam.ac.uk/user/sje30/emacs/fm.el).
Feel free to help develop it further, here is the github page: https://github.com/vapniks/simple-call-tree-ext