9

I had a look over the weekend, and I cannot see an easy way to check whether a function is advised.

I must be missing something.

HELP! :)

Drew
  • 75,699
  • 9
  • 109
  • 225
Realraptor
  • 1,253
  • 6
  • 17
  • 6
    `M-x describe-function` aka `C-h f` – lawlist Jan 08 '18 at 17:47
  • 4
    `advice-add`/`advice-remove` updates function's documentation accordingly, thus `C-h f` works. From Lisp, take a look at `advice-mapc` and `advice-member-p`. – xuchunyang Jan 08 '18 at 18:15
  • 1
    I edited your question. 1. If you are not asking about one of the two aspects (interactive, from Lisp) then please delete that part. 2. It's not clear which advice system you are asking about, new (e.g. `advice-add`) or the old (e.g., `defadvice`). – Drew Jan 08 '18 at 19:16

2 Answers2

11

As lawlist correctly points out in a comment, the Emacs Help system, invoked via C-hfNAMERET (M-xdescribe-functionRETNAMERET) in this case, is a quick way to interactively check whether there is any advice currently active on the function named NAME. This is doubly convenient because the name of the advising function is hyperlinked as a button, allowing you to jump to and back from its definition.

To programmatically determine whether the function definition of a particular symbol (e.g. fn) contains any advice[1], you can write:

(advice--p (advice--symbol-function 'fn))

Note, however, that the double hyphens indicate this is an internal API and thus subject to breaking change.

[1]: This assumes the new nadvice.el system in Emacs 24; see (elisp) Porting old advice.

Basil
  • 12,019
  • 43
  • 69
  • I'm perpetually surprised by how many Emacs things seem to only have an interactive human-level solution and how even more common it is for answers to only mention those solutions - "here's how you as a human user can check/do this" - as if a human wanting to know/do a doesn't inherently imply that a human will eventually want to have their Elisp do it for them with an actually stable/public/guaranteed API. +1 anyway of course, I just see this pattern more with Emacs/Elisp than with other programming languages/frameworks. – mtraceur May 18 '23 at 02:23
  • @mtraceur Patches for improvements are always welcome upstream ;). – Basil May 18 '23 at 07:07
  • Saying what a community could do better is a patch for the cultural upstream. If we can get more developers to think "I'm doing something that's useful for a human -> it's probably useful as an API too" that leads to the far more efficient solution of the people who already know all the relevant knowledge making the patch instead of someone new having to first learn it all. – mtraceur May 19 '23 at 02:38
  • @mtraceur Agreed, but comments on a 3rd-party Q&A forum post are arguably also less efficient than having this discussion upstream: in the form of a concrete report / feature request, or ideally even patch :). – Basil May 19 '23 at 12:43
0

If you want to do it from Elisp, advice-mapc will loop through all the advice functions on a function, and call a callback for each one.

So if you're just interested in a boolean "does this function have advice on it?", you can just have the callback set a boolean a variable:

(defun has-advice-p (symbol)
    (let ((has-advice nil))
        (advice-mapc (lambda (&rest _) (setq has-advice t)) symbol)
        has-advice))

(Note that if you want to check for a specific advice function rather than looping through all of them, you can use advice-member-p instead.)

(Sadly, there seems to be no API to determine "where" on a function the advice is - did it get added with :before, :around, :filter-return, [...]? There no public API for that information. In fact it seems that after advice is applied, the information only exists in a form that isn't super trivial to get back out - for a clue, look at advice--where-alist and advice--where: it looks like the only way to know is by comparing that raw bytecode. How does the help text shown by describe-function (C-h f) know this information? It's added into the docstring by advice--make-single-doc.)

mtraceur
  • 184
  • 1
  • 10