Mercurial > emacs
annotate lisp/emacs-lisp/elint.el @ 102911:e25ee95fb5b0
*** empty log message ***
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Thu, 09 Apr 2009 16:43:51 +0000 |
parents | 5ae300b1d079 |
children | 1a42628a650e |
rev | line source |
---|---|
38436
b174db545cfd
Some fixes to follow coding conventions.
Pavel Janík <Pavel@Janik.cz>
parents:
20014
diff
changeset
|
1 ;;; elint.el --- Lint Emacs Lisp |
19210 | 2 |
102230
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
3 ;; Copyright (C) 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
4 ;; 2009 Free Software Foundation, Inc. |
19210 | 5 |
6 ;; Author: Peter Liljenberg <petli@lysator.liu.se> | |
7 ;; Created: May 1997 | |
8 ;; Keywords: lisp | |
9 | |
10 ;; This file is part of GNU Emacs. | |
11 | |
94655
90a2847062be
Switch to recommended form of GPLv3 permissions notice.
Glenn Morris <rgm@gnu.org>
parents:
93975
diff
changeset
|
12 ;; GNU Emacs is free software: you can redistribute it and/or modify |
19210 | 13 ;; it under the terms of the GNU General Public License as published by |
94655
90a2847062be
Switch to recommended form of GPLv3 permissions notice.
Glenn Morris <rgm@gnu.org>
parents:
93975
diff
changeset
|
14 ;; the Free Software Foundation, either version 3 of the License, or |
90a2847062be
Switch to recommended form of GPLv3 permissions notice.
Glenn Morris <rgm@gnu.org>
parents:
93975
diff
changeset
|
15 ;; (at your option) any later version. |
19210 | 16 |
17 ;; GNU Emacs is distributed in the hope that it will be useful, | |
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 ;; GNU General Public License for more details. | |
21 | |
22 ;; You should have received a copy of the GNU General Public License | |
94655
90a2847062be
Switch to recommended form of GPLv3 permissions notice.
Glenn Morris <rgm@gnu.org>
parents:
93975
diff
changeset
|
23 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
19210 | 24 |
25 ;;; Commentary: | |
26 | |
27 ;; This is a linter for Emacs Lisp. Currently, it mainly catches | |
28 ;; mispellings and undefined variables, although it can also catch | |
29 ;; function calls with the wrong number of arguments. | |
30 | |
59506
3da5314608ab
Fixed typo in Commentary section.
Reiner Steib <Reiner.Steib@gmx.de>
parents:
58938
diff
changeset
|
31 ;; Before using, call `elint-initialize' to set up some argument |
19210 | 32 ;; data. This takes a while. Then call elint-current-buffer or |
33 ;; elint-defun to lint a buffer or a defun. | |
34 | |
35 ;; The linter will try to "include" any require'd libraries to find | |
36 ;; the variables defined in those. There is a fair amount of voodoo | |
37 ;; involved in this, but it seems to work in normal situations. | |
38 | |
39 ;;; History: | |
40 | |
41 ;;; To do: | |
42 | |
43 ;; * A list of all standard Emacs variables would be nice to have... | |
44 ;; * Adding type checking. (Stop that sniggering!) | |
45 | |
46 ;;; Code: | |
47 | |
48 (defvar elint-log-buffer "*Elint*" | |
49 "*The buffer to insert lint messages in.") | |
50 | |
51 ;;; | |
58938
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
52 ;;; Data |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
53 ;;; |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
54 |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
55 (defconst elint-standard-variables |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
56 '(abbrev-mode auto-fill-function buffer-auto-save-file-name |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
57 buffer-backed-up buffer-display-count buffer-display-table buffer-display-time buffer-file-coding-system buffer-file-format |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
58 buffer-file-name buffer-file-number buffer-file-truename |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
59 buffer-file-type buffer-invisibility-spec buffer-offer-save |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
60 buffer-read-only buffer-saved-size buffer-undo-list |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
61 cache-long-line-scans case-fold-search ctl-arrow cursor-type comment-column |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
62 default-directory defun-prompt-regexp desktop-save-buffer enable-multibyte-characters fill-column fringes-outside-margins goal-column |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
63 header-line-format indicate-buffer-boundaries indicate-empty-lines |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
64 left-fringe-width |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
65 left-margin left-margin-width line-spacing local-abbrev-table local-write-file-hooks major-mode |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
66 mark-active mark-ring mode-line-buffer-identification |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
67 mode-line-format mode-line-modified mode-line-process mode-name |
63511
964ef053b1bc
(elint-init-env): Fix spelling in docstrings.
Juanma Barranquero <lekktu@gmail.com>
parents:
59506
diff
changeset
|
68 overwrite-mode |
58938
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
69 point-before-scroll right-fringe-width right-margin-width |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
70 scroll-bar-width scroll-down-aggressively scroll-up-aggressively selective-display |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
71 selective-display-ellipses tab-width truncate-lines vc-mode vertical-scroll-bar) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
72 "Standard buffer local vars.") |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
73 |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
74 (defconst elint-unknown-builtin-args |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
75 '((while test &rest forms) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
76 (insert-before-markers-and-inherit &rest text) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
77 (catch tag &rest body) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
78 (and &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
79 (funcall func &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
80 (insert &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
81 (vconcat &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
82 (run-hook-with-args hook &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
83 (message-or-box string &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
84 (save-window-excursion &rest body) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
85 (append &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
86 (logior &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
87 (progn &rest body) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
88 (insert-and-inherit &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
89 (message-box string &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
90 (prog2 x y &rest body) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
91 (prog1 first &rest body) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
92 (insert-before-markers &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
93 (call-process-region start end program &optional delete |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
94 destination display &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
95 (concat &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
96 (vector &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
97 (run-hook-with-args-until-success hook &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
98 (track-mouse &rest body) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
99 (unwind-protect bodyform &rest unwindforms) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
100 (save-restriction &rest body) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
101 (quote arg) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
102 (make-byte-code &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
103 (or &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
104 (cond &rest clauses) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
105 (start-process name buffer program &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
106 (run-hook-with-args-until-failure hook &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
107 (if cond then &rest else) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
108 (apply function &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
109 (format string &rest args) |
102230
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
110 (encode-time second minute hour day month year &optional zone) |
58938
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
111 (min &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
112 (logand &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
113 (logxor &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
114 (max &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
115 (list &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
116 (message string &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
117 (defvar symbol init doc) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
118 (call-process program &optional infile destination display &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
119 (with-output-to-temp-buffer bufname &rest body) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
120 (nconc &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
121 (save-excursion &rest body) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
122 (run-hooks &rest hooks) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
123 (/ x y &rest zs) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
124 (- x &rest y) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
125 (+ &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
126 (* &rest args) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
127 (interactive &optional args)) |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
128 "Those built-ins for which we can't find arguments.") |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
129 |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
130 ;;; |
19210 | 131 ;;; ADT: top-form |
132 ;;; | |
133 | |
134 (defsubst elint-make-top-form (form pos) | |
135 "Create a top form. | |
136 FORM is the form, and POS is the point where it starts in the buffer." | |
137 (cons form pos)) | |
138 | |
139 (defsubst elint-top-form-form (top-form) | |
140 "Extract the form from a TOP-FORM." | |
141 (car top-form)) | |
142 | |
143 (defsubst elint-top-form-pos (top-form) | |
144 "Extract the position from a TOP-FORM." | |
145 (cdr top-form)) | |
146 | |
147 ;;; | |
148 ;;; ADT: env | |
149 ;;; | |
150 | |
151 (defsubst elint-make-env () | |
152 "Create an empty environment." | |
153 (list (list nil) nil nil)) | |
154 | |
155 (defsubst elint-env-add-env (env newenv) | |
156 "Augment ENV with NEWENV. | |
157 None of them is modified, and the new env is returned." | |
158 (list (append (car env) (car newenv)) | |
159 (append (car (cdr env)) (car (cdr newenv))) | |
160 (append (car (cdr (cdr env))) (car (cdr (cdr newenv)))))) | |
161 | |
162 (defsubst elint-env-add-var (env var) | |
163 "Augment ENV with the variable VAR. | |
164 The new environment is returned, the old is unmodified." | |
165 (cons (cons (list var) (car env)) (cdr env))) | |
166 | |
167 (defsubst elint-env-add-global-var (env var) | |
168 "Augment ENV with the variable VAR. | |
169 ENV is modified so VAR is seen everywhere. | |
170 ENV is returned." | |
171 (nconc (car env) (list (list var))) | |
172 env) | |
173 | |
174 (defsubst elint-env-find-var (env var) | |
175 "Non-nil if ENV contains the variable VAR. | |
176 Actually, a list with VAR as a single element is returned." | |
177 (assq var (car env))) | |
178 | |
179 (defsubst elint-env-add-func (env func args) | |
180 "Augment ENV with the function FUNC, which has the arguments ARGS. | |
181 The new environment is returned, the old is unmodified." | |
182 (list (car env) | |
183 (cons (list func args) (car (cdr env))) | |
184 (car (cdr (cdr env))))) | |
185 | |
186 (defsubst elint-env-find-func (env func) | |
187 "Non-nil if ENV contains the function FUNC. | |
188 Actually, a list of (FUNC ARGS) is returned." | |
189 (assq func (car (cdr env)))) | |
190 | |
191 (defsubst elint-env-add-macro (env macro def) | |
192 "Augment ENV with the macro named MACRO. | |
193 DEF is the macro definition (a lambda expression or similar). | |
194 The new environment is returned, the old is unmodified." | |
195 (list (car env) | |
196 (car (cdr env)) | |
197 (cons (cons macro def) (car (cdr (cdr env)))))) | |
198 | |
199 (defsubst elint-env-macro-env (env) | |
200 "Return the macro environment of ENV. | |
201 This environment can be passed to `macroexpand'." | |
202 (car (cdr (cdr env)))) | |
203 | |
204 (defsubst elint-env-macrop (env macro) | |
205 "Non-nil if ENV contains MACRO." | |
206 (assq macro (elint-env-macro-env env))) | |
207 | |
208 ;;; | |
209 ;;; User interface | |
210 ;;; | |
211 | |
212 (defun elint-current-buffer () | |
213 "Lint the current buffer." | |
214 (interactive) | |
215 (elint-clear-log (format "Linting %s" (if (buffer-file-name) | |
216 (buffer-file-name) | |
217 (buffer-name)))) | |
218 (elint-display-log) | |
84899
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
219 (mapc 'elint-top-form (elint-update-env)) |
19210 | 220 |
221 ;; Tell the user we're finished. This is terribly klugy: we set | |
222 ;; elint-top-form-logged so elint-log-message doesn't print the | |
223 ;; ** top form ** header... | |
224 (let ((elint-top-form-logged t)) | |
225 (elint-log-message "\nLinting complete.\n"))) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
226 |
19210 | 227 (defun elint-defun () |
228 "Lint the function at point." | |
229 (interactive) | |
230 (save-excursion | |
231 (if (not (beginning-of-defun)) | |
232 (error "Lint what?")) | |
233 | |
234 (let ((pos (point)) | |
235 (def (read (current-buffer)))) | |
236 (elint-display-log) | |
237 | |
238 (elint-update-env) | |
239 (elint-top-form (elint-make-top-form def pos))))) | |
240 | |
241 ;;; | |
242 ;;; Top form functions | |
243 ;;; | |
244 | |
245 (defvar elint-buffer-env nil | |
246 "The environment of a elisp buffer. | |
247 Will be local in linted buffers.") | |
248 | |
249 (defvar elint-buffer-forms nil | |
250 "The top forms in a buffer. | |
251 Will be local in linted buffers.") | |
252 | |
253 (defvar elint-last-env-time nil | |
254 "The last time the buffers env was updated. | |
255 Is measured in buffer-modified-ticks and is local in linted buffers.") | |
256 | |
257 (defun elint-update-env () | |
258 "Update the elint environment in the current buffer. | |
259 Don't do anything if the buffer hasn't been changed since this | |
260 function was called the last time. | |
261 Returns the forms." | |
262 (if (and (local-variable-p 'elint-buffer-env (current-buffer)) | |
263 (local-variable-p 'elint-buffer-forms (current-buffer)) | |
264 (local-variable-p 'elint-last-env-time (current-buffer)) | |
265 (= (buffer-modified-tick) elint-last-env-time)) | |
266 ;; Env is up to date | |
267 elint-buffer-forms | |
268 ;; Remake env | |
269 (set (make-local-variable 'elint-buffer-forms) (elint-get-top-forms)) | |
270 (set (make-local-variable 'elint-buffer-env) | |
271 (elint-init-env elint-buffer-forms)) | |
272 (set (make-local-variable 'elint-last-env-time) (buffer-modified-tick)) | |
273 elint-buffer-forms)) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
274 |
19210 | 275 (defun elint-get-top-forms () |
276 "Collect all the top forms in the current buffer." | |
277 (save-excursion | |
278 (let ((tops nil)) | |
279 (goto-char (point-min)) | |
280 (while (elint-find-next-top-form) | |
281 (let ((pos (point))) | |
282 (condition-case nil | |
283 (setq tops (cons | |
284 (elint-make-top-form (read (current-buffer)) pos) | |
285 tops)) | |
286 (end-of-file | |
287 (goto-char pos) | |
288 (end-of-line) | |
289 (error "Missing ')' in top form: %s" (buffer-substring pos (point))))) | |
290 )) | |
291 (nreverse tops)))) | |
292 | |
293 (defun elint-find-next-top-form () | |
294 "Find the next top form from point. | |
42206 | 295 Return nil if there are no more forms, t otherwise." |
19210 | 296 (parse-partial-sexp (point) (point-max) nil t) |
297 (not (eobp))) | |
298 | |
299 (defun elint-init-env (forms) | |
63511
964ef053b1bc
(elint-init-env): Fix spelling in docstrings.
Juanma Barranquero <lekktu@gmail.com>
parents:
59506
diff
changeset
|
300 "Initialize the environment from FORMS." |
19210 | 301 (let ((env (elint-make-env)) |
302 form) | |
303 (while forms | |
304 (setq form (elint-top-form-form (car forms)) | |
305 forms (cdr forms)) | |
306 (cond | |
307 ;; Add defined variable | |
308 ((memq (car form) '(defvar defconst defcustom)) | |
309 (setq env (elint-env-add-var env (car (cdr form))))) | |
310 ;; Add function | |
311 ((memq (car form) '(defun defsubst)) | |
312 (setq env (elint-env-add-func env (car (cdr form)) | |
313 (car (cdr (cdr form)))))) | |
314 ;; Add macro, both as a macro and as a function | |
315 ((eq (car form) 'defmacro) | |
316 (setq env (elint-env-add-macro env (car (cdr form)) | |
317 (cons 'lambda | |
318 (cdr (cdr form)))) | |
319 env (elint-env-add-func env (car (cdr form)) | |
320 (car (cdr (cdr form)))))) | |
321 | |
322 ;; Import variable definitions | |
323 ((eq (car form) 'require) | |
324 (let ((name (eval (car (cdr form)))) | |
325 (file (eval (car (cdr (cdr form)))))) | |
326 (setq env (elint-add-required-env env name file)))) | |
327 )) | |
328 env)) | |
329 | |
330 (defun elint-add-required-env (env name file) | |
331 "Augment ENV with the variables definied by feature NAME in FILE." | |
332 (condition-case nil | |
333 (let* ((libname (if (stringp file) | |
334 file | |
335 (symbol-name name))) | |
336 | |
337 ;; First try to find .el files, then the raw name | |
338 (lib1 (locate-library (concat libname ".el") t)) | |
339 (lib (if lib1 lib1 (locate-library libname t)))) | |
340 ;; Clear the messages :-/ | |
341 (message nil) | |
342 (if lib | |
343 (save-excursion | |
344 (set-buffer (find-file-noselect lib)) | |
345 (elint-update-env) | |
346 (setq env (elint-env-add-env env elint-buffer-env))) | |
347 (error "dummy error..."))) | |
348 (error | |
349 (ding) | |
350 (message "Can't get variables from require'd library %s" name))) | |
351 env) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
352 |
19210 | 353 (defun regexp-assoc (regexp alist) |
354 "Search for a key matching REGEXP in ALIST." | |
355 (let ((res nil)) | |
356 (while (and alist (not res)) | |
357 (if (and (stringp (car (car alist))) | |
358 (string-match regexp (car (car alist)))) | |
359 (setq res (car alist)) | |
360 (setq alist (cdr alist)))) | |
361 res)) | |
362 | |
363 (defvar elint-top-form nil | |
364 "The currently linted top form, or nil.") | |
365 | |
366 (defvar elint-top-form-logged nil | |
367 "T if the currently linted top form has been mentioned in the log buffer.") | |
368 | |
369 (defun elint-top-form (form) | |
370 "Lint a top FORM." | |
371 (let ((elint-top-form form) | |
372 (elint-top-form-logged nil)) | |
373 (elint-form (elint-top-form-form form) elint-buffer-env))) | |
374 | |
375 ;;; | |
376 ;;; General form linting functions | |
377 ;;; | |
378 | |
379 (defconst elint-special-forms | |
380 '((let . elint-check-let-form) | |
381 (let* . elint-check-let-form) | |
382 (setq . elint-check-setq-form) | |
383 (quote . elint-check-quote-form) | |
384 (cond . elint-check-cond-form) | |
385 (lambda . elint-check-defun-form) | |
386 (function . elint-check-function-form) | |
387 (setq-default . elint-check-setq-form) | |
388 (defun . elint-check-defun-form) | |
389 (defsubst . elint-check-defun-form) | |
390 (defmacro . elint-check-defun-form) | |
391 (defvar . elint-check-defvar-form) | |
392 (defconst . elint-check-defvar-form) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
393 (defcustom . elint-check-defcustom-form) |
19210 | 394 (macro . elint-check-macro-form) |
395 (condition-case . elint-check-condition-case-form)) | |
396 "Functions to call when some special form should be linted.") | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
397 |
19210 | 398 (defun elint-form (form env) |
399 "Lint FORM in the environment ENV. | |
400 The environment created by the form is returned." | |
401 (cond | |
402 ((consp form) | |
403 (let ((func (cdr (assq (car form) elint-special-forms)))) | |
404 (if func | |
405 ;; Special form | |
406 (funcall func form env) | |
407 | |
408 (let* ((func (car form)) | |
409 (args (elint-get-args func env)) | |
410 (argsok t)) | |
411 (cond | |
412 ((eq args 'undefined) | |
413 (setq argsok nil) | |
414 (elint-error "Call to undefined function: %s" form)) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
415 |
19210 | 416 ((eq args 'unknown) nil) |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
417 |
19210 | 418 (t (setq argsok (elint-match-args form args)))) |
419 | |
420 ;; Is this a macro? | |
421 (if (elint-env-macrop env func) | |
422 ;; Macro defined in buffer, expand it | |
423 (if argsok | |
424 (elint-form (macroexpand form (elint-env-macro-env env)) env) | |
425 env) | |
426 | |
427 (let ((fcode (if (symbolp func) | |
428 (if (fboundp func) | |
429 (indirect-function func) | |
430 nil) | |
431 func))) | |
432 (if (and (listp fcode) (eq (car fcode) 'macro)) | |
433 ;; Macro defined outside buffer | |
434 (if argsok | |
435 (elint-form (macroexpand form) env) | |
436 env) | |
437 ;; Function, lint its parameters | |
438 (elint-forms (cdr form) env)))) | |
439 )) | |
440 )) | |
441 ((symbolp form) | |
442 ;; :foo variables are quoted | |
443 (if (and (/= (aref (symbol-name form) 0) ?:) | |
444 (elint-unbound-variable form env)) | |
445 (elint-warning "Reference to unbound symbol: %s" form)) | |
446 env) | |
447 | |
448 (t env) | |
449 )) | |
450 | |
451 (defun elint-forms (forms env) | |
452 "Lint the FORMS, accumulating an environment, starting with ENV." | |
453 ;; grumblegrumbletailrecursiongrumblegrumble | |
454 (while forms | |
455 (setq env (elint-form (car forms) env) | |
456 forms (cdr forms))) | |
457 env) | |
458 | |
459 (defun elint-unbound-variable (var env) | |
460 "T if VAR is unbound in ENV." | |
461 (not (or (eq var nil) | |
462 (eq var t) | |
463 (elint-env-find-var env var) | |
464 (memq var elint-standard-variables)))) | |
465 | |
466 ;;; | |
467 ;;; Function argument checking | |
468 ;;; | |
469 | |
470 (defun elint-match-args (arglist argpattern) | |
471 "Match ARGLIST against ARGPATTERN." | |
472 | |
473 (let ((state 'all) | |
474 (al (cdr arglist)) | |
475 (ap argpattern) | |
476 (ok t)) | |
477 (while | |
478 (cond | |
479 ((and (null al) (null ap)) nil) | |
480 ((eq (car ap) '&optional) | |
481 (setq state 'optional) | |
482 (setq ap (cdr ap)) | |
483 t) | |
484 ((eq (car ap) '&rest) | |
485 nil) | |
486 ((or (and (eq state 'all) (or (null al) (null ap))) | |
487 (and (eq state 'optional) (and al (null ap)))) | |
488 (elint-error "Wrong number of args: %s, %s" arglist argpattern) | |
489 (setq ok nil) | |
490 nil) | |
491 ((and (eq state 'optional) (null al)) | |
492 nil) | |
493 (t (setq al (cdr al) | |
494 ap (cdr ap)) | |
495 t))) | |
496 ok)) | |
497 | |
498 (defun elint-get-args (func env) | |
499 "Find the args of FUNC in ENV. | |
500 Returns `unknown' if we couldn't find arguments." | |
501 (let ((f (elint-env-find-func env func))) | |
502 (if f | |
503 (car (cdr f)) | |
504 (if (symbolp func) | |
505 (if (fboundp func) | |
506 (let ((fcode (indirect-function func))) | |
507 (if (subrp fcode) | |
508 (let ((args (get func 'elint-args))) | |
102230
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
509 ;; FIXME builtins with no args have args = nil. |
19210 | 510 (if args args 'unknown)) |
511 (elint-find-args-in-code fcode))) | |
512 'undefined) | |
513 (elint-find-args-in-code func))))) | |
514 | |
515 (defun elint-find-args-in-code (code) | |
516 "Extract the arguments from CODE. | |
517 CODE can be a lambda expression, a macro, or byte-compiled code." | |
518 (cond | |
519 ((byte-code-function-p code) | |
520 (aref code 0)) | |
521 ((and (listp code) (eq (car code) 'lambda)) | |
522 (car (cdr code))) | |
523 ((and (listp code) (eq (car code) 'macro)) | |
524 (elint-find-args-in-code (cdr code))) | |
525 (t 'unknown))) | |
526 | |
527 ;;; | |
528 ;;; Functions to check some special forms | |
529 ;;; | |
530 | |
531 (defun elint-check-cond-form (form env) | |
532 "Lint a cond FORM in ENV." | |
533 (setq form (cdr form)) | |
534 (while form | |
535 (if (consp (car form)) | |
536 (elint-forms (car form) env) | |
537 (elint-error "cond clause should be a list: %s" (car form))) | |
538 (setq form (cdr form))) | |
539 env) | |
540 | |
541 (defun elint-check-defun-form (form env) | |
542 "Lint a defun/defmacro/lambda FORM in ENV." | |
543 (setq form (if (eq (car form) 'lambda) (cdr form) (cdr (cdr form)))) | |
84899
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
544 (mapc (function (lambda (p) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
545 (or (memq p '(&optional &rest)) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
546 (setq env (elint-env-add-var env p))) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
547 )) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
548 (car form)) |
19210 | 549 (elint-forms (cdr form) env)) |
550 | |
551 (defun elint-check-let-form (form env) | |
552 "Lint the let/let* FORM in ENV." | |
553 (let ((varlist (car (cdr form)))) | |
554 (if (not varlist) | |
555 (progn | |
556 (elint-error "Missing varlist in let: %s" form) | |
557 env) | |
558 | |
559 ;; Check for (let (a (car b)) ...) type of error | |
560 (if (and (= (length varlist) 2) | |
561 (symbolp (car varlist)) | |
562 (listp (car (cdr varlist))) | |
563 (fboundp (car (car (cdr varlist))))) | |
564 (elint-warning "Suspect varlist: %s" form)) | |
565 | |
566 ;; Add variables to environment, and check the init values | |
567 (let ((newenv env)) | |
84899
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
568 (mapc (function (lambda (s) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
569 (cond |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
570 ((symbolp s) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
571 (setq newenv (elint-env-add-var newenv s))) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
572 ((and (consp s) (<= (length s) 2)) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
573 (elint-form (car (cdr s)) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
574 (if (eq (car form) 'let) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
575 env |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
576 newenv)) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
577 (setq newenv |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
578 (elint-env-add-var newenv (car s)))) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
579 (t (elint-error |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
580 "Malformed `let' declaration: %s" s)) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
581 ))) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
582 varlist) |
19210 | 583 |
584 ;; Lint the body forms | |
585 (elint-forms (cdr (cdr form)) newenv) | |
586 )))) | |
587 | |
588 (defun elint-check-setq-form (form env) | |
589 "Lint the setq FORM in ENV." | |
590 (or (= (mod (length form) 2) 1) | |
591 (elint-error "Missing value in setq: %s" form)) | |
592 | |
593 (let ((newenv env) | |
594 sym val) | |
595 (setq form (cdr form)) | |
596 (while form | |
597 (setq sym (car form) | |
598 val (car (cdr form)) | |
599 form (cdr (cdr form))) | |
600 (if (symbolp sym) | |
601 (if (elint-unbound-variable sym newenv) | |
602 (elint-warning "Setting previously unbound symbol: %s" sym)) | |
603 (elint-error "Setting non-symbol in setq: %s" sym)) | |
604 (elint-form val newenv) | |
605 (if (symbolp sym) | |
606 (setq newenv (elint-env-add-var newenv sym)))) | |
607 newenv)) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
608 |
19210 | 609 (defun elint-check-defvar-form (form env) |
610 "Lint the defvar/defconst FORM in ENV." | |
611 (if (or (= (length form) 2) | |
612 (= (length form) 3) | |
613 (and (= (length form) 4) (stringp (nth 3 form)))) | |
614 (elint-env-add-global-var (elint-form (nth 2 form) env) | |
615 (car (cdr form))) | |
616 (elint-error "Malformed variable declaration: %s" form) | |
617 env)) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
618 |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
619 (defun elint-check-defcustom-form (form env) |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
620 "Lint the defcustom FORM in ENV." |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
621 (if (and (> (length form) 3) |
52880
9417a94488d3
(elint-check-defcustom-form): Don't use `evenp' so we don't implicitly
John Paul Wallington <jpw@pobox.com>
parents:
52401
diff
changeset
|
622 ;; even no. of keyword/value args ? |
9417a94488d3
(elint-check-defcustom-form): Don't use `evenp' so we don't implicitly
John Paul Wallington <jpw@pobox.com>
parents:
52401
diff
changeset
|
623 (zerop (logand (length form) 1))) |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
624 (elint-env-add-global-var (elint-form (nth 2 form) env) |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
625 (car (cdr form))) |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
626 (elint-error "Malformed variable declaration: %s" form) |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
627 env)) |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
628 |
19210 | 629 (defun elint-check-function-form (form env) |
630 "Lint the function FORM in ENV." | |
631 (let ((func (car (cdr-safe form)))) | |
632 (cond | |
633 ((symbolp func) | |
634 (or (elint-env-find-func env func) | |
635 (fboundp func) | |
636 (elint-warning "Reference to undefined function: %s" form)) | |
637 env) | |
638 ((and (consp func) (memq (car func) '(lambda macro))) | |
639 (elint-form func env)) | |
640 ((stringp func) env) | |
641 (t (elint-error "Not a function object: %s" form) | |
642 env) | |
643 ))) | |
644 | |
645 (defun elint-check-quote-form (form env) | |
646 "Lint the quote FORM in ENV." | |
647 env) | |
648 | |
649 (defun elint-check-macro-form (form env) | |
650 "Check the macro FORM in ENV." | |
651 (elint-check-function-form (list (car form) (cdr form)) env)) | |
652 | |
653 (defun elint-check-condition-case-form (form env) | |
654 "Check the condition-case FORM in ENV." | |
655 (let ((resenv env)) | |
656 (if (< (length form) 3) | |
657 (elint-error "Malformed condition-case: %s" form) | |
658 (or (symbolp (car (cdr form))) | |
659 (elint-warning "First parameter should be a symbol: %s" form)) | |
660 (setq resenv (elint-form (nth 2 form) env)) | |
661 | |
662 (let ((newenv (elint-env-add-var env (car (cdr form)))) | |
663 (errforms (nthcdr 3 form)) | |
664 errlist) | |
665 (while errforms | |
666 (setq errlist (car (car errforms))) | |
84899
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
667 (mapc (function (lambda (s) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
668 (or (get s 'error-conditions) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
669 (get s 'error-message) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
670 (elint-warning |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
671 "Not an error symbol in error handler: %s" s)))) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
672 (cond |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
673 ((symbolp errlist) (list errlist)) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
674 ((listp errlist) errlist) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
675 (t (elint-error "Bad error list in error handler: %s" |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
676 errlist) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
677 nil)) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
678 ) |
19210 | 679 (elint-forms (cdr (car errforms)) newenv) |
680 (setq errforms (cdr errforms)) | |
681 ))) | |
682 resenv)) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
683 |
19210 | 684 ;;; |
685 ;;; Message functions | |
686 ;;; | |
687 | |
688 ;; elint-error and elint-warning are identical, but they might change | |
689 ;; to reflect different seriousness of linting errors | |
690 | |
691 (defun elint-error (string &rest args) | |
47923
07d91c802db4
(elint-error, elint-warning): Fix typo.
Juanma Barranquero <lekktu@gmail.com>
parents:
42268
diff
changeset
|
692 "Report a linting error. |
19210 | 693 STRING and ARGS are thrown on `format' to get the message." |
694 (let ((errstr (apply 'format string args))) | |
695 (elint-log-message errstr) | |
696 )) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
697 |
19210 | 698 (defun elint-warning (string &rest args) |
47923
07d91c802db4
(elint-error, elint-warning): Fix typo.
Juanma Barranquero <lekktu@gmail.com>
parents:
42268
diff
changeset
|
699 "Report a linting warning. |
19210 | 700 STRING and ARGS are thrown on `format' to get the message." |
701 (let ((errstr (apply 'format string args))) | |
702 (elint-log-message errstr) | |
703 )) | |
704 | |
705 (defun elint-log-message (errstr) | |
706 "Insert ERRSTR last in the lint log buffer." | |
707 (save-excursion | |
708 (set-buffer (elint-get-log-buffer)) | |
709 (goto-char (point-max)) | |
710 (or (bolp) (newline)) | |
711 | |
712 ;; Do we have to say where we are? | |
713 (if elint-top-form-logged | |
714 nil | |
715 (insert | |
716 (let* ((form (elint-top-form-form elint-top-form)) | |
717 (top (car form))) | |
718 (cond | |
719 ((memq top '(defun defsubst)) | |
720 (format "\n** function %s **\n" (car (cdr form)))) | |
721 ((eq top 'defmacro) | |
722 (format "\n** macro %s **\n" (car (cdr form)))) | |
723 ((memq top '(defvar defconst)) | |
724 (format "\n** variable %s **\n" (car (cdr form)))) | |
725 (t "\n** top level expression **\n")))) | |
726 (setq elint-top-form-logged t)) | |
727 | |
728 (insert errstr) | |
729 (newline))) | |
730 | |
731 (defun elint-clear-log (&optional header) | |
732 "Clear the lint log buffer. | |
733 Insert HEADER followed by a blank line if non-nil." | |
734 (save-excursion | |
735 (set-buffer (elint-get-log-buffer)) | |
736 (erase-buffer) | |
737 (if header | |
738 (progn | |
739 (insert header) | |
740 (newline)) | |
741 ))) | |
742 | |
743 (defun elint-display-log () | |
744 "Display the lint log buffer." | |
745 (let ((pop-up-windows t)) | |
746 (display-buffer (elint-get-log-buffer)) | |
747 (sit-for 0))) | |
748 | |
749 (defun elint-get-log-buffer () | |
750 "Return a log buffer for elint." | |
751 (let ((buf (get-buffer elint-log-buffer))) | |
752 (if buf | |
753 buf | |
754 (let ((oldbuf (current-buffer))) | |
755 (prog1 | |
756 (set-buffer (get-buffer-create elint-log-buffer)) | |
757 (setq truncate-lines t) | |
758 (set-buffer oldbuf))) | |
759 ))) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
760 |
19210 | 761 ;;; |
762 ;;; Initializing code | |
763 ;;; | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
764 |
19210 | 765 ;;;###autoload |
766 (defun elint-initialize () | |
767 "Initialize elint." | |
768 (interactive) | |
84899
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
769 (mapc (function (lambda (x) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
770 (or (not (symbolp (car x))) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
771 (eq (cdr x) 'unknown) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
772 (put (car x) 'elint-args (cdr x))))) |
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
773 (elint-find-builtin-args)) |
19210 | 774 (mapcar (function (lambda (x) |
775 (put (car x) 'elint-args (cdr x)))) | |
776 elint-unknown-builtin-args)) | |
777 | |
778 | |
779 (defun elint-find-builtins () | |
780 "Returns a list of all built-in functions." | |
781 (let ((subrs nil)) | |
782 (mapatoms (lambda (s) (if (and (fboundp s) (subrp (symbol-function s))) | |
783 (setq subrs (cons s subrs))))) | |
784 subrs | |
785 )) | |
786 | |
787 (defun elint-find-builtin-args (&optional list) | |
788 "Returns a list of the built-in functions and their arguments. | |
789 | |
790 If LIST is nil, call `elint-find-builtins' to get a list of all built-in | |
791 functions, otherwise use LIST. | |
792 | |
793 Each functions is represented by a cons cell: | |
794 \(function-symbol . args) | |
795 If no documentation could be found args will be `unknown'." | |
102230
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
796 (mapcar (lambda (f) |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
797 (let ((doc (documentation f t))) |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
798 (or (and doc |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
799 (string-match "\n\n(fn\\(.*)\\)\\'" doc) |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
800 (ignore-errors |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
801 (read (format "(%s %s" f (match-string 1 doc))))) |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
802 (cons f 'unknown)))) |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
803 (or list (elint-find-builtins)))) |
19210 | 804 |
805 (provide 'elint) | |
806 | |
93975
1e3a407766b9
Fix up comment convention on the arch-tag lines.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
87649
diff
changeset
|
807 ;; arch-tag: b2f061e2-af84-4ddc-8e39-f5e969ac228f |
19210 | 808 ;;; elint.el ends here |