Add 2012 to FSF copyright years for Emacs files
[bpt/emacs.git] / lisp / emacs-lisp / check-declare.el
index d71268e..3135b9b 100644 (file)
@@ -1,6 +1,6 @@
 ;;; 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
@@ -34,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:
 
@@ -42,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
@@ -52,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))
@@ -79,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))
 
@@ -130,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)
@@ -158,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]*\
@@ -185,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
@@ -287,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))
@@ -310,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.