Mercurial > emacs
annotate lisp/emacs-lisp/elint.el @ 110612:aac9726c8e54
* lisp/emacs-lisp/float-sup.el (e): Remove.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Mon, 27 Sep 2010 22:11:33 +0200 |
parents | 2da9673fc448 |
children | 9ee34f35bd15 376148b31b5e |
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, |
106815 | 4 ;; 2009, 2010 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 | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
27 ;; This is a linter for Emacs Lisp. Currently, it mainly catches |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
28 ;; misspellings and undefined variables, although it can also catch |
19210 | 29 ;; function calls with the wrong number of arguments. |
30 | |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
31 ;; To use, call elint-current-buffer or elint-defun to lint a buffer |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
32 ;; or defun. The first call runs `elint-initialize' to set up some |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
33 ;; argument data, which may take a while. |
19210 | 34 |
35 ;; The linter will try to "include" any require'd libraries to find | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
36 ;; the variables defined in those. There is a fair amount of voodoo |
19210 | 37 ;; involved in this, but it seems to work in normal situations. |
38 | |
39 ;;; To do: | |
40 | |
41 ;; * Adding type checking. (Stop that sniggering!) | |
105137 | 42 ;; * Make eval-when-compile be sensitive to the difference between |
43 ;; funcs and macros. | |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
44 ;; * Requires within function bodies. |
105137 | 45 ;; * Handle defstruct. |
46 ;; * Prevent recursive requires. | |
19210 | 47 |
48 ;;; Code: | |
49 | |
105137 | 50 (defgroup elint nil |
51 "Linting for Emacs Lisp." | |
52 :prefix "elint-" | |
53 :group 'maint) | |
54 | |
55 (defcustom elint-log-buffer "*Elint*" | |
56 "The buffer in which to log lint messages." | |
57 :type 'string | |
58 :safe 'stringp | |
59 :group 'elint) | |
60 | |
61 (defcustom elint-scan-preloaded t | |
62 "Non-nil means to scan `preloaded-file-list' when initializing. | |
63 Otherwise, just scan the DOC file for functions and variables. | |
64 This is faster, but less accurate, since it misses undocumented features. | |
65 This may result in spurious warnings about unknown functions, etc." | |
66 :type 'boolean | |
67 :safe 'booleanp | |
68 :group 'elint | |
69 :version "23.2") | |
70 | |
71 (defcustom elint-ignored-warnings nil | |
72 "If non-nil, a list of issue types that Elint should ignore. | |
73 This is useful if Elint has trouble understanding your code and | |
74 you need to suppress lots of spurious warnings. The valid list elements | |
75 are as follows, and suppress messages about the indicated features: | |
76 undefined-functions - calls to unknown functions | |
77 unbound-reference - reference to unknown variables | |
78 unbound-assignment - assignment to unknown variables | |
79 macro-expansions - failure to expand macros | |
80 empty-let - let-bindings with empty variable lists" | |
81 :type '(choice (const :tag "Don't suppress any warnings" nil) | |
82 (repeat :tag "List of issues to ignore" | |
83 (choice (const undefined-functions | |
84 :tag "Calls to unknown functions") | |
85 (const unbound-reference | |
86 :tag "Reference to unknown variables") | |
87 (const unbound-assignment | |
88 :tag "Assignment to unknown variables") | |
89 (const macro-expansion | |
90 :tag "Failure to expand macros") | |
91 (const empty-let | |
92 :tag "Let-binding with empty varlist")))) | |
93 :safe (lambda (value) (or (null value) | |
94 (and (listp value) | |
95 (equal value | |
96 (mapcar | |
97 (lambda (e) | |
98 (if (memq e | |
99 '(undefined-functions | |
100 unbound-reference | |
101 unbound-assignment | |
102 macro-expansion | |
103 empty-let)) | |
104 e)) | |
105 value))))) | |
106 :version "23.2" | |
107 :group 'elint) | |
108 | |
109 (defcustom elint-directory-skip-re "\\(ldefs-boot\\|loaddefs\\)\\.el\\'" | |
110 "If nil, a regexp matching files to skip when linting a directory." | |
111 :type '(choice (const :tag "Lint all files" nil) | |
112 (regexp :tag "Regexp to skip")) | |
113 :safe 'string-or-null-p | |
114 :group 'elint | |
115 :version "23.2") | |
19210 | 116 |
117 ;;; | |
58938
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
118 ;;; Data |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
119 ;;; |
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
120 |
106016
042d5d78d053
Shigeru Fukaya <shigeru.fukaya at gmail.com>
Glenn Morris <rgm@gnu.org>
parents:
105305
diff
changeset
|
121 (defconst elint-standard-variables |
106017
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
122 ;; Most of these are defined in C with no documentation. |
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
123 ;; FIXME I don't see why they shouldn't just get doc-strings. |
106016
042d5d78d053
Shigeru Fukaya <shigeru.fukaya at gmail.com>
Glenn Morris <rgm@gnu.org>
parents:
105305
diff
changeset
|
124 '(vc-mode local-write-file-hooks activate-menubar-hook buffer-name-history |
042d5d78d053
Shigeru Fukaya <shigeru.fukaya at gmail.com>
Glenn Morris <rgm@gnu.org>
parents:
105305
diff
changeset
|
125 coding-system-history extended-command-history |
042d5d78d053
Shigeru Fukaya <shigeru.fukaya at gmail.com>
Glenn Morris <rgm@gnu.org>
parents:
105305
diff
changeset
|
126 kbd-macro-termination-hook read-expression-history |
042d5d78d053
Shigeru Fukaya <shigeru.fukaya at gmail.com>
Glenn Morris <rgm@gnu.org>
parents:
105305
diff
changeset
|
127 yes-or-no-p-history) |
106017
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
128 "Standard variables, excluding `elint-builtin-variables'. |
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
129 These are variables that we cannot detect automatically for some reason.") |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
130 |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
131 (defvar elint-builtin-variables nil |
105137 | 132 "List of built-in variables. Set by `elint-initialize'. |
133 This is actually all those documented in the DOC file, which includes | |
134 built-in variables and those from dumped Lisp files.") | |
58938
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
135 |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
136 (defvar elint-autoloaded-variables nil |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
137 "List of `loaddefs.el' variables. Set by `elint-initialize'.") |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
138 |
105137 | 139 (defvar elint-preloaded-env nil |
140 "Environment defined by the preloaded (dumped) Lisp files. | |
141 Set by `elint-initialize', if `elint-scan-preloaded' is non-nil.") | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
142 |
105137 | 143 (defconst elint-unknown-builtin-args |
144 ;; encode-time allows extra arguments for use with decode-time. | |
145 ;; For some reason, some people seem to like to use them in other cases. | |
146 '((encode-time second minute hour day month year &rest zone)) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
147 "Those built-ins for which we can't find arguments, if any.") |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
148 |
105137 | 149 (defvar elint-extra-errors '(file-locked file-supersession ftp-error) |
107146
149c0b848923
Fix typos in docstrings.
Juanma Barranquero <lekktu@gmail.com>
parents:
106815
diff
changeset
|
150 "Errors without `error-message' or `error-conditions' properties.") |
58938
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
151 |
105137 | 152 (defconst elint-preloaded-skip-re |
153 (regexp-opt '("loaddefs.el" "loadup.el" "cus-start" "language/" | |
154 "eucjp-ms" "mule-conf" "/characters" "/charprop" | |
155 "cp51932")) | |
156 "Regexp matching elements of `preloaded-file-list' to ignore. | |
157 We ignore them because they contain no definitions of use to Elint.") | |
158 | |
58938
f3ac898990de
(elint-standard-variables, elint-unknown-builtin-args): Move definitions up.
Richard M. Stallman <rms@gnu.org>
parents:
58740
diff
changeset
|
159 ;;; |
19210 | 160 ;;; ADT: top-form |
161 ;;; | |
162 | |
163 (defsubst elint-make-top-form (form pos) | |
164 "Create a top form. | |
165 FORM is the form, and POS is the point where it starts in the buffer." | |
166 (cons form pos)) | |
167 | |
168 (defsubst elint-top-form-form (top-form) | |
169 "Extract the form from a TOP-FORM." | |
170 (car top-form)) | |
171 | |
172 (defsubst elint-top-form-pos (top-form) | |
173 "Extract the position from a TOP-FORM." | |
174 (cdr top-form)) | |
175 | |
176 ;;; | |
177 ;;; ADT: env | |
178 ;;; | |
179 | |
180 (defsubst elint-make-env () | |
181 "Create an empty environment." | |
182 (list (list nil) nil nil)) | |
183 | |
184 (defsubst elint-env-add-env (env newenv) | |
185 "Augment ENV with NEWENV. | |
186 None of them is modified, and the new env is returned." | |
187 (list (append (car env) (car newenv)) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
188 (append (cadr env) (cadr newenv)) |
19210 | 189 (append (car (cdr (cdr env))) (car (cdr (cdr newenv)))))) |
190 | |
191 (defsubst elint-env-add-var (env var) | |
192 "Augment ENV with the variable VAR. | |
193 The new environment is returned, the old is unmodified." | |
194 (cons (cons (list var) (car env)) (cdr env))) | |
195 | |
196 (defsubst elint-env-add-global-var (env var) | |
197 "Augment ENV with the variable VAR. | |
198 ENV is modified so VAR is seen everywhere. | |
199 ENV is returned." | |
200 (nconc (car env) (list (list var))) | |
201 env) | |
202 | |
203 (defsubst elint-env-find-var (env var) | |
204 "Non-nil if ENV contains the variable VAR. | |
205 Actually, a list with VAR as a single element is returned." | |
206 (assq var (car env))) | |
207 | |
208 (defsubst elint-env-add-func (env func args) | |
209 "Augment ENV with the function FUNC, which has the arguments ARGS. | |
210 The new environment is returned, the old is unmodified." | |
211 (list (car env) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
212 (cons (list func args) (cadr env)) |
19210 | 213 (car (cdr (cdr env))))) |
214 | |
215 (defsubst elint-env-find-func (env func) | |
216 "Non-nil if ENV contains the function FUNC. | |
217 Actually, a list of (FUNC ARGS) is returned." | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
218 (assq func (cadr env))) |
19210 | 219 |
220 (defsubst elint-env-add-macro (env macro def) | |
221 "Augment ENV with the macro named MACRO. | |
222 DEF is the macro definition (a lambda expression or similar). | |
223 The new environment is returned, the old is unmodified." | |
224 (list (car env) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
225 (cadr env) |
19210 | 226 (cons (cons macro def) (car (cdr (cdr env)))))) |
227 | |
228 (defsubst elint-env-macro-env (env) | |
229 "Return the macro environment of ENV. | |
230 This environment can be passed to `macroexpand'." | |
231 (car (cdr (cdr env)))) | |
232 | |
233 (defsubst elint-env-macrop (env macro) | |
234 "Non-nil if ENV contains MACRO." | |
235 (assq macro (elint-env-macro-env env))) | |
236 | |
237 ;;; | |
238 ;;; User interface | |
239 ;;; | |
240 | |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
241 ;;;###autoload |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
242 (defun elint-file (file) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
243 "Lint the file FILE." |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
244 (interactive "fElint file: ") |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
245 (setq file (expand-file-name file)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
246 (or elint-builtin-variables |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
247 (elint-initialize)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
248 (let ((dir (file-name-directory file))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
249 (let ((default-directory dir)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
250 (elint-display-log)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
251 (elint-set-mode-line t) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
252 (with-current-buffer elint-log-buffer |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
253 (unless (string-equal default-directory dir) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
254 (elint-log-message (format "\nLeaving directory `%s'" |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
255 default-directory) t) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
256 (elint-log-message (format "Entering directory `%s'" dir) t) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
257 (setq default-directory dir)))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
258 (let ((str (format "Linting file %s" file))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
259 (message "%s..." str) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
260 (or noninteractive |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
261 (elint-log-message (format "\n%s at %s" str (current-time-string)) t)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
262 ;; elint-current-buffer clears log. |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
263 (with-temp-buffer |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
264 (insert-file-contents file) |
104985
25639b195258
(elint-file): Make max-lisp-eval-depth at least 1000.
Glenn Morris <rgm@gnu.org>
parents:
104974
diff
changeset
|
265 (let ((buffer-file-name file) |
25639b195258
(elint-file): Make max-lisp-eval-depth at least 1000.
Glenn Morris <rgm@gnu.org>
parents:
104974
diff
changeset
|
266 (max-lisp-eval-depth (max 1000 max-lisp-eval-depth))) |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
267 (with-syntax-table emacs-lisp-mode-syntax-table |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
268 (mapc 'elint-top-form (elint-update-env))))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
269 (elint-set-mode-line) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
270 (message "%s...done" str))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
271 |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
272 ;; cf byte-recompile-directory. |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
273 ;;;###autoload |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
274 (defun elint-directory (directory) |
105137 | 275 "Lint all the .el files in DIRECTORY. |
276 A complicated directory may require a lot of memory." | |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
277 (interactive "DElint directory: ") |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
278 (let ((elint-running t)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
279 (dolist (file (directory-files directory t)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
280 ;; Bytecomp has emacs-lisp-file-regexp. |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
281 (when (and (string-match "\\.el\\'" file) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
282 (file-readable-p file) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
283 (not (auto-save-file-name-p file))) |
105137 | 284 (if (string-match elint-directory-skip-re file) |
285 (message "Skipping file %s" file) | |
286 (elint-file file))))) | |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
287 (elint-set-mode-line)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
288 |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
289 ;;;###autoload |
19210 | 290 (defun elint-current-buffer () |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
291 "Lint the current buffer. |
107146
149c0b848923
Fix typos in docstrings.
Juanma Barranquero <lekktu@gmail.com>
parents:
106815
diff
changeset
|
292 If necessary, this first calls `elint-initialize'." |
19210 | 293 (interactive) |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
294 (or elint-builtin-variables |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
295 (elint-initialize)) |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
296 (elint-clear-log (format "Linting %s" (or (buffer-file-name) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
297 (buffer-name)))) |
19210 | 298 (elint-display-log) |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
299 (elint-set-mode-line t) |
84899
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
300 (mapc 'elint-top-form (elint-update-env)) |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
301 ;; Tell the user we're finished. This is terribly klugy: we set |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
302 ;; elint-top-form-logged so elint-log-message doesn't print the |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
303 ;; ** top form ** header... |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
304 (elint-set-mode-line) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
305 (elint-log-message "\nLinting finished.\n" t)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
306 |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
307 |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
308 ;;;###autoload |
19210 | 309 (defun elint-defun () |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
310 "Lint the function at point. |
107146
149c0b848923
Fix typos in docstrings.
Juanma Barranquero <lekktu@gmail.com>
parents:
106815
diff
changeset
|
311 If necessary, this first calls `elint-initialize'." |
19210 | 312 (interactive) |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
313 (or elint-builtin-variables |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
314 (elint-initialize)) |
19210 | 315 (save-excursion |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
316 (or (beginning-of-defun) (error "Lint what?")) |
19210 | 317 (let ((pos (point)) |
318 (def (read (current-buffer)))) | |
319 (elint-display-log) | |
320 (elint-update-env) | |
321 (elint-top-form (elint-make-top-form def pos))))) | |
322 | |
323 ;;; | |
324 ;;; Top form functions | |
325 ;;; | |
326 | |
327 (defvar elint-buffer-env nil | |
107146
149c0b848923
Fix typos in docstrings.
Juanma Barranquero <lekktu@gmail.com>
parents:
106815
diff
changeset
|
328 "The environment of an elisp buffer. |
19210 | 329 Will be local in linted buffers.") |
330 | |
331 (defvar elint-buffer-forms nil | |
332 "The top forms in a buffer. | |
333 Will be local in linted buffers.") | |
334 | |
335 (defvar elint-last-env-time nil | |
336 "The last time the buffers env was updated. | |
337 Is measured in buffer-modified-ticks and is local in linted buffers.") | |
338 | |
105137 | 339 ;; This is a minor optimization. It is local to every buffer, and so |
340 ;; does not prevent recursive requirs. It does not list the requires | |
341 ;; of requires. | |
342 (defvar elint-features nil | |
343 "List of all libraries this buffer has required, or that have been provided.") | |
344 | |
19210 | 345 (defun elint-update-env () |
346 "Update the elint environment in the current buffer. | |
347 Don't do anything if the buffer hasn't been changed since this | |
348 function was called the last time. | |
349 Returns the forms." | |
350 (if (and (local-variable-p 'elint-buffer-env (current-buffer)) | |
351 (local-variable-p 'elint-buffer-forms (current-buffer)) | |
352 (local-variable-p 'elint-last-env-time (current-buffer)) | |
353 (= (buffer-modified-tick) elint-last-env-time)) | |
354 ;; Env is up to date | |
355 elint-buffer-forms | |
356 ;; Remake env | |
357 (set (make-local-variable 'elint-buffer-forms) (elint-get-top-forms)) | |
105137 | 358 (set (make-local-variable 'elint-features) nil) |
19210 | 359 (set (make-local-variable 'elint-buffer-env) |
360 (elint-init-env elint-buffer-forms)) | |
105137 | 361 (if elint-preloaded-env |
362 (elint-env-add-env elint-preloaded-env elint-buffer-env)) | |
19210 | 363 (set (make-local-variable 'elint-last-env-time) (buffer-modified-tick)) |
364 elint-buffer-forms)) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
365 |
19210 | 366 (defun elint-get-top-forms () |
367 "Collect all the top forms in the current buffer." | |
368 (save-excursion | |
105137 | 369 (let (tops) |
19210 | 370 (goto-char (point-min)) |
371 (while (elint-find-next-top-form) | |
105137 | 372 (let ((elint-current-pos (point))) |
373 ;; non-list check could be here too. errors may be out of seq. | |
374 ;; quoted check cannot be elsewhere, since quotes skipped. | |
375 (if (looking-back "'") | |
376 ;; Eg cust-print.el uses ' as a comment syntax. | |
377 (elint-warning "Skipping quoted form `'%.20s...'" | |
378 (read (current-buffer))) | |
379 (condition-case nil | |
380 (setq tops (cons | |
381 (elint-make-top-form (read (current-buffer)) | |
382 elint-current-pos) | |
383 tops)) | |
384 (end-of-file | |
385 (goto-char elint-current-pos) | |
386 (error "Missing ')' in top form: %s" | |
387 (buffer-substring elint-current-pos | |
388 (line-end-position)))))))) | |
19210 | 389 (nreverse tops)))) |
390 | |
391 (defun elint-find-next-top-form () | |
392 "Find the next top form from point. | |
42206 | 393 Return nil if there are no more forms, t otherwise." |
19210 | 394 (parse-partial-sexp (point) (point-max) nil t) |
395 (not (eobp))) | |
396 | |
105137 | 397 (defvar env) ; from elint-init-env |
398 | |
399 (defun elint-init-form (form) | |
400 "Process FORM, adding to ENV if recognized." | |
401 (cond | |
402 ;; Eg nnmaildir seems to use [] as a form of comment syntax. | |
403 ((not (listp form)) | |
404 (elint-warning "Skipping non-list form `%s'" form)) | |
405 ;; Add defined variable | |
406 ((memq (car form) '(defvar defconst defcustom)) | |
407 (setq env (elint-env-add-var env (cadr form)))) | |
408 ;; Add function | |
409 ((memq (car form) '(defun defsubst)) | |
410 (setq env (elint-env-add-func env (cadr form) (nth 2 form)))) | |
411 ;; FIXME needs a handler to say second arg is not a variable when we come | |
412 ;; to scan the form. | |
413 ((eq (car form) 'define-derived-mode) | |
414 (setq env (elint-env-add-func env (cadr form) ()) | |
415 env (elint-env-add-var env (cadr form)) | |
416 env (elint-env-add-var env (intern (format "%s-map" (cadr form)))))) | |
417 ((eq (car form) 'define-minor-mode) | |
418 (setq env (elint-env-add-func env (cadr form) '(&optional arg)) | |
419 ;; FIXME mode map? | |
420 env (elint-env-add-var env (cadr form)))) | |
421 ((and (eq (car form) 'easy-menu-define) | |
422 (cadr form)) | |
423 (setq env (elint-env-add-func env (cadr form) '(event)) | |
424 env (elint-env-add-var env (cadr form)))) | |
425 ;; FIXME it would be nice to check the autoloads are correct. | |
426 ((eq (car form) 'autoload) | |
427 (setq env (elint-env-add-func env (cadr (cadr form)) 'unknown))) | |
428 ((eq (car form) 'declare-function) | |
105305
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
429 (setq env (elint-env-add-func |
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
430 env (cadr form) |
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
431 (if (or (< (length form) 4) |
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
432 (eq (nth 3 form) t) |
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
433 (unless (stringp (nth 2 form)) |
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
434 (elint-error "Malformed declaration for `%s'" |
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
435 (cadr form)) |
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
436 t)) |
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
437 'unknown |
76b69a033cf7
(elint-init-form): Report declarations where the filename is not a string.
Glenn Morris <rgm@gnu.org>
parents:
105137
diff
changeset
|
438 (nth 3 form))))) |
105137 | 439 ((and (eq (car form) 'defalias) (listp (nth 2 form))) |
440 ;; If the alias points to something already in the environment, | |
441 ;; add the alias to the environment with the same arguments. | |
442 ;; FIXME symbol-function, eg backquote.el? | |
443 (let ((def (elint-env-find-func env (cadr (nth 2 form))))) | |
444 (setq env (elint-env-add-func env (cadr (cadr form)) | |
445 (if def (cadr def) 'unknown))))) | |
446 ;; Add macro, both as a macro and as a function | |
447 ((eq (car form) 'defmacro) | |
448 (setq env (elint-env-add-macro env (cadr form) | |
449 (cons 'lambda (cddr form))) | |
450 env (elint-env-add-func env (cadr form) (nth 2 form)))) | |
451 ((and (eq (car form) 'put) | |
452 (= 4 (length form)) | |
453 (eq (car-safe (cadr form)) 'quote) | |
454 (equal (nth 2 form) '(quote error-conditions))) | |
455 (set (make-local-variable 'elint-extra-errors) | |
456 (cons (cadr (cadr form)) elint-extra-errors))) | |
457 ((eq (car form) 'provide) | |
458 (add-to-list 'elint-features (eval (cadr form)))) | |
459 ;; Import variable definitions | |
460 ((memq (car form) '(require cc-require cc-require-when-compile)) | |
461 (let ((name (eval (cadr form))) | |
462 (file (eval (nth 2 form))) | |
463 (elint-doing-cl (bound-and-true-p elint-doing-cl))) | |
464 (unless (memq name elint-features) | |
465 (add-to-list 'elint-features name) | |
466 ;; cl loads cl-macs in an opaque manner. | |
467 ;; Since cl-macs requires cl, we can just process cl-macs. | |
468 (and (eq name 'cl) (not elint-doing-cl) | |
469 ;; We need cl if elint-form is to be able to expand cl macros. | |
470 (require 'cl) | |
471 (setq name 'cl-macs | |
472 file nil | |
473 elint-doing-cl t)) ; blech | |
474 (setq env (elint-add-required-env env name file)))))) | |
475 env) | |
476 | |
19210 | 477 (defun elint-init-env (forms) |
63511
964ef053b1bc
(elint-init-env): Fix spelling in docstrings.
Juanma Barranquero <lekktu@gmail.com>
parents:
59506
diff
changeset
|
478 "Initialize the environment from FORMS." |
19210 | 479 (let ((env (elint-make-env)) |
480 form) | |
481 (while forms | |
482 (setq form (elint-top-form-form (car forms)) | |
483 forms (cdr forms)) | |
105137 | 484 ;; FIXME eval-when-compile should be treated differently (macros). |
485 ;; Could bind something that makes elint-init-form only check | |
486 ;; defmacros. | |
487 (if (memq (car-safe form) | |
488 '(eval-and-compile eval-when-compile progn prog1 prog2 | |
489 with-no-warnings)) | |
490 (mapc 'elint-init-form (cdr form)) | |
491 (elint-init-form form))) | |
19210 | 492 env)) |
493 | |
494 (defun elint-add-required-env (env name file) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
495 "Augment ENV with the variables defined by feature NAME in FILE." |
106226
85863d02e2db
* emacs-lisp/elint.el (elint-add-required-env): Better error message
Kevin Ryde <user42@zip.com.au>
parents:
106017
diff
changeset
|
496 (condition-case err |
19210 | 497 (let* ((libname (if (stringp file) |
498 file | |
499 (symbol-name name))) | |
500 | |
501 ;; First try to find .el files, then the raw name | |
502 (lib1 (locate-library (concat libname ".el") t)) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
503 (lib (or lib1 (locate-library libname t)))) |
19210 | 504 ;; Clear the messages :-/ |
105137 | 505 ;; (Messes up the "Initializing elint..." message.) |
506 ;;; (message nil) | |
19210 | 507 (if lib |
107252
2da9673fc448
Fix more save-excursion warnings.
Chong Yidong <cyd@stupidchicken.com>
parents:
107146
diff
changeset
|
508 (with-current-buffer (find-file-noselect lib) |
105008
b9b9c3b2718d
(elint-add-required-env): Revert to not using temp-buffers (2009-09-12).
Glenn Morris <rgm@gnu.org>
parents:
104989
diff
changeset
|
509 ;; FIXME this doesn't use a temp buffer, because it |
b9b9c3b2718d
(elint-add-required-env): Revert to not using temp-buffers (2009-09-12).
Glenn Morris <rgm@gnu.org>
parents:
104989
diff
changeset
|
510 ;; stores the result in buffer-local variables so that |
b9b9c3b2718d
(elint-add-required-env): Revert to not using temp-buffers (2009-09-12).
Glenn Morris <rgm@gnu.org>
parents:
104989
diff
changeset
|
511 ;; it can be reused. |
105137 | 512 (elint-update-env) |
513 (setq env (elint-env-add-env env elint-buffer-env))) | |
105008
b9b9c3b2718d
(elint-add-required-env): Revert to not using temp-buffers (2009-09-12).
Glenn Morris <rgm@gnu.org>
parents:
104989
diff
changeset
|
514 ;;; (with-temp-buffer |
b9b9c3b2718d
(elint-add-required-env): Revert to not using temp-buffers (2009-09-12).
Glenn Morris <rgm@gnu.org>
parents:
104989
diff
changeset
|
515 ;;; (insert-file-contents lib) |
b9b9c3b2718d
(elint-add-required-env): Revert to not using temp-buffers (2009-09-12).
Glenn Morris <rgm@gnu.org>
parents:
104989
diff
changeset
|
516 ;;; (with-syntax-table emacs-lisp-mode-syntax-table |
b9b9c3b2718d
(elint-add-required-env): Revert to not using temp-buffers (2009-09-12).
Glenn Morris <rgm@gnu.org>
parents:
104989
diff
changeset
|
517 ;;; (elint-update-env)) |
b9b9c3b2718d
(elint-add-required-env): Revert to not using temp-buffers (2009-09-12).
Glenn Morris <rgm@gnu.org>
parents:
104989
diff
changeset
|
518 ;;; (setq env (elint-env-add-env env elint-buffer-env)))) |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
519 ;;(message "Elint processed (require '%s)" name)) |
106226
85863d02e2db
* emacs-lisp/elint.el (elint-add-required-env): Better error message
Kevin Ryde <user42@zip.com.au>
parents:
106017
diff
changeset
|
520 (error "%s.el not found in load-path" libname))) |
19210 | 521 (error |
106226
85863d02e2db
* emacs-lisp/elint.el (elint-add-required-env): Better error message
Kevin Ryde <user42@zip.com.au>
parents:
106017
diff
changeset
|
522 (message "Can't get variables from require'd library %s: %s" |
85863d02e2db
* emacs-lisp/elint.el (elint-add-required-env): Better error message
Kevin Ryde <user42@zip.com.au>
parents:
106017
diff
changeset
|
523 name (error-message-string err)))) |
19210 | 524 env) |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
525 |
19210 | 526 (defvar elint-top-form nil |
527 "The currently linted top form, or nil.") | |
528 | |
529 (defvar elint-top-form-logged nil | |
107146
149c0b848923
Fix typos in docstrings.
Juanma Barranquero <lekktu@gmail.com>
parents:
106815
diff
changeset
|
530 "The value t if the currently linted top form has been mentioned in the log buffer.") |
19210 | 531 |
532 (defun elint-top-form (form) | |
533 "Lint a top FORM." | |
534 (let ((elint-top-form form) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
535 (elint-top-form-logged nil) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
536 (elint-current-pos (elint-top-form-pos form))) |
19210 | 537 (elint-form (elint-top-form-form form) elint-buffer-env))) |
538 | |
539 ;;; | |
540 ;;; General form linting functions | |
541 ;;; | |
542 | |
543 (defconst elint-special-forms | |
544 '((let . elint-check-let-form) | |
545 (let* . elint-check-let-form) | |
546 (setq . elint-check-setq-form) | |
547 (quote . elint-check-quote-form) | |
105137 | 548 (function . elint-check-quote-form) |
19210 | 549 (cond . elint-check-cond-form) |
550 (lambda . elint-check-defun-form) | |
551 (function . elint-check-function-form) | |
552 (setq-default . elint-check-setq-form) | |
105137 | 553 (defalias . elint-check-defalias-form) |
19210 | 554 (defun . elint-check-defun-form) |
555 (defsubst . elint-check-defun-form) | |
556 (defmacro . elint-check-defun-form) | |
557 (defvar . elint-check-defvar-form) | |
558 (defconst . elint-check-defvar-form) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
559 (defcustom . elint-check-defcustom-form) |
19210 | 560 (macro . elint-check-macro-form) |
105137 | 561 (condition-case . elint-check-condition-case-form) |
562 (if . elint-check-conditional-form) | |
563 (when . elint-check-conditional-form) | |
564 (unless . elint-check-conditional-form) | |
565 (and . elint-check-conditional-form) | |
566 (or . elint-check-conditional-form)) | |
19210 | 567 "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
|
568 |
105137 | 569 (defun elint-form (form env &optional nohandler) |
19210 | 570 "Lint FORM in the environment ENV. |
105137 | 571 Optional argument NOHANDLER non-nil means ignore `elint-special-forms'. |
572 Returns the environment created by the form." | |
19210 | 573 (cond |
574 ((consp form) | |
575 (let ((func (cdr (assq (car form) elint-special-forms)))) | |
105137 | 576 (if (and func (not nohandler)) |
19210 | 577 ;; Special form |
578 (funcall func form env) | |
579 | |
580 (let* ((func (car form)) | |
581 (args (elint-get-args func env)) | |
582 (argsok t)) | |
583 (cond | |
584 ((eq args 'undefined) | |
585 (setq argsok nil) | |
105137 | 586 (or (memq 'undefined-functions elint-ignored-warnings) |
587 (elint-error "Call to undefined function: %s" func))) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
588 |
19210 | 589 ((eq args 'unknown) nil) |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
590 |
19210 | 591 (t (setq argsok (elint-match-args form args)))) |
592 | |
593 ;; Is this a macro? | |
594 (if (elint-env-macrop env func) | |
595 ;; Macro defined in buffer, expand it | |
596 (if argsok | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
597 ;; FIXME error if macro uses macro, eg bytecomp.el. |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
598 (condition-case nil |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
599 (elint-form |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
600 (macroexpand form (elint-env-macro-env env)) env) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
601 (error |
105137 | 602 (or (memq 'macro-expansion elint-ignored-warnings) |
603 (elint-error "Elint failed to expand macro: %s" func)) | |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
604 env)) |
19210 | 605 env) |
606 | |
607 (let ((fcode (if (symbolp func) | |
608 (if (fboundp func) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
609 (indirect-function func)) |
19210 | 610 func))) |
611 (if (and (listp fcode) (eq (car fcode) 'macro)) | |
612 ;; Macro defined outside buffer | |
613 (if argsok | |
614 (elint-form (macroexpand form) env) | |
615 env) | |
616 ;; Function, lint its parameters | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
617 (elint-forms (cdr form) env)))))))) |
19210 | 618 ((symbolp form) |
619 ;; :foo variables are quoted | |
105137 | 620 (and (/= (aref (symbol-name form) 0) ?:) |
621 (not (memq 'unbound-reference elint-ignored-warnings)) | |
622 (elint-unbound-variable form env) | |
623 (elint-warning "Reference to unbound symbol: %s" form)) | |
19210 | 624 env) |
625 | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
626 (t env))) |
19210 | 627 |
628 (defun elint-forms (forms env) | |
629 "Lint the FORMS, accumulating an environment, starting with ENV." | |
630 ;; grumblegrumbletailrecursiongrumblegrumble | |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
631 (if (listp forms) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
632 (dolist (f forms env) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
633 (setq env (elint-form f env))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
634 ;; Loop macro? |
104985
25639b195258
(elint-file): Make max-lisp-eval-depth at least 1000.
Glenn Morris <rgm@gnu.org>
parents:
104974
diff
changeset
|
635 (elint-error "Elint failed to parse form: %s" forms) |
25639b195258
(elint-file): Make max-lisp-eval-depth at least 1000.
Glenn Morris <rgm@gnu.org>
parents:
104974
diff
changeset
|
636 env)) |
19210 | 637 |
105137 | 638 (defvar elint-bound-variable nil |
639 "Name of a temporarily bound symbol.") | |
640 | |
19210 | 641 (defun elint-unbound-variable (var env) |
107146
149c0b848923
Fix typos in docstrings.
Juanma Barranquero <lekktu@gmail.com>
parents:
106815
diff
changeset
|
642 "Return t if VAR is unbound in ENV." |
106017
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
643 ;; #1063 suggests adding (symbol-file var) here, but I don't think |
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
644 ;; this is right, because it depends on what files you happen to have |
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
645 ;; loaded at the time, which might not be the same when the code runs. |
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
646 ;; It also suggests adding: |
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
647 ;; (numberp (get var 'variable-documentation)) |
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
648 ;; (numberp (cdr-safe (get var 'variable-documentation))) |
660fd54d2835
(elint-standard-variables): Doc fix.
Glenn Morris <rgm@gnu.org>
parents:
106016
diff
changeset
|
649 ;; but this is not needed now elint-scan-doc-file exists. |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
650 (not (or (memq var '(nil t)) |
105137 | 651 (eq var elint-bound-variable) |
19210 | 652 (elint-env-find-var env var) |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
653 (memq var elint-builtin-variables) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
654 (memq var elint-autoloaded-variables) |
19210 | 655 (memq var elint-standard-variables)))) |
656 | |
657 ;;; | |
658 ;;; Function argument checking | |
659 ;;; | |
660 | |
661 (defun elint-match-args (arglist argpattern) | |
662 "Match ARGLIST against ARGPATTERN." | |
663 (let ((state 'all) | |
664 (al (cdr arglist)) | |
665 (ap argpattern) | |
666 (ok t)) | |
667 (while | |
668 (cond | |
669 ((and (null al) (null ap)) nil) | |
670 ((eq (car ap) '&optional) | |
671 (setq state 'optional) | |
672 (setq ap (cdr ap)) | |
673 t) | |
674 ((eq (car ap) '&rest) | |
675 nil) | |
676 ((or (and (eq state 'all) (or (null al) (null ap))) | |
677 (and (eq state 'optional) (and al (null ap)))) | |
678 (elint-error "Wrong number of args: %s, %s" arglist argpattern) | |
679 (setq ok nil) | |
680 nil) | |
681 ((and (eq state 'optional) (null al)) | |
682 nil) | |
683 (t (setq al (cdr al) | |
684 ap (cdr ap)) | |
685 t))) | |
686 ok)) | |
687 | |
105137 | 688 (defvar elint-bound-function nil |
689 "Name of a temporarily bound function symbol.") | |
690 | |
19210 | 691 (defun elint-get-args (func env) |
692 "Find the args of FUNC in ENV. | |
693 Returns `unknown' if we couldn't find arguments." | |
694 (let ((f (elint-env-find-func env func))) | |
695 (if f | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
696 (cadr f) |
19210 | 697 (if (symbolp func) |
105137 | 698 (if (eq func elint-bound-function) |
699 'unknown | |
700 (if (fboundp func) | |
701 (let ((fcode (indirect-function func))) | |
702 (if (subrp fcode) | |
703 ;; FIXME builtins with no args have args = nil. | |
704 (or (get func 'elint-args) 'unknown) | |
705 (elint-find-args-in-code fcode))) | |
706 'undefined)) | |
19210 | 707 (elint-find-args-in-code func))))) |
708 | |
709 (defun elint-find-args-in-code (code) | |
710 "Extract the arguments from CODE. | |
711 CODE can be a lambda expression, a macro, or byte-compiled code." | |
712 (cond | |
713 ((byte-code-function-p code) | |
714 (aref code 0)) | |
715 ((and (listp code) (eq (car code) 'lambda)) | |
716 (car (cdr code))) | |
717 ((and (listp code) (eq (car code) 'macro)) | |
718 (elint-find-args-in-code (cdr code))) | |
719 (t 'unknown))) | |
720 | |
721 ;;; | |
722 ;;; Functions to check some special forms | |
723 ;;; | |
724 | |
725 (defun elint-check-cond-form (form env) | |
726 "Lint a cond FORM in ENV." | |
105137 | 727 (dolist (f (cdr form)) |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
728 (if (consp f) |
105137 | 729 (let ((test (car f))) |
730 (cond ((equal test '(featurep (quote xemacs)))) | |
731 ((equal test '(not (featurep (quote emacs))))) | |
732 ;; FIXME (and (boundp 'foo) | |
733 ((and (eq (car-safe test) 'fboundp) | |
734 (= 2 (length test)) | |
735 (eq (car-safe (cadr test)) 'quote)) | |
736 (let ((elint-bound-function (cadr (cadr test)))) | |
737 (elint-forms f env))) | |
738 ((and (eq (car-safe test) 'boundp) | |
739 (= 2 (length test)) | |
740 (eq (car-safe (cadr test)) 'quote)) | |
741 (let ((elint-bound-variable (cadr (cadr test)))) | |
742 (elint-forms f env))) | |
743 (t (elint-forms f env)))) | |
744 (elint-error "cond clause should be a list: %s" f))) | |
745 env) | |
19210 | 746 |
747 (defun elint-check-defun-form (form env) | |
748 "Lint a defun/defmacro/lambda FORM in ENV." | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
749 (setq form (if (eq (car form) 'lambda) (cdr form) (cddr form))) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
750 (mapc (lambda (p) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
751 (or (memq p '(&optional &rest)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
752 (setq env (elint-env-add-var env p)))) |
84899
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
753 (car form)) |
19210 | 754 (elint-forms (cdr form) env)) |
755 | |
105137 | 756 (defun elint-check-defalias-form (form env) |
757 "Lint a defalias FORM in ENV." | |
758 (let ((alias (cadr form)) | |
759 (target (nth 2 form))) | |
760 (and (eq (car-safe alias) 'quote) | |
761 (eq (car-safe target) 'quote) | |
762 (eq (elint-get-args (cadr target) env) 'undefined) | |
763 (elint-warning "Alias `%s' has unknown target `%s'" | |
764 (cadr alias) (cadr target)))) | |
765 (elint-form form env t)) | |
766 | |
19210 | 767 (defun elint-check-let-form (form env) |
768 "Lint the let/let* FORM in ENV." | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
769 (let ((varlist (cadr form))) |
19210 | 770 (if (not varlist) |
105137 | 771 (if (> (length form) 2) |
772 ;; An empty varlist is not really an error. Eg some cl macros | |
773 ;; can expand to such a form. | |
774 (progn | |
775 (or (memq 'empty-let elint-ignored-warnings) | |
776 (elint-warning "Empty varlist in let: %s" form)) | |
777 ;; Lint the body forms | |
778 (elint-forms (cddr form) env)) | |
779 (elint-error "Malformed let: %s" form) | |
19210 | 780 env) |
781 ;; Check for (let (a (car b)) ...) type of error | |
782 (if (and (= (length varlist) 2) | |
783 (symbolp (car varlist)) | |
784 (listp (car (cdr varlist))) | |
785 (fboundp (car (car (cdr varlist))))) | |
786 (elint-warning "Suspect varlist: %s" form)) | |
787 ;; Add variables to environment, and check the init values | |
788 (let ((newenv env)) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
789 (mapc (lambda (s) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
790 (cond |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
791 ((symbolp s) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
792 (setq newenv (elint-env-add-var newenv s))) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
793 ((and (consp s) (<= (length s) 2)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
794 (elint-form (cadr s) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
795 (if (eq (car form) 'let) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
796 env |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
797 newenv)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
798 (setq newenv |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
799 (elint-env-add-var newenv (car s)))) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
800 (t (elint-error |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
801 "Malformed `let' declaration: %s" s)))) |
84899
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
802 varlist) |
19210 | 803 |
804 ;; Lint the body forms | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
805 (elint-forms (cddr form) newenv))))) |
19210 | 806 |
807 (defun elint-check-setq-form (form env) | |
808 "Lint the setq FORM in ENV." | |
809 (or (= (mod (length form) 2) 1) | |
105137 | 810 ;; (setq foo) is valid and equivalent to (setq foo nil). |
811 (elint-warning "Missing value in setq: %s" form)) | |
19210 | 812 (let ((newenv env) |
813 sym val) | |
814 (setq form (cdr form)) | |
815 (while form | |
816 (setq sym (car form) | |
817 val (car (cdr form)) | |
818 form (cdr (cdr form))) | |
819 (if (symbolp sym) | |
105137 | 820 (and (not (memq 'unbound-assignment elint-ignored-warnings)) |
821 (elint-unbound-variable sym newenv) | |
822 (elint-warning "Setting previously unbound symbol: %s" sym)) | |
19210 | 823 (elint-error "Setting non-symbol in setq: %s" sym)) |
824 (elint-form val newenv) | |
825 (if (symbolp sym) | |
826 (setq newenv (elint-env-add-var newenv sym)))) | |
827 newenv)) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
828 |
19210 | 829 (defun elint-check-defvar-form (form env) |
830 "Lint the defvar/defconst FORM in ENV." | |
831 (if (or (= (length form) 2) | |
832 (= (length form) 3) | |
105137 | 833 ;; Eg the defcalcmodevar macro can expand with a nil doc-string. |
834 (and (= (length form) 4) (string-or-null-p (nth 3 form)))) | |
19210 | 835 (elint-env-add-global-var (elint-form (nth 2 form) env) |
836 (car (cdr form))) | |
837 (elint-error "Malformed variable declaration: %s" form) | |
838 env)) | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
839 |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
840 (defun elint-check-defcustom-form (form env) |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
841 "Lint the defcustom FORM in ENV." |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
842 (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
|
843 ;; 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
|
844 (zerop (logand (length form) 1))) |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
845 (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
|
846 (car (cdr form))) |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
847 (elint-error "Malformed variable declaration: %s" form) |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
848 env)) |
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
849 |
19210 | 850 (defun elint-check-function-form (form env) |
851 "Lint the function FORM in ENV." | |
852 (let ((func (car (cdr-safe form)))) | |
853 (cond | |
854 ((symbolp func) | |
855 (or (elint-env-find-func env func) | |
105137 | 856 ;; FIXME potentially bogus, since it uses the current |
857 ;; environment rather than a clean one. | |
19210 | 858 (fboundp func) |
859 (elint-warning "Reference to undefined function: %s" form)) | |
860 env) | |
861 ((and (consp func) (memq (car func) '(lambda macro))) | |
862 (elint-form func env)) | |
863 ((stringp func) env) | |
864 (t (elint-error "Not a function object: %s" form) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
865 env)))) |
19210 | 866 |
867 (defun elint-check-quote-form (form env) | |
868 "Lint the quote FORM in ENV." | |
869 env) | |
870 | |
871 (defun elint-check-macro-form (form env) | |
872 "Check the macro FORM in ENV." | |
873 (elint-check-function-form (list (car form) (cdr form)) env)) | |
874 | |
875 (defun elint-check-condition-case-form (form env) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
876 "Check the `condition-case' FORM in ENV." |
19210 | 877 (let ((resenv env)) |
878 (if (< (length form) 3) | |
879 (elint-error "Malformed condition-case: %s" form) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
880 (or (symbolp (cadr form)) |
19210 | 881 (elint-warning "First parameter should be a symbol: %s" form)) |
882 (setq resenv (elint-form (nth 2 form) env)) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
883 (let ((newenv (elint-env-add-var env (cadr form))) |
19210 | 884 errlist) |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
885 (dolist (err (nthcdr 3 form)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
886 (setq errlist (car err)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
887 (mapc (lambda (s) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
888 (or (get s 'error-conditions) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
889 (get s 'error-message) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
890 (memq s elint-extra-errors) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
891 (elint-warning |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
892 "Not an error symbol in error handler: %s" s))) |
84899
789f9201f375
(elint-current-buffer, elint-check-defun-form, elint-check-let-form,
Juanma Barranquero <lekktu@gmail.com>
parents:
78217
diff
changeset
|
893 (cond |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
894 ((symbolp errlist) (list errlist)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
895 ((listp errlist) errlist) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
896 (t (elint-error "Bad error list in error handler: %s" |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
897 errlist) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
898 nil))) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
899 (elint-forms (cdr err) newenv)))) |
19210 | 900 resenv)) |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
901 |
105137 | 902 ;; For the featurep parts, an alternative is to have |
903 ;; elint-get-top-forms skip the irrelevant branches. | |
904 (defun elint-check-conditional-form (form env) | |
905 "Check the when/unless/and/or FORM in ENV. | |
906 Does basic handling of `featurep' tests." | |
907 (let ((func (car form)) | |
908 (test (cadr form)) | |
909 sym) | |
910 ;; Misses things like (and t (featurep 'xemacs)) | |
911 ;; Check byte-compile-maybe-guarded. | |
912 (cond ((and (memq func '(when and)) | |
913 (eq (car-safe test) 'boundp) | |
914 (= 2 (length test)) | |
915 (eq (car-safe (cadr test)) 'quote)) | |
916 ;; Cf elint-check-let-form, which modifies the whole ENV. | |
917 (let ((elint-bound-variable (cadr (cadr test)))) | |
918 (elint-form form env t))) | |
919 ((and (memq func '(when and)) | |
920 (eq (car-safe test) 'fboundp) | |
921 (= 2 (length test)) | |
922 (eq (car-safe (cadr test)) 'quote)) | |
923 (let ((elint-bound-function (cadr (cadr test)))) | |
924 (elint-form form env t))) | |
925 ;; Let's not worry about (if (not (boundp... | |
926 ((and (eq func 'if) | |
927 (eq (car-safe test) 'boundp) | |
928 (= 2 (length test)) | |
929 (eq (car-safe (cadr test)) 'quote)) | |
930 (let ((elint-bound-variable (cadr (cadr test)))) | |
931 (elint-form (nth 2 form) env)) | |
932 (dolist (f (nthcdr 3 form)) | |
933 (elint-form f env))) | |
934 ((and (eq func 'if) | |
935 (eq (car-safe test) 'fboundp) | |
936 (= 2 (length test)) | |
937 (eq (car-safe (cadr test)) 'quote)) | |
938 (let ((elint-bound-function (cadr (cadr test)))) | |
939 (elint-form (nth 2 form) env)) | |
940 (dolist (f (nthcdr 3 form)) | |
941 (elint-form f env))) | |
942 ((and (memq func '(when and)) ; skip all | |
943 (or (null test) | |
944 (member test '((featurep (quote xemacs)) | |
945 (not (featurep (quote emacs))))) | |
946 (and (eq (car-safe test) 'and) | |
947 (equal (car-safe (cdr test)) | |
948 '(featurep (quote xemacs))))))) | |
949 ((and (memq func '(unless or)) | |
950 (equal test '(featurep (quote emacs))))) | |
951 ((and (eq func 'if) | |
952 (or (null test) ; eg custom-browse-insert-prefix | |
953 (member test '((featurep (quote xemacs)) | |
954 (not (featurep (quote emacs))))) | |
955 (and (eq (car-safe test) 'and) | |
956 (equal (car-safe (cdr test)) | |
957 '(featurep (quote xemacs)))))) | |
958 (dolist (f (nthcdr 3 form)) | |
959 (elint-form f env))) ; lint the else branch | |
960 ((and (eq func 'if) | |
961 (equal test '(featurep (quote emacs)))) | |
962 (elint-form (nth 2 form) env)) ; lint the if branch | |
963 ;; Process conditional as normal, without handler. | |
964 (t | |
965 (elint-form form env t)))) | |
966 env) | |
967 | |
19210 | 968 ;;; |
969 ;;; Message functions | |
970 ;;; | |
971 | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
972 (defvar elint-current-pos) ; dynamically bound in elint-top-form |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
973 |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
974 (defun elint-log (type string args) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
975 (elint-log-message (format "%s:%d:%s: %s" |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
976 (let ((f (buffer-file-name))) |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
977 (if f |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
978 (file-name-nondirectory f) |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
979 (buffer-name))) |
104989
bbe883d49650
(elint-init-env): Skip non-list forms.
Glenn Morris <rgm@gnu.org>
parents:
104985
diff
changeset
|
980 (if (boundp 'elint-current-pos) |
bbe883d49650
(elint-init-env): Skip non-list forms.
Glenn Morris <rgm@gnu.org>
parents:
104985
diff
changeset
|
981 (save-excursion |
bbe883d49650
(elint-init-env): Skip non-list forms.
Glenn Morris <rgm@gnu.org>
parents:
104985
diff
changeset
|
982 (goto-char elint-current-pos) |
bbe883d49650
(elint-init-env): Skip non-list forms.
Glenn Morris <rgm@gnu.org>
parents:
104985
diff
changeset
|
983 (1+ (count-lines (point-min) |
bbe883d49650
(elint-init-env): Skip non-list forms.
Glenn Morris <rgm@gnu.org>
parents:
104985
diff
changeset
|
984 (line-beginning-position)))) |
bbe883d49650
(elint-init-env): Skip non-list forms.
Glenn Morris <rgm@gnu.org>
parents:
104985
diff
changeset
|
985 0) ; unknown position |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
986 type |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
987 (apply 'format string args)))) |
19210 | 988 |
989 (defun elint-error (string &rest args) | |
47923
07d91c802db4
(elint-error, elint-warning): Fix typo.
Juanma Barranquero <lekktu@gmail.com>
parents:
42268
diff
changeset
|
990 "Report a linting error. |
19210 | 991 STRING and ARGS are thrown on `format' to get the message." |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
992 (elint-log "Error" string args)) |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
993 |
19210 | 994 (defun elint-warning (string &rest args) |
47923
07d91c802db4
(elint-error, elint-warning): Fix typo.
Juanma Barranquero <lekktu@gmail.com>
parents:
42268
diff
changeset
|
995 "Report a linting warning. |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
996 See `elint-error'." |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
997 (elint-log "Warning" string args)) |
19210 | 998 |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
999 (defun elint-output (string) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1000 "Print or insert STRING, depending on value of `noninteractive'." |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1001 (if noninteractive |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1002 (message "%s" string) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1003 (insert string "\n"))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1004 |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1005 (defun elint-log-message (errstr &optional top) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1006 "Insert ERRSTR last in the lint log buffer. |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1007 Optional argument TOP non-nil means pretend `elint-top-form-logged' is non-nil." |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1008 (with-current-buffer (elint-get-log-buffer) |
19210 | 1009 (goto-char (point-max)) |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1010 (let ((inhibit-read-only t)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1011 (or (bolp) (newline)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1012 ;; Do we have to say where we are? |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1013 (unless (or elint-top-form-logged top) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1014 (let* ((form (elint-top-form-form elint-top-form)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1015 (top (car form))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1016 (elint-output (cond |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1017 ((memq top '(defun defsubst)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1018 (format "\nIn function %s:" (cadr form))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1019 ((eq top 'defmacro) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1020 (format "\nIn macro %s:" (cadr form))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1021 ((memq top '(defvar defconst)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1022 (format "\nIn variable %s:" (cadr form))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1023 (t "\nIn top level expression:")))) |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1024 (setq elint-top-form-logged t)) |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1025 (elint-output errstr)))) |
19210 | 1026 |
1027 (defun elint-clear-log (&optional header) | |
1028 "Clear the lint log buffer. | |
1029 Insert HEADER followed by a blank line if non-nil." | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1030 (let ((dir default-directory)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1031 (with-current-buffer (elint-get-log-buffer) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1032 (setq default-directory dir) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1033 (let ((inhibit-read-only t)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1034 (erase-buffer) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1035 (if header (insert header "\n")))))) |
19210 | 1036 |
1037 (defun elint-display-log () | |
1038 "Display the lint log buffer." | |
1039 (let ((pop-up-windows t)) | |
1040 (display-buffer (elint-get-log-buffer)) | |
1041 (sit-for 0))) | |
1042 | |
104974
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1043 (defvar elint-running) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1044 |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1045 (defun elint-set-mode-line (&optional on) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1046 "Set the mode-line-process of the Elint log buffer." |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1047 (with-current-buffer (elint-get-log-buffer) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1048 (and (eq major-mode 'compilation-mode) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1049 (setq mode-line-process |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1050 (list (if (or on (bound-and-true-p elint-running)) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1051 (propertize ":run" 'face 'compilation-warning) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1052 (propertize ":finished" 'face 'compilation-info))))))) |
646ba543ede9
(elint-file, elint-directory): New autoloaded commands.
Glenn Morris <rgm@gnu.org>
parents:
104049
diff
changeset
|
1053 |
19210 | 1054 (defun elint-get-log-buffer () |
1055 "Return a log buffer for elint." | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1056 (or (get-buffer elint-log-buffer) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1057 (with-current-buffer (get-buffer-create elint-log-buffer) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1058 (or (eq major-mode 'compilation-mode) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1059 (compilation-mode)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1060 (setq buffer-undo-list t) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1061 (current-buffer)))) |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
1062 |
19210 | 1063 ;;; |
1064 ;;; Initializing code | |
1065 ;;; | |
20014
2ecea967337d
(elint-check-defcustom-form): New function.
Karl Heuer <kwzh@gnu.org>
parents:
19210
diff
changeset
|
1066 |
105137 | 1067 (defun elint-put-function-args (func args) |
1068 "Mark function FUNC as having argument list ARGS." | |
1069 (and (symbolp func) | |
1070 args | |
1071 (not (eq args 'unknown)) | |
1072 (put func 'elint-args args))) | |
1073 | |
19210 | 1074 ;;;###autoload |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1075 (defun elint-initialize (&optional reinit) |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1076 "Initialize elint. |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1077 If elint is already initialized, this does nothing, unless |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1078 optional prefix argument REINIT is non-nil." |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1079 (interactive "P") |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1080 (if (and elint-builtin-variables (not reinit)) |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1081 (message "Elint is already initialized") |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1082 (message "Initializing elint...") |
105137 | 1083 (setq elint-builtin-variables (elint-scan-doc-file) |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1084 elint-autoloaded-variables (elint-find-autoloaded-variables)) |
105137 | 1085 (mapc (lambda (x) (elint-put-function-args (car x) (cdr x))) |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1086 (elint-find-builtin-args)) |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1087 (if elint-unknown-builtin-args |
105137 | 1088 (mapc (lambda (x) (elint-put-function-args (car x) (cdr x))) |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1089 elint-unknown-builtin-args)) |
105137 | 1090 (when elint-scan-preloaded |
1091 (dolist (lib preloaded-file-list) | |
1092 ;; Skip files that contain nothing of use to us. | |
1093 (unless (string-match elint-preloaded-skip-re lib) | |
1094 (setq elint-preloaded-env | |
1095 (elint-add-required-env elint-preloaded-env nil lib))))) | |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1096 (message "Initializing elint...done"))) |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1097 |
19210 | 1098 |
105137 | 1099 ;; This includes all the built-in and dumped things with documentation. |
1100 (defun elint-scan-doc-file () | |
1101 "Scan the DOC file for function and variables. | |
1102 Marks the function wih their arguments, and returns a list of variables." | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1103 ;; Cribbed from help-fns.el. |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1104 (let ((docbuf " *DOC*") |
105137 | 1105 vars sym args) |
104049
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1106 (save-excursion |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1107 (if (get-buffer docbuf) |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1108 (progn |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1109 (set-buffer docbuf) |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1110 (goto-char (point-min))) |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1111 (set-buffer (get-buffer-create docbuf)) |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1112 (insert-file-contents-literally |
7fcfa9c429bd
(elint-current-buffer, elint-defun):
Glenn Morris <rgm@gnu.org>
parents:
104036
diff
changeset
|
1113 (expand-file-name internal-doc-file-name doc-directory))) |
105137 | 1114 (while (re-search-forward "\\([VF]\\)" nil t) |
1115 (when (setq sym (intern-soft (buffer-substring (point) | |
1116 (line-end-position)))) | |
1117 (if (string-equal (match-string 1) "V") | |
1118 ;; Excludes platform-specific stuff not relevant to the | |
1119 ;; running platform. | |
1120 (if (boundp sym) (setq vars (cons sym vars))) | |
1121 ;; Function. | |
1122 (when (fboundp sym) | |
1123 (when (re-search-forward "\\(^(fn.*)\\)?" nil t) | |
1124 (backward-char 1) | |
1125 ;; FIXME distinguish no args from not found. | |
1126 (and (setq args (match-string 1)) | |
1127 (setq args | |
1128 (ignore-errors | |
1129 (read | |
1130 (replace-regexp-in-string "^(fn ?" "(" args)))) | |
1131 (elint-put-function-args sym args)))))))) | |
1132 vars)) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1133 |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1134 (defun elint-find-autoloaded-variables () |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1135 "Return a list of all autoloaded variables." |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1136 (let (var vars) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1137 (with-temp-buffer |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1138 (insert-file-contents (locate-library "loaddefs.el")) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1139 (while (re-search-forward "^(defvar \\([[:alnum:]_-]+\\)" nil t) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1140 (and (setq var (intern-soft (match-string 1))) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1141 (boundp var) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1142 (setq vars (cons var vars))))) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1143 vars)) |
19210 | 1144 |
1145 (defun elint-find-builtins () | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1146 "Return a list of all built-in functions." |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1147 (let (subrs) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1148 (mapatoms (lambda (s) (and (fboundp s) (subrp (symbol-function s)) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1149 (setq subrs (cons s subrs))))) |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1150 subrs)) |
19210 | 1151 |
1152 (defun elint-find-builtin-args (&optional list) | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1153 "Return a list of the built-in functions and their arguments. |
19210 | 1154 If LIST is nil, call `elint-find-builtins' to get a list of all built-in |
1155 functions, otherwise use LIST. | |
1156 | |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1157 Each function is represented by a cons cell: |
19210 | 1158 \(function-symbol . args) |
1159 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
|
1160 (mapcar (lambda (f) |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
1161 (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
|
1162 (or (and doc |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
1163 (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
|
1164 (ignore-errors |
104036
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1165 ;; "BODY...)" -> "&rest BODY)". |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1166 (read (replace-regexp-in-string |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1167 "\\([^ ]+\\)\\.\\.\\.)\\'" "&rest \\1)" |
1a42628a650e
(elint-standard-variables): Remove most members,
Glenn Morris <rgm@gnu.org>
parents:
102230
diff
changeset
|
1168 (format "(%s %s" f (match-string 1 doc)) t)))) |
102230
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
1169 (cons f 'unknown)))) |
5ae300b1d079
(elint-unknown-builtin-args): Fix encode-time spec. (Bug#2453)
Glenn Morris <rgm@gnu.org>
parents:
100908
diff
changeset
|
1170 (or list (elint-find-builtins)))) |
19210 | 1171 |
1172 (provide 'elint) | |
1173 | |
93975
1e3a407766b9
Fix up comment convention on the arch-tag lines.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
87649
diff
changeset
|
1174 ;; arch-tag: b2f061e2-af84-4ddc-8e39-f5e969ac228f |
19210 | 1175 ;;; elint.el ends here |