Commit c2bbdc33 authored by Philipp Stephani's avatar Philipp Stephani

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.
parent b72e3604
......@@ -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)
......
......@@ -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
......
......@@ -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:
......
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment