diff options
| author | Philipp Stephani | 2015-06-30 22:38:35 +0200 |
|---|---|---|
| committer | Philipp Stephani | 2017-05-01 20:39:10 +0200 |
| commit | c2bbdc3316487e34eba1470dd059c0c290431e00 (patch) | |
| tree | bed5315e69d89c99c62be4a78e8f26d799643f70 | |
| parent | b72e36047c9a5d46b02e12252e0fc640b6839903 (diff) | |
| download | emacs-c2bbdc3316487e34eba1470dd059c0c290431e00.tar.gz emacs-c2bbdc3316487e34eba1470dd059c0c290431e00.zip | |
Warn about missing backslashes during load
* src/lread.c (load_warn_unescaped_character_literals, Fload, read1)
(syms_of_lread): Warn if unescaped character literals are
found (Bug#20152).
* lisp/emacs-lisp/bytecomp.el (byte-compile-from-buffer): Check for
unescaped character literals during byte compilation.
* test/src/lread-tests.el (lread-tests--unescaped-char-literals): New
unit test.
(lread-tests--with-temp-file, lread-tests--last-message): Helper
functions for unit test.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp-tests--unescaped-char-literals): New unit test.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--with-temp-file):
Helper macro for unit test.
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 7 | ||||
| -rw-r--r-- | src/lread.c | 40 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/bytecomp-tests.el | 23 | ||||
| -rw-r--r-- | test/src/lread-tests.el | 26 |
4 files changed, 96 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 15dc24060aa..25102548a9d 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -2027,12 +2027,19 @@ With argument ARG, insert value in current buffer after the form." | |||
| 2027 | (setq byte-compile-read-position (point) | 2027 | (setq byte-compile-read-position (point) |
| 2028 | byte-compile-last-position byte-compile-read-position) | 2028 | byte-compile-last-position byte-compile-read-position) |
| 2029 | (let* ((old-style-backquotes nil) | 2029 | (let* ((old-style-backquotes nil) |
| 2030 | (lread--unescaped-character-literals nil) | ||
| 2030 | (form (read inbuffer))) | 2031 | (form (read inbuffer))) |
| 2031 | ;; Warn about the use of old-style backquotes. | 2032 | ;; Warn about the use of old-style backquotes. |
| 2032 | (when old-style-backquotes | 2033 | (when old-style-backquotes |
| 2033 | (byte-compile-warn "!! The file uses old-style backquotes !! | 2034 | (byte-compile-warn "!! The file uses old-style backquotes !! |
| 2034 | This functionality has been obsolete for more than 10 years already | 2035 | This functionality has been obsolete for more than 10 years already |
| 2035 | and will be removed soon. See (elisp)Backquote in the manual.")) | 2036 | and will be removed soon. See (elisp)Backquote in the manual.")) |
| 2037 | (when lread--unescaped-character-literals | ||
| 2038 | (byte-compile-warn | ||
| 2039 | "unescaped character literals %s detected!" | ||
| 2040 | (mapconcat #'string | ||
| 2041 | (sort lread--unescaped-character-literals #'<) | ||
| 2042 | ", "))) | ||
| 2036 | (byte-compile-toplevel-file-form form))) | 2043 | (byte-compile-toplevel-file-form form))) |
| 2037 | ;; Compile pending forms at end of file. | 2044 | ;; Compile pending forms at end of file. |
| 2038 | (byte-compile-flush-pending) | 2045 | (byte-compile-flush-pending) |
diff --git a/src/lread.c b/src/lread.c index 3b2e123dd39..6467043b1da 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -955,6 +955,21 @@ load_warn_old_style_backquotes (Lisp_Object file) | |||
| 955 | } | 955 | } |
| 956 | } | 956 | } |
| 957 | 957 | ||
| 958 | static void | ||
| 959 | load_warn_unescaped_character_literals (Lisp_Object file) | ||
| 960 | { | ||
| 961 | if (NILP (Vlread_unescaped_character_literals)) return; | ||
| 962 | CHECK_CONS (Vlread_unescaped_character_literals); | ||
| 963 | AUTO_STRING (format, | ||
| 964 | "Loading `%s': unescaped character literals %s detected!"); | ||
| 965 | AUTO_STRING (separator, ", "); | ||
| 966 | CALLN (Fmessage, | ||
| 967 | format, file, | ||
| 968 | Fmapconcat (Qstring, | ||
| 969 | Fsort (Vlread_unescaped_character_literals, Qlss), | ||
| 970 | separator)); | ||
| 971 | } | ||
| 972 | |||
| 958 | DEFUN ("get-load-suffixes", Fget_load_suffixes, Sget_load_suffixes, 0, 0, 0, | 973 | DEFUN ("get-load-suffixes", Fget_load_suffixes, Sget_load_suffixes, 0, 0, 0, |
| 959 | doc: /* Return the suffixes that `load' should try if a suffix is \ | 974 | doc: /* Return the suffixes that `load' should try if a suffix is \ |
| 960 | required. | 975 | required. |
| @@ -1202,6 +1217,11 @@ Return t if the file exists and loads successfully. */) | |||
| 1202 | specbind (Qold_style_backquotes, Qnil); | 1217 | specbind (Qold_style_backquotes, Qnil); |
| 1203 | record_unwind_protect (load_warn_old_style_backquotes, file); | 1218 | record_unwind_protect (load_warn_old_style_backquotes, file); |
| 1204 | 1219 | ||
| 1220 | /* Check for the presence of unescaped character literals and warn | ||
| 1221 | about them. */ | ||
| 1222 | specbind (Qlread_unescaped_character_literals, Qnil); | ||
| 1223 | record_unwind_protect (load_warn_unescaped_character_literals, file); | ||
| 1224 | |||
| 1205 | int is_elc; | 1225 | int is_elc; |
| 1206 | if ((is_elc = suffix_p (found, ".elc")) != 0 | 1226 | if ((is_elc = suffix_p (found, ".elc")) != 0 |
| 1207 | /* version = 1 means the file is empty, in which case we can | 1227 | /* version = 1 means the file is empty, in which case we can |
| @@ -3092,6 +3112,16 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list) | |||
| 3092 | if (c == ' ' || c == '\t') | 3112 | if (c == ' ' || c == '\t') |
| 3093 | return make_number (c); | 3113 | return make_number (c); |
| 3094 | 3114 | ||
| 3115 | if (c == '(' || c == ')' || c == '[' || c == ']' | ||
| 3116 | || c == '"' || c == ';') | ||
| 3117 | { | ||
| 3118 | CHECK_LIST (Vlread_unescaped_character_literals); | ||
| 3119 | Lisp_Object char_obj = make_natnum (c); | ||
| 3120 | if (NILP (Fmemq (char_obj, Vlread_unescaped_character_literals))) | ||
| 3121 | Vlread_unescaped_character_literals = | ||
| 3122 | Fcons (char_obj, Vlread_unescaped_character_literals); | ||
| 3123 | } | ||
| 3124 | |||
| 3095 | if (c == '\\') | 3125 | if (c == '\\') |
| 3096 | c = read_escape (readcharfun, 0); | 3126 | c = read_escape (readcharfun, 0); |
| 3097 | modifiers = c & CHAR_MODIFIER_MASK; | 3127 | modifiers = c & CHAR_MODIFIER_MASK; |
| @@ -4815,6 +4845,16 @@ variables, this must be set in the first line of a file. */); | |||
| 4815 | Vold_style_backquotes = Qnil; | 4845 | Vold_style_backquotes = Qnil; |
| 4816 | DEFSYM (Qold_style_backquotes, "old-style-backquotes"); | 4846 | DEFSYM (Qold_style_backquotes, "old-style-backquotes"); |
| 4817 | 4847 | ||
| 4848 | DEFVAR_LISP ("lread--unescaped-character-literals", | ||
| 4849 | Vlread_unescaped_character_literals, | ||
| 4850 | doc: /* List of deprecated unescaped character literals encountered by `read'. | ||
| 4851 | For internal use only. */); | ||
| 4852 | Vlread_unescaped_character_literals = Qnil; | ||
| 4853 | DEFSYM (Qlread_unescaped_character_literals, | ||
| 4854 | "lread--unescaped-character-literals"); | ||
| 4855 | |||
| 4856 | DEFSYM (Qlss, "<"); | ||
| 4857 | |||
| 4818 | DEFVAR_BOOL ("load-prefer-newer", load_prefer_newer, | 4858 | DEFVAR_BOOL ("load-prefer-newer", load_prefer_newer, |
| 4819 | doc: /* Non-nil means `load' prefers the newest version of a file. | 4859 | doc: /* Non-nil means `load' prefers the newest version of a file. |
| 4820 | This applies when a filename suffix is not explicitly specified and | 4860 | This applies when a filename suffix is not explicitly specified and |
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el index e8feec31d26..3624904753c 100644 --- a/test/lisp/emacs-lisp/bytecomp-tests.el +++ b/test/lisp/emacs-lisp/bytecomp-tests.el | |||
| @@ -506,6 +506,29 @@ bytecompiled code, and their results compared.") | |||
| 506 | (dolist (pat bytecomp-lexbind-tests) | 506 | (dolist (pat bytecomp-lexbind-tests) |
| 507 | (should (bytecomp-lexbind-check-1 pat)))) | 507 | (should (bytecomp-lexbind-check-1 pat)))) |
| 508 | 508 | ||
| 509 | (defmacro bytecomp-tests--with-temp-file (file-name-var &rest body) | ||
| 510 | (declare (indent 1)) | ||
| 511 | (cl-check-type file-name-var symbol) | ||
| 512 | `(let ((,file-name-var (make-temp-file "emacs"))) | ||
| 513 | (unwind-protect | ||
| 514 | (progn ,@body) | ||
| 515 | (delete-file ,file-name-var)))) | ||
| 516 | |||
| 517 | (ert-deftest bytecomp-tests--unescaped-char-literals () | ||
| 518 | "Check that byte compiling warns about unescaped character | ||
| 519 | literals (Bug#20852)." | ||
| 520 | (should (boundp 'lread--unescaped-character-literals)) | ||
| 521 | (bytecomp-tests--with-temp-file source | ||
| 522 | (write-region "(list ?) ?( ?; ?\" ?[ ?])" nil source) | ||
| 523 | (bytecomp-tests--with-temp-file destination | ||
| 524 | (let* ((byte-compile-dest-file-function (lambda (_) destination)) | ||
| 525 | (byte-compile-error-on-warn t) | ||
| 526 | (byte-compile-debug t) | ||
| 527 | (err (should-error (byte-compile-file source)))) | ||
| 528 | (should (equal (cdr err) | ||
| 529 | (list (concat "unescaped character literals " | ||
| 530 | "\", (, ), ;, [, ] detected!")))))))) | ||
| 531 | |||
| 509 | ;; Local Variables: | 532 | ;; Local Variables: |
| 510 | ;; no-byte-compile: t | 533 | ;; no-byte-compile: t |
| 511 | ;; End: | 534 | ;; End: |
diff --git a/test/src/lread-tests.el b/test/src/lread-tests.el index 27f967f045b..84342348d45 100644 --- a/test/src/lread-tests.el +++ b/test/src/lread-tests.el | |||
| @@ -116,4 +116,30 @@ | |||
| 116 | (should (equal '(#s(foo) #s(foo)) | 116 | (should (equal '(#s(foo) #s(foo)) |
| 117 | (read "(#1=#s(foo) #1#)")))) | 117 | (read "(#1=#s(foo) #1#)")))) |
| 118 | 118 | ||
| 119 | (defmacro lread-tests--with-temp-file (file-name-var &rest body) | ||
| 120 | (declare (indent 1)) | ||
| 121 | (cl-check-type file-name-var symbol) | ||
| 122 | `(let ((,file-name-var (make-temp-file "emacs"))) | ||
| 123 | (unwind-protect | ||
| 124 | (progn ,@body) | ||
| 125 | (delete-file ,file-name-var)))) | ||
| 126 | |||
| 127 | (defun lread-tests--last-message () | ||
| 128 | (with-current-buffer "*Messages*" | ||
| 129 | (save-excursion | ||
| 130 | (goto-char (point-max)) | ||
| 131 | (skip-chars-backward "\n") | ||
| 132 | (buffer-substring (line-beginning-position) (point))))) | ||
| 133 | |||
| 134 | (ert-deftest lread-tests--unescaped-char-literals () | ||
| 135 | "Check that loading warns about unescaped character | ||
| 136 | literals (Bug#20852)." | ||
| 137 | (lread-tests--with-temp-file file-name | ||
| 138 | (write-region "?) ?( ?; ?\" ?[ ?]" nil file-name) | ||
| 139 | (should (equal (load file-name nil :nomessage :nosuffix) t)) | ||
| 140 | (should (equal (lread-tests--last-message) | ||
| 141 | (concat (format-message "Loading `%s': " file-name) | ||
| 142 | "unescaped character literals " | ||
| 143 | "\", (, ), ;, [, ] detected!"))))) | ||
| 144 | |||
| 119 | ;;; lread-tests.el ends here | 145 | ;;; lread-tests.el ends here |