;;; advice.el --- An overloading mechanism for Emacs Lisp functions -*- lexical-binding: t -*-
-;; Copyright (C) 1993-1994, 2000-2012 Free Software Foundation, Inc.
+;; Copyright (C) 1993-1994, 2000-2013 Free Software Foundation, Inc.
;; Author: Hans Chalupsky <hans@cs.buffalo.edu>
;; Maintainer: FSF
;; Advice implements forward advice mainly via the following: 1) Separation
;; of advice definition and activation that makes it possible to accumulate
;; advice information without having the original function already defined,
-;; 2) special versions of the built-in functions `fset/defalias' which check
-;; for advice information whenever they define a function. If advice
-;; information was found then the advice will immediately get activated when
-;; the function gets defined.
+;; 2) Use of the `defalias-fset-function' symbol property which lets
+;; us advise the function when it gets defined.
;; Automatic advice activation means, that whenever a function gets defined
-;; with either `defun', `defmacro', `fset' or by loading a byte-compiled
+;; with either `defun', `defmacro', `defalias' or by loading a byte-compiled
;; file, and the function has some advice-info stored with it then that
;; advice will get activated right away.
"Take a macro function DEFINITION and make a lambda out of it."
`(cdr ,definition))
-(defmacro ad-subr-p (definition)
- ;;"non-nil if DEFINITION is a subr."
- (list 'subrp definition))
-
-(defmacro ad-macro-p (definition)
- ;;"non-nil if DEFINITION is a macro."
- `(eq (car-safe ,definition) 'macro))
-
(defmacro ad-lambda-p (definition)
;;"non-nil if DEFINITION is a lambda expression."
`(eq (car-safe ,definition) 'lambda))
(defmacro ad-compiled-p (definition)
"Return non-nil if DEFINITION is a compiled byte-code object."
`(or (byte-code-function-p ,definition)
- (and (ad-macro-p ,definition)
- (byte-code-function-p (ad-lambdafy ,definition)))))
+ (and (macrop ,definition)
+ (byte-code-function-p (ad-lambdafy ,definition)))))
(defmacro ad-compiled-code (compiled-definition)
"Return the byte-code object of a COMPILED-DEFINITION."
- `(if (ad-macro-p ,compiled-definition)
+ `(if (macrop ,compiled-definition)
(ad-lambdafy ,compiled-definition)
,compiled-definition))
"Return the lambda expression of a function/macro/advice DEFINITION."
(cond ((ad-lambda-p definition)
definition)
- ((ad-macro-p definition)
+ ((macrop definition)
(ad-lambdafy definition))
((ad-advice-p definition)
(cdr definition))
"Return the argument list of DEFINITION."
(require 'help-fns)
(help-function-arglist
- (if (or (ad-macro-p definition) (ad-advice-p definition))
+ (if (or (macrop definition) (ad-advice-p definition))
(cdr definition)
definition)
'preserve-names))
(defun ad-advised-definition-p (definition)
"Return non-nil if DEFINITION was generated from advice information."
(if (or (ad-lambda-p definition)
- (ad-macro-p definition)
+ (macrop definition)
(ad-compiled-p definition))
(let ((docstring (ad-docstring definition)))
(and (stringp docstring)
;; representations, so cache entries preactivated with version
;; 1 can't be used.
(cond
- ((ad-macro-p definition) 'macro2)
- ((ad-subr-p definition) 'subr2)
+ ((macrop definition) 'macro2)
+ ((subrp definition) 'subr2)
((or (ad-lambda-p definition) (ad-compiled-p definition)) 'fun2)
((ad-advice-p definition) 'advice2))) ;; FIXME: Can this ever happen?
"True if FUNCTION has an interpreted definition that can be compiled."
(and (ad-has-proper-definition function)
(or (ad-lambda-p (symbol-function function))
- (ad-macro-p (symbol-function function)))
+ (macrop (symbol-function function)))
(not (ad-compiled-p (symbol-function function)))))
(defvar warning-suppress-types) ;From warnings.el.
(defun ad-compile-function (function)
"Byte-compile the assembled advice function."
(require 'bytecomp)
- (require 'warnings) ;To define warning-suppress-types before we let-bind it.
(let ((byte-compile-warnings byte-compile-warnings)
;; Don't pop up windows showing byte-compiler warnings.
(warning-suppress-types '((bytecomp))))
(defun ad-preactivate-advice (function advice class position)
"Preactivate FUNCTION and returns the constructed cache."
- (let* ((function-defined-p (fboundp function))
- (old-definition
- (if function-defined-p
- (symbol-function function)))
+ (let* ((advicefunname (ad-get-advice-info-field function 'advicefunname))
+ (old-advice (symbol-function advicefunname))
(old-advice-info (ad-copy-advice-info function))
(ad-advised-functions ad-advised-functions))
(unwind-protect
(list (ad-get-cache-definition function)
(ad-get-cache-id function))))
(ad-set-advice-info function old-advice-info)
- ;; Don't `fset' function to nil if it was previously unbound:
- (if function-defined-p
- (fset function old-definition)
- (fmakunbound function)))))
+ (advice-remove function advicefunname)
+ (fset advicefunname old-advice)
+ (if old-advice (advice-add function :around advicefunname)))))
;; @@ Activation and definition handling:
((eq ad-default-compilation-action 'never) nil)
((eq ad-default-compilation-action 'always) t)
((eq ad-default-compilation-action 'like-original)
- (or (ad-subr-p (ad-get-orig-definition function))
+ (or (subrp (ad-get-orig-definition function))
(ad-compiled-p (ad-get-orig-definition function))))
;; everything else means `maybe':
(t (featurep 'byte-compile))))
"Redefine FUNCTION with its advised definition from cache or scratch.
The resulting FUNCTION will be compiled if `ad-should-compile' returns t.
The current definition and its cache-id will be put into the cache."
- (let ((verified-cached-definition
- (if (ad-verify-cache-id function)
- (ad-get-cache-definition function)))
- (advicefunname (ad-get-advice-info-field function 'advicefunname)))
+ (let* ((verified-cached-definition
+ (if (ad-verify-cache-id function)
+ (ad-get-cache-definition function)))
+ (advicefunname (ad-get-advice-info-field function 'advicefunname))
+ (old-ispec (interactive-form advicefunname)))
(fset advicefunname
(or verified-cached-definition
(ad-make-advised-definition function)))
+ (unless (equal (interactive-form advicefunname) old-ispec)
+ ;; If the interactive-spec of advicefunname has changed, force nadvice to
+ ;; refresh its copy.
+ (advice-remove function advicefunname))
(advice-add function :around advicefunname)
(if (ad-should-compile function compile)
(ad-compile-function function))
usage: (defadvice FUNCTION (CLASS NAME [POSITION] [ARGLIST] FLAG...)
[DOCSTRING] [INTERACTIVE-FORM]
BODY...)"
- (declare (doc-string 3)
+ (declare (doc-string 3) (indent 2)
(debug (&define name ;; thing being advised.
(name ;; class is [&or "before" "around" "after"
;; "activation" "deactivation"]
`((ad-set-cache
',function
;; the function will get compiled:
- ,(cond ((ad-macro-p (car preactivation))
+ ,(cond ((macrop (car preactivation))
`(ad-macrofy
(function
,(ad-lambdafy