Tools such as Emacs’s built-in help command C-h f (see Help in The GNU Emacs Manual) can find the definition site of functions
and other Lisp objects in the source code. To do this, they use the
variable find-function-regexp-alist.
The alist find-function-regexp-alist associates object types with
a regexp or a function that finds the definition of that object in its
source file. Each element’s car is a symbol that describes the
type of object, or nil, which means a function defined with
defun. Each element’s cdr can be one of the following:
car is a regexp (or function that returns
one) and the cdr is form-matcher: a function that creates a
matcher for macro-expanded forms.
A regexp string is actually a format string, and %s will be
substituted with the name of the symbol we are looking for.
A function will be called with one argument, the (symbol for) the object we are searching for.
The form-matcher function in a cons cell value is called with one
argument (the symbol being sought) and should return a function; that
function should take a form and return non-nil if the form
defines the sought symbol. This is useful for finding definitions that
are created by expansion of macros.
If the function to be found is defined by a macro, it may be hard for
Emacs to find the definition site in the source code. A macro call may
have an unexpected look to it, and find-function-regexp-alist
will fail to identify the definition.
For example, a define-derived-mode (see Defining Derived Modes) might
define a mode-specific function or a variable implicitly; or your Lisp
program might generate a run-time call to defun to define a
function. In these and similar cases, the definition-name
property of the symbol should be another symbol whose definition can be
found by textual search and whose code defines the original symbol. In
the example with define-derived-mode, the value of this property
of the functions and variables it defines should be the mode symbol.
In some cases, the definition cannot be found by looking for the
definition of another symbol. For example, a test file might use a
macro to generate calls to ert-deftest (see How to Write
Tests in ERT: Emacs Lisp Regression Testing) where the code is
boiler plate and only varying data need to be passed in. In such cases,
the find-function-type-alist property of the symbol can be an
alist that augments find-function-regexp-alist telling how to
find the definition of symbols of this type.
The find-function-regexp-alist property is most easily maintained
with the convenience function find-function-update-type-alist.
Update property find-function-type-alist of symbol with
a new element containing key type and value variable.
In the example of a macro defining calls to ert-deftest,
the macro could put the property find-function-type-alist on each
test defined, associating ert--test (the internal type of ERT
tests) with the name of a regexp or function that can find the correct
macro call. The file defining the macro would also have to provide that
definition-finding function or regexp.
Here is an example using a function to find the definition:
(defmacro define-foo-test (data)
"Define a test of the foo system using DATA."
(declare (debug (&rest sexp)))
(let ((test-name (intern (concat ...))))
`(progn
(find-function-update-type-alist
',test-name 'ert--test 'foo-find-test-def-function)
(ert-deftest ,test-name ()
,(concat "Test foo with " ...)
...))))
(defun foo-find-test-def-function (test-name)
"Search for the `define-foo-test' call defining TEST-NAME.
Return non-nil if the definition is found."
(let ((regexp ...))
(re-search-forward regexp nil t)))