New symbol property 'definition-type' used by 'find-function'.

* lisp/emacs-lisp/find-func.el (find-function-search-for-symbol):
Look for new property 'definition-type' on the symbol.
* doc/lispref/symbols.texi (Standard Properties): Add 'Definition-type'.
* doc/lispref/functions.texi (Defining Functions):
* doc/lispref/tips.texi (Coding Conventions):
* doc/misc/ert.texi (How to Write Tests):
Add cross reference to new property 'definition-type'.
* etc/NEWS: Announce new symbol property 'definition-type'.

Thanks to Eli Zaretskii for reviewing this change.
This commit is contained in:
Stephen Gildea 2025-01-12 20:39:02 -08:00
parent c98d9e8bf5
commit e6591b549f
6 changed files with 90 additions and 15 deletions

View file

@ -752,9 +752,9 @@ commands, such as @kbd{C-h f}, which present in the @file{*Help*}
buffer a button to jump to the function's definition, might be unable
to find the source code because generating a function dynamically
usually looks very different from the usual static calls to
@code{defun}. You can make the job of finding the code which
@code{defun}. You can make the job of finding the code that
generates such functions easier by using the @code{definition-name}
property, @pxref{Standard Properties}.
or @code{definition-type} property, @pxref{Standard Properties}.
@cindex override existing functions
@cindex redefine existing functions

View file

@ -536,10 +536,18 @@ Do not set them directly; they are managed by @code{defcustom} and
related functions. @xref{Variable Definitions}.
@cindex @code{definition-name} (symbol property)
@cindex @code{definition-type} (symbol property)
@item definition-name
This property is used to find the definition of a symbol in the source
code, when it might be hard to find the definition by textual search
of the source file. For example, a @code{define-derived-mode}
@itemx definition-type
These properties help find the definition of a symbol in the source
code when it might be hard to find the definition by textual search
of the source file.
The Emacs Help commands such as @kbd{C-h f} (@pxref{Help,,,
emacs, The GNU Emacs Manual}) use these properties to show the definition
of a symbol via a button in the @file{*Help*} buffer where the
symbol's documentation is shown.
For example, a @code{define-derived-mode}
(@pxref{Derived Modes}) might define a mode-specific function or a
variable implicitly; or your Lisp program might generate a run-time
call to @code{defun} to define a function (@pxref{Defining
@ -548,10 +556,56 @@ 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 @code{define-derived-mode}, the value of this
property of the functions and variables it defines should be the mode
symbol. The Emacs Help commands such as @kbd{C-h f} (@pxref{Help,,,
emacs, The GNU Emacs Manual}) use this property to show the definition
of a symbol via a button in the @file{*Help*} buffer where the
symbol's documentation is shown.
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 @code{ert-deftest}
(@pxref{,,,ert, ERT: Emacs Lisp Regression Testing}) where the code
is boiler plate and only varying data need to be passed in.
In such cases, the @code{definition-type} property of the symbol can
be a symbol that has an entry in @code{find-function-regexp-alist}
telling how to find the definition of symbols of this type.
In the example of a macro defining calls to @code{ert-deftest},
the macro could put the property @code{definition-type} on each
test defined. The file defining the macro would also define a
definition-finding function or regexp and add it to
@code{find-function-regexp-alist} after that variable is loaded.
Here is an example using a function to find the definition:
@example
@group
(defmacro define-foo-test (data)
"Define a test of the foo system using DATA."
(declare (debug (&rest sexp)))
(let ((test-name (intern (concat ...))))
`(progn
(put ',test-name 'definition-type 'foo-test-type)
(ert-deftest ,test-name ()
,(concat "Test foo with " ...)
...))))
@end group
@group
(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."
(save-match-data
(let ((regexp ...))
(save-restriction
(widen)
(goto-char (point-min))
(re-search-forward regexp nil t)))))
@end group
@group
(with-eval-after-load "find-func"
(add-to-list
'find-function-regexp-alist
'(foo-test-type . foo-find-test-def-function)))
@end group
@end example
@item disabled
If the value is non-@code{nil}, the named function is disabled as a

View file

@ -226,6 +226,10 @@ The macro should receive the name to be
defined as the first argument. That will help various tools find the
definition automatically. Avoid constructing the names in the macro
itself, since that would confuse these tools.
If your macro cannot be written in this style, the macro can still
help these tools find the defining call by putting the property
@code{definition-name} or @code{definition-type} on the name.
@xref{Standard Properties}.
@item
In some other systems there is a convention of choosing variable names

View file

@ -518,9 +518,14 @@ can type @code{ert-deftest} forms in a buffer and evaluate them there
with @code{eval-defun} or @code{compile-defun}, or you can save the
file and load it, optionally byte-compiling it first.
Just like @code{find-function} is only able to find where a function
was defined if the function was loaded from a file, ERT is only able
to find where a test was defined if the test was loaded from a file.
Just like @code{find-function} is able to find where a function was
defined only if the function was loaded from a file, ERT is able to
find where a test was defined only if the test was loaded from a file.
If the test definition is generated by a macro, the macro may want to
help ERT find the defining call to the macro by putting the property
@code{definition-type} on the test name.
@xref{Standard Properties,,,elisp, GNU Emacs Lisp Reference Manual}.
@menu

View file

@ -1165,6 +1165,13 @@ It offers a more concise way to create a completion table with metadata.
+++
** 'all-completions' and 'unintern' no longer support old calling conventions.
+++
** New symbol property 'definition-type' used by 'find-function' and friends.
Macros that define an object in a way that makes the object's name and
the macro call site defining the object hard to associate can put the
property 'definition-type' on the object's name to provide instructions
for finding the definition.
* Changes in Emacs 31.1 on Non-Free Operating Systems

View file

@ -400,9 +400,12 @@ See `find-library' for more details."
Visit the library in a buffer, and return a cons cell (BUFFER . POSITION),
or just (BUFFER . nil) if the definition can't be found in the file.
If TYPE is nil, look for a function definition.
Otherwise, TYPE specifies the kind of definition,
and it is interpreted via `find-function-regexp-alist'.
If TYPE is nil, look for a function definition,
otherwise, TYPE specifies the kind of definition.
If SYMBOL has a property `definition-type',
the property value is used instead of TYPE.
TYPE is interpreted via `find-function-regexp-alist'.
The search is done in the source for library LIBRARY."
(if (null library)
(error "Don't know where `%s' is defined" symbol))
@ -410,6 +413,8 @@ The search is done in the source for library LIBRARY."
;; that defines something else.
(while (and (symbolp symbol) (get symbol 'definition-name))
(setq symbol (get symbol 'definition-name)))
(setq type (or (get symbol 'definition-type)
type))
(if (string-match "\\`src/\\(.*\\.\\(c\\|m\\)\\)\\'" library)
(find-function-C-source symbol (match-string 1 library) type)
(when (string-match "\\.el\\(c\\)\\'" library)