diff options
author | Philipp Stephani <phst@google.com> | 2015-06-30 22:38:35 +0200 |
---|---|---|
committer | Philipp Stephani <phst@google.com> | 2017-05-01 20:39:10 +0200 |
commit | c2bbdc3316487e34eba1470dd059c0c290431e00 (patch) | |
tree | bed5315e69d89c99c62be4a78e8f26d799643f70 | |
parent | b72e36047c9a5d46b02e12252e0fc640b6839903 (diff) | |
download | emacs-c2bbdc3316487e34eba1470dd059c0c290431e00.tar.gz emacs-c2bbdc3316487e34eba1470dd059c0c290431e00.tar.bz2 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." (setq byte-compile-read-position (point) byte-compile-last-position byte-compile-read-position) (let* ((old-style-backquotes nil) + (lread--unescaped-character-literals nil) (form (read inbuffer))) ;; Warn about the use of old-style backquotes. (when old-style-backquotes (byte-compile-warn "!! The file uses old-style backquotes !! This functionality has been obsolete for more than 10 years already and will be removed soon. See (elisp)Backquote in the manual.")) + (when lread--unescaped-character-literals + (byte-compile-warn + "unescaped character literals %s detected!" + (mapconcat #'string + (sort lread--unescaped-character-literals #'<) + ", "))) (byte-compile-toplevel-file-form form))) ;; Compile pending forms at end of file. (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) } } +static void +load_warn_unescaped_character_literals (Lisp_Object file) +{ + if (NILP (Vlread_unescaped_character_literals)) return; + CHECK_CONS (Vlread_unescaped_character_literals); + AUTO_STRING (format, + "Loading `%s': unescaped character literals %s detected!"); + AUTO_STRING (separator, ", "); + CALLN (Fmessage, + format, file, + Fmapconcat (Qstring, + Fsort (Vlread_unescaped_character_literals, Qlss), + separator)); +} + DEFUN ("get-load-suffixes", Fget_load_suffixes, Sget_load_suffixes, 0, 0, 0, doc: /* Return the suffixes that `load' should try if a suffix is \ required. @@ -1202,6 +1217,11 @@ Return t if the file exists and loads successfully. */) specbind (Qold_style_backquotes, Qnil); record_unwind_protect (load_warn_old_style_backquotes, file); + /* Check for the presence of unescaped character literals and warn + about them. */ + specbind (Qlread_unescaped_character_literals, Qnil); + record_unwind_protect (load_warn_unescaped_character_literals, file); + int is_elc; if ((is_elc = suffix_p (found, ".elc")) != 0 /* 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) if (c == ' ' || c == '\t') return make_number (c); + if (c == '(' || c == ')' || c == '[' || c == ']' + || c == '"' || c == ';') + { + CHECK_LIST (Vlread_unescaped_character_literals); + Lisp_Object char_obj = make_natnum (c); + if (NILP (Fmemq (char_obj, Vlread_unescaped_character_literals))) + Vlread_unescaped_character_literals = + Fcons (char_obj, Vlread_unescaped_character_literals); + } + if (c == '\\') c = read_escape (readcharfun, 0); modifiers = c & CHAR_MODIFIER_MASK; @@ -4815,6 +4845,16 @@ variables, this must be set in the first line of a file. */); Vold_style_backquotes = Qnil; DEFSYM (Qold_style_backquotes, "old-style-backquotes"); + DEFVAR_LISP ("lread--unescaped-character-literals", + Vlread_unescaped_character_literals, + doc: /* List of deprecated unescaped character literals encountered by `read'. +For internal use only. */); + Vlread_unescaped_character_literals = Qnil; + DEFSYM (Qlread_unescaped_character_literals, + "lread--unescaped-character-literals"); + + DEFSYM (Qlss, "<"); + DEFVAR_BOOL ("load-prefer-newer", load_prefer_newer, doc: /* Non-nil means `load' prefers the newest version of a file. 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.") (dolist (pat bytecomp-lexbind-tests) (should (bytecomp-lexbind-check-1 pat)))) +(defmacro bytecomp-tests--with-temp-file (file-name-var &rest body) + (declare (indent 1)) + (cl-check-type file-name-var symbol) + `(let ((,file-name-var (make-temp-file "emacs"))) + (unwind-protect + (progn ,@body) + (delete-file ,file-name-var)))) + +(ert-deftest bytecomp-tests--unescaped-char-literals () + "Check that byte compiling warns about unescaped character +literals (Bug#20852)." + (should (boundp 'lread--unescaped-character-literals)) + (bytecomp-tests--with-temp-file source + (write-region "(list ?) ?( ?; ?\" ?[ ?])" nil source) + (bytecomp-tests--with-temp-file destination + (let* ((byte-compile-dest-file-function (lambda (_) destination)) + (byte-compile-error-on-warn t) + (byte-compile-debug t) + (err (should-error (byte-compile-file source)))) + (should (equal (cdr err) + (list (concat "unescaped character literals " + "\", (, ), ;, [, ] detected!")))))))) + ;; Local Variables: ;; no-byte-compile: t ;; 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 @@ (should (equal '(#s(foo) #s(foo)) (read "(#1=#s(foo) #1#)")))) +(defmacro lread-tests--with-temp-file (file-name-var &rest body) + (declare (indent 1)) + (cl-check-type file-name-var symbol) + `(let ((,file-name-var (make-temp-file "emacs"))) + (unwind-protect + (progn ,@body) + (delete-file ,file-name-var)))) + +(defun lread-tests--last-message () + (with-current-buffer "*Messages*" + (save-excursion + (goto-char (point-max)) + (skip-chars-backward "\n") + (buffer-substring (line-beginning-position) (point))))) + +(ert-deftest lread-tests--unescaped-char-literals () + "Check that loading warns about unescaped character +literals (Bug#20852)." + (lread-tests--with-temp-file file-name + (write-region "?) ?( ?; ?\" ?[ ?]" nil file-name) + (should (equal (load file-name nil :nomessage :nosuffix) t)) + (should (equal (lread-tests--last-message) + (concat (format-message "Loading `%s': " file-name) + "unescaped character literals " + "\", (, ), ;, [, ] detected!"))))) + ;;; lread-tests.el ends here |