aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Morris2009-09-12 02:41:39 +0000
committerGlenn Morris2009-09-12 02:41:39 +0000
commit6974be68b6a243403ce44033bc0d556b134e75f3 (patch)
tree442a0e34517a12d2e4cf4cd6340fb624b017666f
parent30194d4d1b45fb4d096b5b98976bad4549127cc1 (diff)
downloademacs-6974be68b6a243403ce44033bc0d556b134e75f3.tar.gz
emacs-6974be68b6a243403ce44033bc0d556b134e75f3.zip
(elint-file, elint-directory): New autoloaded commands.
(elint-current-buffer): Set mode-line-process. (elint-init-env): Handle define-derived-mode. Fix declare-function with unspecified arglist. Guard against odd defalias statements (eg iso-insert's 8859-1-map). (elint-add-required-env): Use a temp buffer. (elint-form): Just print the function/macro name, not the whole form. Return env unchanged if we fail to parse a macro. (elint-forms): Guard against parse errors. (elint-output): New function, to handle batch mode. (elint-log-message): Add optional argument. Use elint-output. (elint-set-mode-line): New function.
-rw-r--r--lisp/emacs-lisp/elint.el142
1 files changed, 111 insertions, 31 deletions
diff --git a/lisp/emacs-lisp/elint.el b/lisp/emacs-lisp/elint.el
index d144a66a61a..32011f143f3 100644
--- a/lisp/emacs-lisp/elint.el
+++ b/lisp/emacs-lisp/elint.el
@@ -40,6 +40,9 @@
40 40
41;; * List of variables and functions defined in dumped lisp files. 41;; * List of variables and functions defined in dumped lisp files.
42;; * Adding type checking. (Stop that sniggering!) 42;; * Adding type checking. (Stop that sniggering!)
43;; * Handle eval-when-compile (eg for requires, being sensitive to the
44;; difference between funcs and macros).
45;; * Requires within function bodies.
43 46
44;;; Code: 47;;; Code:
45 48
@@ -152,6 +155,50 @@ This environment can be passed to `macroexpand'."
152;;; 155;;;
153 156
154;;;###autoload 157;;;###autoload
158(defun elint-file (file)
159 "Lint the file FILE."
160 (interactive "fElint file: ")
161 (setq file (expand-file-name file))
162 (or elint-builtin-variables
163 (elint-initialize))
164 (let ((dir (file-name-directory file)))
165 (let ((default-directory dir))
166 (elint-display-log))
167 (elint-set-mode-line t)
168 (with-current-buffer elint-log-buffer
169 (unless (string-equal default-directory dir)
170 (elint-log-message (format " \nLeaving directory `%s'"
171 default-directory) t)
172 (elint-log-message (format "Entering directory `%s'" dir) t)
173 (setq default-directory dir))))
174 (let ((str (format "Linting file %s" file)))
175 (message "%s..." str)
176 (or noninteractive
177 (elint-log-message (format " \n%s at %s" str (current-time-string)) t))
178 ;; elint-current-buffer clears log.
179 (with-temp-buffer
180 (insert-file-contents file)
181 (let ((buffer-file-name file))
182 (with-syntax-table emacs-lisp-mode-syntax-table
183 (mapc 'elint-top-form (elint-update-env)))))
184 (elint-set-mode-line)
185 (message "%s...done" str)))
186
187;; cf byte-recompile-directory.
188;;;###autoload
189(defun elint-directory (directory)
190 "Lint all the .el files in DIRECTORY."
191 (interactive "DElint directory: ")
192 (let ((elint-running t))
193 (dolist (file (directory-files directory t))
194 ;; Bytecomp has emacs-lisp-file-regexp.
195 (when (and (string-match "\\.el\\'" file)
196 (file-readable-p file)
197 (not (auto-save-file-name-p file)))
198 (elint-file file))))
199 (elint-set-mode-line))
200
201;;;###autoload
155(defun elint-current-buffer () 202(defun elint-current-buffer ()
156 "Lint the current buffer. 203 "Lint the current buffer.
157If necessary, this first calls `elint-initalize'." 204If necessary, this first calls `elint-initalize'."
@@ -161,12 +208,14 @@ If necessary, this first calls `elint-initalize'."
161 (elint-clear-log (format "Linting %s" (or (buffer-file-name) 208 (elint-clear-log (format "Linting %s" (or (buffer-file-name)
162 (buffer-name)))) 209 (buffer-name))))
163 (elint-display-log) 210 (elint-display-log)
211 (elint-set-mode-line t)
164 (mapc 'elint-top-form (elint-update-env)) 212 (mapc 'elint-top-form (elint-update-env))
165 ;; Tell the user we're finished. This is terribly klugy: we set 213 ;; Tell the user we're finished. This is terribly klugy: we set
166 ;; elint-top-form-logged so elint-log-message doesn't print the 214 ;; elint-top-form-logged so elint-log-message doesn't print the
167 ;; ** top form ** header... 215 ;; ** top form ** header...
168 (let ((elint-top-form-logged t)) 216 (elint-set-mode-line)
169 (elint-log-message "\nLinting finished.\n"))) 217 (elint-log-message "\nLinting finished.\n" t))
218
170 219
171;;;###autoload 220;;;###autoload
172(defun elint-defun () 221(defun elint-defun ()
@@ -254,15 +303,19 @@ Return nil if there are no more forms, t otherwise."
254 ;; Add function 303 ;; Add function
255 ((memq (car form) '(defun defsubst)) 304 ((memq (car form) '(defun defsubst))
256 (setq env (elint-env-add-func env (cadr form) (nth 2 form)))) 305 (setq env (elint-env-add-func env (cadr form) (nth 2 form))))
306 ((eq (car form) 'define-derived-mode)
307 (setq env (elint-env-add-func env (cadr form) ())
308 env (elint-env-add-var env (cadr form))))
257 ;; FIXME it would be nice to check the autoloads are correct. 309 ;; FIXME it would be nice to check the autoloads are correct.
258 ((eq (car form) 'autoload) 310 ((eq (car form) 'autoload)
259 (setq env (elint-env-add-func env (cadr (cadr form)) 'unknown))) 311 (setq env (elint-env-add-func env (cadr (cadr form)) 'unknown)))
260 ((eq (car form) 'declare-function) 312 ((eq (car form) 'declare-function)
261 (setq env (elint-env-add-func env (cadr form) 313 (setq env (elint-env-add-func env (cadr form)
262 (if (> (length form) 3) 314 (if (or (< (length form) 4)
263 (nth 3 form) 315 (eq (nth 3 form) t))
264 'unknown)))) 316 'unknown
265 ((eq (car form) 'defalias) 317 (nth 3 form)))))
318 ((and (eq (car form) 'defalias) (listp (nth 2 form)))
266 ;; If the alias points to something already in the environment, 319 ;; If the alias points to something already in the environment,
267 ;; add the alias to the environment with the same arguments. 320 ;; add the alias to the environment with the same arguments.
268 (let ((def (elint-env-find-func env (cadr (nth 2 form))))) 321 (let ((def (elint-env-find-func env (cadr (nth 2 form)))))
@@ -295,10 +348,16 @@ Return nil if there are no more forms, t otherwise."
295 (message nil) 348 (message nil)
296 (if lib 349 (if lib
297 (save-excursion 350 (save-excursion
298 (set-buffer (find-file-noselect lib)) 351 ;;; (set-buffer (find-file-noselect lib))
299 (elint-update-env) 352 ;;; (elint-update-env)
300 (setq env (elint-env-add-env env elint-buffer-env))) 353 ;;; (setq env (elint-env-add-env env elint-buffer-env)))
301 (error "Dummy error"))) 354 (with-temp-buffer
355 (insert-file-contents lib)
356 (with-syntax-table emacs-lisp-mode-syntax-table
357 (elint-update-env))
358 (setq env (elint-env-add-env env elint-buffer-env))))
359 ;;(message "Elint processed (require '%s)" name))
360 (error "Unable to find require'd library %s" name)))
302 (error 361 (error
303 (ding) 362 (ding)
304 (message "Can't get variables from require'd library %s" name))) 363 (message "Can't get variables from require'd library %s" name)))
@@ -356,7 +415,7 @@ The environment created by the form is returned."
356 (cond 415 (cond
357 ((eq args 'undefined) 416 ((eq args 'undefined)
358 (setq argsok nil) 417 (setq argsok nil)
359 (elint-error "Call to undefined function: %s" form)) 418 (elint-error "Call to undefined function: %s" func))
360 419
361 ((eq args 'unknown) nil) 420 ((eq args 'unknown) nil)
362 421
@@ -371,7 +430,8 @@ The environment created by the form is returned."
371 (elint-form 430 (elint-form
372 (macroexpand form (elint-env-macro-env env)) env) 431 (macroexpand form (elint-env-macro-env env)) env)
373 (error 432 (error
374 (elint-error "Elint failed to expand macro: %s" form))) 433 (elint-error "Elint failed to expand macro: %s" func)
434 env))
375 env) 435 env)
376 436
377 (let ((fcode (if (symbolp func) 437 (let ((fcode (if (symbolp func)
@@ -397,8 +457,11 @@ The environment created by the form is returned."
397(defun elint-forms (forms env) 457(defun elint-forms (forms env)
398 "Lint the FORMS, accumulating an environment, starting with ENV." 458 "Lint the FORMS, accumulating an environment, starting with ENV."
399 ;; grumblegrumbletailrecursiongrumblegrumble 459 ;; grumblegrumbletailrecursiongrumblegrumble
400 (dolist (f forms env) 460 (if (listp forms)
401 (setq env (elint-form f env)))) 461 (dolist (f forms env)
462 (setq env (elint-form f env)))
463 ;; Loop macro?
464 (elint-error "Elint failed to parse form: %s" forms)))
402 465
403(defun elint-unbound-variable (var env) 466(defun elint-unbound-variable (var env)
404 "T if VAR is unbound in ENV." 467 "T if VAR is unbound in ENV."
@@ -639,27 +702,33 @@ STRING and ARGS are thrown on `format' to get the message."
639See `elint-error'." 702See `elint-error'."
640 (elint-log "Warning" string args)) 703 (elint-log "Warning" string args))
641 704
642(defun elint-log-message (errstr) 705(defun elint-output (string)
643 "Insert ERRSTR last in the lint log buffer." 706 "Print or insert STRING, depending on value of `noninteractive'."
707 (if noninteractive
708 (message "%s" string)
709 (insert string "\n")))
710
711(defun elint-log-message (errstr &optional top)
712 "Insert ERRSTR last in the lint log buffer.
713Optional argument TOP non-nil means pretend `elint-top-form-logged' is non-nil."
644 (with-current-buffer (elint-get-log-buffer) 714 (with-current-buffer (elint-get-log-buffer)
645 (goto-char (point-max)) 715 (goto-char (point-max))
646 (let ((inhibit-read-only t)) 716 (let ((inhibit-read-only t))
647 (or (bolp) (newline)) 717 (or (bolp) (newline))
648 ;; Do we have to say where we are? 718 ;; Do we have to say where we are?
649 (unless elint-top-form-logged 719 (unless (or elint-top-form-logged top)
650 (insert 720 (let* ((form (elint-top-form-form elint-top-form))
651 (let* ((form (elint-top-form-form elint-top-form)) 721 (top (car form)))
652 (top (car form))) 722 (elint-output (cond
653 (cond 723 ((memq top '(defun defsubst))
654 ((memq top '(defun defsubst)) 724 (format "\nIn function %s:" (cadr form)))
655 (format "\nIn function %s:\n" (cadr form))) 725 ((eq top 'defmacro)
656 ((eq top 'defmacro) 726 (format "\nIn macro %s:" (cadr form)))
657 (format "\nIn macro %s:\n" (cadr form))) 727 ((memq top '(defvar defconst))
658 ((memq top '(defvar defconst)) 728 (format "\nIn variable %s:" (cadr form)))
659 (format "\nIn variable %s:\n" (cadr form))) 729 (t "\nIn top level expression:"))))
660 (t "\nIn top level expression:\n"))))
661 (setq elint-top-form-logged t)) 730 (setq elint-top-form-logged t))
662 (insert errstr "\n")))) 731 (elint-output errstr))))
663 732
664(defun elint-clear-log (&optional header) 733(defun elint-clear-log (&optional header)
665 "Clear the lint log buffer. 734 "Clear the lint log buffer.
@@ -677,6 +746,17 @@ Insert HEADER followed by a blank line if non-nil."
677 (display-buffer (elint-get-log-buffer)) 746 (display-buffer (elint-get-log-buffer))
678 (sit-for 0))) 747 (sit-for 0)))
679 748
749(defvar elint-running)
750
751(defun elint-set-mode-line (&optional on)
752 "Set the mode-line-process of the Elint log buffer."
753 (with-current-buffer (elint-get-log-buffer)
754 (and (eq major-mode 'compilation-mode)
755 (setq mode-line-process
756 (list (if (or on (bound-and-true-p elint-running))
757 (propertize ":run" 'face 'compilation-warning)
758 (propertize ":finished" 'face 'compilation-info)))))))
759
680(defun elint-get-log-buffer () 760(defun elint-get-log-buffer ()
681 "Return a log buffer for elint." 761 "Return a log buffer for elint."
682 (or (get-buffer elint-log-buffer) 762 (or (get-buffer elint-log-buffer)