unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Glenn Morris <rgm@gnu.org>
To: rms@gnu.org
Cc: Stefan Monnier <monnier@iro.umontreal.ca>, emacs-devel@gnu.org
Subject: Re: suppressing byte-compiler warnings about undefined functions
Date: Sat, 10 Nov 2007 20:11:10 -0500	[thread overview]
Message-ID: <gid4uhlh75.fsf@fencepost.gnu.org> (raw)
In-Reply-To: <E1IquXm-0000PY-M9@fencepost.gnu.org> (Richard Stallman's message of "Sat, 10 Nov 2007 12:54:54 -0500")

Richard Stallman wrote:

> It is probably nontrivial to arrange to find all the
> `declare-function' calls in Emacs and check them. I doubt it
> requires deep thought, but it should to be implemented before we
> install this.

See below: `check-declared-functions'. I haven't bothered to make it
efficient/elegant (see how long it takes when all the necessary
declare statements are added...). I'm thinking it could go in
admin/admin.el (it uses process-lines from there).

> Why clear byte-compile-declared-functions at the end of compilation?

I'm using the existing variable `byte-compile-function-environment'
now. This also allows for the optional argument checking Stefan asked for.


*** byte-run.el	26 Jul 2007 05:26:44 -0000	1.22
--- byte-run.el	11 Nov 2007 00:35:08 -0000
***************
*** 103,108 ****
--- 103,126 ----
       (eval-and-compile
         (put ',name 'byte-optimizer 'byte-compile-inline-expand))))
  
+ (defun declare-function (fn file &optional arglist)
+   "Tell the byte-compiler that function FN is defined, in FILE.
+ Optional ARGLIST is the argument list used by the function.  The
+ FILE argument is not used by the byte-compiler, but by the
+ function `check-declared-functions', which checks that FILE
+ contains a definition for FN.  FILE should be either absolute, or
+ relative to the location of the file containing the declaration.
+ ARGLIST is used by both the byte-compiler and
+ `check-declared-functions' to check for consistency.
+ 
+ Note that for the purposes of `check-declared-functions', this
+ statement must be the first non-whitespace on a line, and
+ everything up to the end of FILE must be all on the same line.
+ For example:
+ 
+ \(declare-function 'c-end-of-defun \"progmodes/cc-cmds.el\" '(&optional arg))"
+ nil)
+ 
  (defun make-obsolete (obsolete-name current-name &optional when)
    "Make the byte-compiler warn that OBSOLETE-NAME is obsolete.
  The warning will say that CURRENT-NAME should be used instead.
*** bytecomp.el	10 Nov 2007 08:05:15 -0000	2.217
--- bytecomp.el	11 Nov 2007 00:35:23 -0000
***************
*** 1258,1264 ****
  		  (byte-compile-fdefinition (car form) t)))
  	 (sig (if (and def (not (eq def t)))
  		  (byte-compile-arglist-signature
! 		   (if (eq 'lambda (car-safe def))
  		       (nth 1 def)
  		     (if (byte-code-function-p def)
  			 (aref def 0)
--- 1258,1264 ----
  		  (byte-compile-fdefinition (car form) t)))
  	 (sig (if (and def (not (eq def t)))
  		  (byte-compile-arglist-signature
! 		   (if (memq (car-safe def) '(declared lambda))
  		       (nth 1 def)
  		     (if (byte-code-function-p def)
  			 (aref def 0)
***************
*** 2818,2823 ****
--- 2818,2831 ----
  	(body
  	 (list body))))
  
+ (put 'declare-function 'byte-hunk-handler 'byte-compile-declare-function)
+ (defun byte-compile-declare-function (form)
+   (push (cons (eval (nth 1 form))
+               (list 'declared (eval (nth 3 form))))
+         byte-compile-function-environment)
+   nil)
+ 
+ \f
  ;; This is the recursive entry point for compiling each subform of an
  ;; expression.
  ;; If for-effect is non-nil, byte-compile-form will output a byte-discard




;; Adapted from authors.el.
(defmacro checkdec-visit (file &rest body)
  "Execute the forms in BODY while visiting FILE.
Re-uses an existing buffer visiting FILE if there is one.  The
value returned is the value of the last form in BODY."
  (declare (indent 1))
  `(let ((existing-buffer (find-buffer-visiting ,file))
         (enable-local-variables :safe)
         (enable-local-eval nil)
         (buffer (find-file-noselect ,file)))
     (prog1
         (save-current-buffer
           (set-buffer buffer)
           (save-restriction
             (widen)
             (goto-char (point-min))
             ,@body))
       (unless existing-buffer
         (kill-buffer buffer)))))

(defun checkdec-warn (file fn fnfile type)
  "Warn that FILE made a false claim about FN in FNFILE.
TYPE is a string given the nature of the error."
  (display-warning 'checkdec
                   (format "%s said `%s' was defined in %s: %s"
                           (file-name-nondirectory file) fn
                           (file-relative-name fnfile
                                               (file-name-directory file))
                           type)
                   nil "*Check Declarations Warnings*"))

(autoload 'byte-compile-arglist-signature "bytecomp.el")

(defun checkdec-verify (file fn fnfile &optional arglist)
  "Check that FNFILE defines the function FN, as claimed in FILE.
Optionally also check that the arglist matches ARGLIST.
Returns non-nil if the claim was incorrect in some way."
  (unless (file-name-absolute-p fnfile)
    (setq fnfile (expand-file-name fnfile (file-name-directory file))))
  (let (type defarglist)
    (if (file-exists-p fnfile)
        (checkdec-visit fnfile
          (if (re-search-forward
               (format "^(def\\(un\\|subst\\|macro\\)[ \t]+%s\\>" fn) nil t)
              (when arglist
                (skip-chars-forward " \t")
                (if (eolp) (forward-line 1))
                (skip-chars-forward " \t")
                (if (looking-at "(")
                    (setq defarglist (read (current-buffer))))
                (or (equal (byte-compile-arglist-signature defarglist)
                           (byte-compile-arglist-signature arglist))
                    (setq type "arglist mismatch")))
            (setq type "function not found")))
      (setq type "file not found"))
    (if type
        (checkdec-warn file fn fnfile type))))

(defun checkdec-scan (file)
  "Scan FILE for `declare-function' calls and check them.
Returns non-nil if any checks fail."
  (let ((m (format "Checking %s..." file))
        alist anyf e)
     (message "%s" m)
     (checkdec-visit file
      (while (re-search-forward
              "^[ \t]*(declare-function[ \t]+'\\(\\S-+\\)[ \t]+\
\"\\(\\S-+\\)\"" nil t)
        (setq e (list (match-string-no-properties 1)
                      (match-string-no-properties 2)))
        (skip-chars-forward " \t")
        (if (eolp) (forward-line 1))
        (skip-chars-forward " \t'")
        (if (looking-at "(")
            (setq e (append e (list (read (current-buffer))))))
        (setq alist (cons e alist))))
    (dolist (e alist)
      (setq anyf (or anyf
                     (checkdec-verify file (car e) (nth 1 e) (nth 2 e)))))
    (message "%sdone" m)
    anyf))

(defun check-declared-functions (root)
  "Check veracity of all `declare-function' statements under directory ROOT.
Returns non-nil if any false statements are found.  For this to
work correctly, the statements must adhere to the format
described in the documentation of `declare-function'."
  (interactive "DEmacs lisp directory: ")
  (setq root (expand-file-name root))
  (unless (file-exists-p (expand-file-name "emacs-lisp/bytecomp.el" root))
    (error "Not the root lisp directory of Emacs: %s" root))
  (let ((m "Checking `declare-function' statements...")
        anyf)
    (message "%s" m)
    (dolist (file (process-lines "find" root "-name" "*.el"
                                 "-exec" "grep" "-l"
                                 "^(declare-function" "{}" ";"))
      (setq anyf (or anyf (checkdec-scan file))))
    (message "%s%s" m (if anyf "problems found" "OK"))
    anyf))

  reply	other threads:[~2007-11-11  1:11 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-11-10  0:55 suppressing byte-compiler warnings about undefined functions Glenn Morris
2007-11-10  3:13 ` Stefan Monnier
2007-11-10 17:54 ` Richard Stallman
2007-11-11  1:11   ` Glenn Morris [this message]
2007-11-11  4:00     ` Glenn Morris
2007-11-11 19:33     ` Richard Stallman
2007-11-13  4:20       ` Glenn Morris
2007-11-13  9:31         ` martin rudalics
2007-11-14  5:32           ` Glenn Morris
2007-11-14 14:53             ` Stefan Monnier
2007-11-15  3:07             ` Richard Stallman
2007-11-17  3:58               ` Glenn Morris
2007-11-17 23:30                 ` Richard Stallman
2007-11-13 20:02         ` Richard Stallman
2007-11-13 21:05           ` Stefan Monnier
2007-11-14  5:30             ` Glenn Morris
2007-11-15  3:06             ` Richard Stallman
     [not found]     ` <ur9oddrnmg0.fsf@mothra.ics.uci.edu>
2007-11-19  0:39       ` byte-compiler warnings about undefined functions can now be silenced Glenn Morris
2007-11-19  9:04         ` martin rudalics
2007-11-24  3:12           ` Glenn Morris
2007-11-19 19:02         ` Richard Stallman
2007-11-20  4:05           ` Glenn Morris
2007-11-19 19:33         ` Jay Belanger
2007-11-19 20:46           ` Glenn Morris
2007-11-20 12:12           ` Richard Stallman
2007-11-11  8:46 ` suppressing byte-compiler warnings about undefined functions Alan Mackenzie
2007-11-11 15:51   ` Dan Nicolaescu
2007-11-11 16:10     ` Alan Mackenzie
2007-11-11 16:18       ` Dan Nicolaescu
2007-11-11 18:32         ` Dan Nicolaescu
2007-11-11 23:54           ` Richard Stallman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=gid4uhlh75.fsf@fencepost.gnu.org \
    --to=rgm@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=monnier@iro.umontreal.ca \
    --cc=rms@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).