]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/elint.el
Merge branch 'seq-let'
[gnu-emacs] / lisp / emacs-lisp / elint.el
index de2a05fb46ddc0a4d42892f41ec800378a74968b..317e5a6fd3f58645e3c9f679ec43abdb28c03466 100644 (file)
@@ -1,7 +1,6 @@
 ;;; elint.el --- Lint Emacs Lisp
 
-;; Copyright (C) 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-;;   2009, 2010  Free Software Foundation, Inc.
+;; Copyright (C) 1997, 2001-2015 Free Software Foundation, Inc.
 
 ;; Author: Peter Liljenberg <petli@lysator.liu.se>
 ;; Created: May 1997
@@ -47,6 +46,8 @@
 
 ;;; Code:
 
+(require 'help-fns)
+
 (defgroup elint nil
   "Linting for Emacs Lisp."
   :prefix "elint-"
@@ -123,7 +124,6 @@ are as follows, and suppress messages about the indicated features:
   ;; FIXME I don't see why they shouldn't just get doc-strings.
   '(vc-mode local-write-file-hooks activate-menubar-hook buffer-name-history
            coding-system-history extended-command-history
-           kbd-macro-termination-hook read-expression-history
            yes-or-no-p-history)
   "Standard variables, excluding `elint-builtin-variables'.
 These are variables that we cannot detect automatically for some reason.")
@@ -147,7 +147,7 @@ Set by `elint-initialize', if `elint-scan-preloaded' is non-nil.")
   "Those built-ins for which we can't find arguments, if any.")
 
 (defvar elint-extra-errors '(file-locked file-supersession ftp-error)
-  "Errors without error-message or error-confitions properties.")
+  "Errors without `error-message' or `error-conditions' properties.")
 
 (defconst elint-preloaded-skip-re
   (regexp-opt '("loaddefs.el" "loadup.el" "cus-start" "language/"
@@ -289,7 +289,7 @@ A complicated directory may require a lot of memory."
 ;;;###autoload
 (defun elint-current-buffer ()
   "Lint the current buffer.
-If necessary, this first calls `elint-initalize'."
+If necessary, this first calls `elint-initialize'."
   (interactive)
   (or elint-builtin-variables
       (elint-initialize))
@@ -298,7 +298,7 @@ If necessary, this first calls `elint-initalize'."
   (elint-display-log)
   (elint-set-mode-line t)
   (mapc 'elint-top-form (elint-update-env))
-  ;; Tell the user we're finished.  This is terribly klugy: we set
+  ;; Tell the user we're finished.  This is terribly kludgy: we set
     ;; elint-top-form-logged so elint-log-message doesn't print the
     ;; ** top form ** header...
   (elint-set-mode-line)
@@ -308,7 +308,7 @@ If necessary, this first calls `elint-initalize'."
 ;;;###autoload
 (defun elint-defun ()
   "Lint the function at point.
-If necessary, this first calls `elint-initalize'."
+If necessary, this first calls `elint-initialize'."
   (interactive)
   (or elint-builtin-variables
       (elint-initialize))
@@ -325,7 +325,7 @@ If necessary, this first calls `elint-initalize'."
 ;;;
 
 (defvar elint-buffer-env nil
-  "The environment of a elisp buffer.
+  "The environment of an elisp buffer.
 Will be local in linted buffers.")
 
 (defvar elint-buffer-forms nil
@@ -337,7 +337,7 @@ Will be local in linted buffers.")
 Is measured in buffer-modified-ticks and is local in linted buffers.")
 
 ;; This is a minor optimization.  It is local to every buffer, and so
-;; does not prevent recursive requirs.  It does not list the requires
+;; does not prevent recursive requires.  It does not list the requires
 ;; of requires.
 (defvar elint-features nil
   "List of all libraries this buffer has required, or that have been provided.")
@@ -359,6 +359,8 @@ Returns the forms."
     (set (make-local-variable 'elint-buffer-env)
         (elint-init-env elint-buffer-forms))
     (if elint-preloaded-env
+        ;; FIXME: This doesn't do anything!  Should we setq the result to
+        ;; elint-buffer-env?
        (elint-env-add-env elint-preloaded-env elint-buffer-env))
     (set (make-local-variable 'elint-last-env-time) (buffer-modified-tick))
     elint-buffer-forms))
@@ -372,7 +374,7 @@ Returns the forms."
        (let ((elint-current-pos (point)))
          ;; non-list check could be here too. errors may be out of seq.
          ;; quoted check cannot be elsewhere, since quotes skipped.
-         (if (looking-back "'")
+         (if (looking-back "'" (1- (point)))
              ;; Eg cust-print.el uses ' as a comment syntax.
              (elint-warning "Skipping quoted form `'%.20s...'"
                           (read (current-buffer)))
@@ -394,40 +396,41 @@ Return nil if there are no more forms, t otherwise."
   (parse-partial-sexp (point) (point-max) nil t)
   (not (eobp)))
 
-(defvar env)                           ; from elint-init-env
+(defvar elint-env)                     ; from elint-init-env
 
 (defun elint-init-form (form)
-  "Process FORM, adding to ENV if recognized."
+  "Process FORM, adding to ELINT-ENV if recognized."
   (cond
    ;; Eg nnmaildir seems to use [] as a form of comment syntax.
    ((not (listp form))
     (elint-warning "Skipping non-list form `%s'" form))
    ;; Add defined variable
    ((memq (car form) '(defvar defconst defcustom))
-    (setq env (elint-env-add-var env (cadr form))))
+    (setq elint-env (elint-env-add-var elint-env (cadr form))))
    ;; Add function
    ((memq (car form) '(defun defsubst))
-    (setq env (elint-env-add-func env (cadr form) (nth 2 form))))
+    (setq elint-env (elint-env-add-func elint-env (cadr form) (nth 2 form))))
    ;; FIXME needs a handler to say second arg is not a variable when we come
    ;; to scan the form.
    ((eq (car form) 'define-derived-mode)
-    (setq env (elint-env-add-func env (cadr form) ())
-         env (elint-env-add-var env (cadr form))
-         env (elint-env-add-var env (intern (format "%s-map" (cadr form))))))
+    (setq elint-env (elint-env-add-func elint-env (cadr form) ())
+         elint-env (elint-env-add-var elint-env (cadr form))
+         elint-env (elint-env-add-var elint-env
+                                      (intern (format "%s-map" (cadr form))))))
    ((eq (car form) 'define-minor-mode)
-    (setq env (elint-env-add-func env (cadr form) '(&optional arg))
+    (setq elint-env (elint-env-add-func elint-env (cadr form) '(&optional arg))
          ;; FIXME mode map?
-         env (elint-env-add-var env (cadr form))))
+         elint-env (elint-env-add-var elint-env (cadr form))))
    ((and (eq (car form) 'easy-menu-define)
         (cadr form))
-    (setq env (elint-env-add-func env (cadr form) '(event))
-         env (elint-env-add-var env (cadr form))))
+    (setq elint-env (elint-env-add-func elint-env (cadr form) '(event))
+         elint-env (elint-env-add-var elint-env (cadr form))))
    ;; FIXME it would be nice to check the autoloads are correct.
    ((eq (car form) 'autoload)
-    (setq env (elint-env-add-func env (cadr (cadr form)) 'unknown)))
+    (setq elint-env (elint-env-add-func elint-env (cadr (cadr form)) 'unknown)))
    ((eq (car form) 'declare-function)
-    (setq env (elint-env-add-func
-              env (cadr form)
+    (setq elint-env (elint-env-add-func
+              elint-env (cadr form)
               (if (or (< (length form) 4)
                       (eq (nth 3 form) t)
                       (unless (stringp (nth 2 form))
@@ -440,14 +443,14 @@ Return nil if there are no more forms, t otherwise."
     ;; If the alias points to something already in the environment,
     ;; add the alias to the environment with the same arguments.
     ;; FIXME symbol-function, eg backquote.el?
-    (let ((def (elint-env-find-func env (cadr (nth 2 form)))))
-      (setq env (elint-env-add-func env (cadr (cadr form))
+    (let ((def (elint-env-find-func elint-env (cadr (nth 2 form)))))
+      (setq elint-env (elint-env-add-func elint-env (cadr (cadr form))
                                    (if def (cadr def) 'unknown)))))
    ;; Add macro, both as a macro and as a function
    ((eq (car form) 'defmacro)
-    (setq env (elint-env-add-macro env (cadr form)
+    (setq elint-env (elint-env-add-macro elint-env (cadr form)
                                   (cons 'lambda (cddr form)))
-         env (elint-env-add-func env (cadr form) (nth 2 form))))
+         elint-env (elint-env-add-func elint-env (cadr form) (nth 2 form))))
    ((and (eq (car form) 'put)
         (= 4 (length form))
         (eq (car-safe (cadr form)) 'quote)
@@ -465,18 +468,21 @@ Return nil if there are no more forms, t otherwise."
        (add-to-list 'elint-features name)
        ;; cl loads cl-macs in an opaque manner.
        ;; Since cl-macs requires cl, we can just process cl-macs.
+        ;; FIXME: AFAIK, `cl' now behaves properly and does not need any
+        ;; special treatment any more.  Can someone who understands this
+        ;; code confirm?  --Stef
        (and (eq name 'cl) (not elint-doing-cl)
             ;; We need cl if elint-form is to be able to expand cl macros.
             (require 'cl)
             (setq name 'cl-macs
                   file nil
                   elint-doing-cl t)) ; blech
-       (setq env (elint-add-required-env env name file))))))
-  env)
+       (setq elint-env (elint-add-required-env elint-env name file))))))
+  elint-env)
 
 (defun elint-init-env (forms)
   "Initialize the environment from FORMS."
-  (let ((env (elint-make-env))
+  (let ((elint-env (elint-make-env))
        form)
     (while forms
       (setq form (elint-top-form-form (car forms))
@@ -489,7 +495,7 @@ Return nil if there are no more forms, t otherwise."
                                   with-no-warnings))
          (mapc 'elint-init-form (cdr form))
        (elint-init-form form)))
-    env))
+    elint-env))
 
 (defun elint-add-required-env (env name file)
   "Augment ENV with the variables defined by feature NAME in FILE."
@@ -505,11 +511,10 @@ Return nil if there are no more forms, t otherwise."
        ;; (Messes up the "Initializing elint..." message.)
 ;;;    (message nil)
        (if lib
-           (save-excursion
+           (with-current-buffer (find-file-noselect lib)
              ;; FIXME this doesn't use a temp buffer, because it
              ;; stores the result in buffer-local variables so that
              ;; it can be reused.
-             (set-buffer (find-file-noselect lib))
              (elint-update-env)
              (setq env (elint-env-add-env env elint-buffer-env)))
              ;;; (with-temp-buffer
@@ -528,7 +533,7 @@ Return nil if there are no more forms, t otherwise."
   "The currently linted top form, or nil.")
 
 (defvar elint-top-form-logged nil
-  "T if the currently linted top form has been mentioned in the log buffer.")
+  "The value t if the currently linted top form has been mentioned in the log buffer.")
 
 (defun elint-top-form (form)
   "Lint a top FORM."
@@ -640,7 +645,7 @@ Returns the environment created by the form."
   "Name of a temporarily bound symbol.")
 
 (defun elint-unbound-variable (var env)
-  "T if VAR is unbound in ENV."
+  "Return t if VAR is unbound in ENV."
   ;; #1063 suggests adding (symbol-file var) here, but I don't think
   ;; this is right, because it depends on what files you happen to have
   ;; loaded at the time, which might not be the same when the code runs.
@@ -710,14 +715,8 @@ Returns `unknown' if we couldn't find arguments."
 (defun elint-find-args-in-code (code)
   "Extract the arguments from CODE.
 CODE can be a lambda expression, a macro, or byte-compiled code."
-  (cond
-   ((byte-code-function-p code)
-    (aref code 0))
-   ((and (listp code) (eq (car code) 'lambda))
-    (car (cdr code)))
-   ((and (listp code) (eq (car code) 'macro))
-    (elint-find-args-in-code (cdr code)))
-   (t 'unknown)))
+  (let ((args (help-function-arglist code)))
+    (if (listp args) args 'unknown)))
 
 ;;;
 ;;; Functions to check some special forms
@@ -1100,7 +1099,7 @@ optional prefix argument REINIT is non-nil."
 ;; This includes all the built-in and dumped things with documentation.
 (defun elint-scan-doc-file ()
   "Scan the DOC file for function and variables.
-Marks the function wih their arguments, and returns a list of variables."
+Marks the function with their arguments, and returns a list of variables."
   ;; Cribbed from help-fns.el.
   (let ((docbuf " *DOC*")
        vars sym args)
@@ -1146,8 +1145,8 @@ Marks the function wih their arguments, and returns a list of variables."
 (defun elint-find-builtins ()
   "Return a list of all built-in functions."
   (let (subrs)
-    (mapatoms (lambda (s) (and (fboundp s) (subrp (symbol-function s))
-                              (setq subrs (cons s subrs)))))
+    (mapatoms (lambda (s) (and (subrp (symbol-function s))
+                          (push s subrs))))
     subrs))
 
 (defun elint-find-builtin-args (&optional list)
@@ -1172,5 +1171,4 @@ If no documentation could be found args will be `unknown'."
 
 (provide 'elint)
 
-;; arch-tag: b2f061e2-af84-4ddc-8e39-f5e969ac228f
 ;;; elint.el ends here