Add 2012 to FSF copyright years for Emacs files
[bpt/emacs.git] / lisp / emacs-lisp / check-declare.el
index 47dd57d..3135b9b 100644 (file)
@@ -1,16 +1,16 @@
 ;;; check-declare.el --- Check declare-function statements
 
-;; Copyright (C) 2007, 2008  Free Software Foundation, Inc.
+;; Copyright (C) 2007-2012  Free Software Foundation, Inc.
 
 ;; Author: Glenn Morris <rgm@gnu.org>
 ;; Keywords: lisp, tools, maint
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,9 +18,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -36,6 +34,8 @@
 
 ;; 1. Warn about functions marked as obsolete, eg
 ;; password-read-and-add in smime.el.
+;; 2. defmethod, defclass argument checking.
+;; 3. defclass also defines -p and -child-p.
 
 ;;; Code:
 
@@ -44,7 +44,7 @@
 
 (defun check-declare-locate (file basefile)
   "Return the full path of FILE.
-Expands files with a \".c\" extension relative to the Emacs
+Expands files with a \".c\" or \".m\" extension relative to the Emacs
 \"src/\" directory.  Otherwise, `locate-library' searches for FILE.
 If that fails, expands FILE relative to BASEFILE's directory part.
 The returned file might not exist.  If FILE has an \"ext:\" prefix, so does
@@ -54,9 +54,9 @@ the result."
     (if ext
         (setq file (substring file 4)))
     (setq file
-          (if (string-equal "c" (file-name-extension file))
+          (if (member (file-name-extension file) '("c" "m"))
               (expand-file-name file (expand-file-name "src" source-directory))
-            (if (setq tfile (locate-library (file-name-nondirectory file)))
+            (if (setq tfile (locate-library file))
                 (progn
                   (setq tfile
                         (replace-regexp-in-string "\\.elc\\'" ".el" tfile))
@@ -81,28 +81,32 @@ defines FN, with ARGLIST.  FILEONLY non-nil means only check that FNFILE
 exists, not that it defines FN.  This is for function definitions that we
 don't know how to recognize (e.g. some macros)."
   (let ((m (format "Scanning %s..." file))
-        alist fnfile fn arglist fileonly)
+        alist form len fn fnfile arglist fileonly)
     (message "%s" m)
     (with-temp-buffer
       (insert-file-contents file)
-      (while (re-search-forward
-              "^[ \t]*(declare-function[ \t]+\\(\\S-+\\)[ \t]+\
-\"\\(\\S-+\\)\"" nil t)
-        (setq fn (match-string 1)
-              fnfile (match-string 2)
-              fnfile (check-declare-locate fnfile (expand-file-name file))
-              arglist (progn
-                        (skip-chars-forward " \t\n")
-                        ;; Use `t' to distinguish no arglist
-                        ;; specified from an empty one.
-                        (if (looking-at "\\((\\|nil\\|t\\)")
-                            (read (current-buffer))
-                          t))
-              fileonly (progn
-                        (skip-chars-forward " \t\n")
-                        (if (looking-at "\\(t\\|'\\sw+\\)")
-                            (match-string 1)))
-              alist (cons (list fnfile fn arglist fileonly) alist))))
+      ;; FIXME we could theoretically be inside a string.
+      (while (re-search-forward "^[ \t]*\\((declare-function\\)[ \t\n]" nil t)
+        (goto-char (match-beginning 1))
+        (if (and (setq form (ignore-errors (read (current-buffer))))
+                 ;; Exclude element of byte-compile-initial-macro-environment.
+                 (or (listp (cdr form)) (setq form nil))
+                 (> (setq len (length form)) 2)
+                 (< len 6)
+                 (symbolp (setq fn (cadr form)))
+                 (setq fn (symbol-name fn)) ; later we use as a search string
+                 (stringp (setq fnfile (nth 2 form)))
+                 (setq fnfile (check-declare-locate fnfile
+                                                    (expand-file-name file)))
+                 ;; Use `t' to distinguish unspecified arglist from empty one.
+                 (or (eq t (setq arglist (if (> len 3)
+                                             (nth 3 form)
+                                           t)))
+                     (listp arglist))
+                 (symbolp (setq fileonly (nth 4 form))))
+            (setq alist (cons (list fnfile fn arglist fileonly) alist))
+          ;; FIXME make this more noticeable.
+          (if form (message "Malformed declaration for `%s'" (cadr form))))))
     (message "%sdone" m)
     alist))
 
@@ -132,22 +136,23 @@ Returns nil if all claims are found to be true, otherwise a list
 of errors with elements of the form \(FILE FN TYPE), where TYPE
 is a string giving details of the error."
   (let ((m (format "Checking %s..." fnfile))
-        (cflag (string-equal "c" (file-name-extension fnfile)))
+        (cflag (member (file-name-extension fnfile) '("c" "m")))
         (ext (string-match "^ext:" fnfile))
         re fn sig siglist arglist type errlist minargs maxargs)
     (message "%s" m)
     (if ext
         (setq fnfile (substring fnfile 4)))
-    (if (file-exists-p fnfile)
+    (if (file-regular-p fnfile)
         (with-temp-buffer
           (insert-file-contents fnfile)
           ;; defsubst's don't _have_ to be known at compile time.
           (setq re (format (if cflag
                                "^[ \t]*\\(DEFUN\\)[ \t]*([ \t]*\"%s\""
                              "^[ \t]*(\\(fset[ \t]+'\\|\
-def\\(?:un\\|subst\\|foo\\|\
-ine-\\(?:derived\\|generic\\|\\(?:global\\(?:ized\\)?-\\)?minor\\)-mode\
-\\|\\(?:ine-obsolete-function-\\)?alias[ \t]+'\\)\\)\
+def\\(?:un\\|subst\\|foo\\|method\\|class\\|\
+ine-\\(?:derived\\|generic\\|\\(?:global\\(?:ized\\)?-\\)?minor\\)-mode\\|\
+\\(?:ine-obsolete-function-\\)?alias[ \t]+'\\|\
+ine-overloadable-function\\)\\)\
 \[ \t]*%s\\([ \t;]+\\|$\\)")
                            (regexp-opt (mapcar 'cadr fnlist) t)))
           (while (re-search-forward re nil t)
@@ -160,7 +165,7 @@ ine-\\(?:derived\\|generic\\|\\(?:global\\(?:ized\\)?-\\)?minor\\)-mode\
                   ;; sig = 'err means we could not find an arglist.
                   sig (cond (cflag
                              (or
-                              (when (re-search-forward "," nil t 3)
+                              (when (search-forward "," nil t 3)
                                 (skip-chars-forward " \t\n")
                                 ;; Assuming minargs and maxargs on same line.
                                 (when (looking-at "\\([0-9]+\\)[ \t]*,[ \t]*\
@@ -187,7 +192,8 @@ ine-\\(?:derived\\|generic\\|\\(?:global\\(?:ized\\)?-\\)?minor\\)-mode\
                               type)
                              'obsolete)
                             ;; Can't easily check arguments in these cases.
-                            ((string-match "\\`\\(defalias\\|fset\\)\\>" type)
+                            ((string-match "\\`\\(def\\(alias\\|\
+method\\|class\\)\\|fset\\)\\>" type)
                              t)
                             ((looking-at "\\((\\|nil\\)")
                              (byte-compile-arglist-signature
@@ -289,9 +295,7 @@ See `check-declare-directory' for more information."
 ;;;###autoload
 (defun check-declare-directory (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'."
+Returns non-nil if any false statements are found."
   (interactive "DDirectory to check: ")
   (or (file-directory-p (setq root (expand-file-name root)))
       (error "Directory `%s' not found" root))
@@ -312,5 +316,4 @@ described in the documentation of `declare-function'."
 
 (provide 'check-declare)
 
-;; arch-tag: a4d6cdc4-deb7-4502-b327-0e4ef3d82d96
 ;;; check-declare.el ends here.