'(skip-unless (not noninteractive))' can be changed to the easier
to read '(skip-when noninteractive)'.
-** Checkdoc
-
----
-*** New checkdock warning if not using lexical-binding.
-Checkdoc now warns if the first line of an Emacs Lisp file does not
-end with a "-*- lexical-binding: t -*-" cookie. Customize the user
-option 'checkdoc-lexical-binding-flag' to nil to disable this warning.
-
** URL
+++
** New or changed byte-compilation warnings
+---
+*** Warn about missing 'lexical-binding' directive.
+The compiler now warns if an Elisp file lacks the standard
+'-*- lexical-binding: ... -*-' cookie on the first line.
+This line typically looks something like
+
+ ;;; My little pony mode -*- lexical-binding: t -*-
+
+It is needed to inform the compiler about which dialect of ELisp
+your code is using: the modern dialect with lexical binding or
+the old dialect with only dynamic binding.
+
+Lexical binding avoids some name conflicts and allows the compiler
+to detect more mistakes and generate more efficient code. To adapt
+your code to lexical binding, see the "(elisp) Converting to Lexical
+Binding" section in the manual.
+
+If you are unable to convert the code to lexical binding, you can insert
+the line
+
+ ;;; -*- lexical-binding: nil -*-
+
+first in the file to declare that it uses the old dialect.
+
---
*** Warn about empty bodies for more special forms and macros.
The compiler now warns about an empty body argument to 'when',
;; simple style rules to follow which checkdoc will auto-fix for you.
;; `y-or-n-p' and `yes-or-no-p' should also end in "?".
;;
-;; Lexical binding:
-;;
-;; We recommend always using lexical binding in new code, and
-;; converting old code to use it. Checkdoc warns if you don't have
-;; the recommended string "-*- lexical-binding: t -*-" at the top of
-;; the file. You can disable this check with the user option
-;; `checkdoc-lexical-binding-flag'.
-;;
;; Adding your own checks:
;;
;; You can experiment with adding your own checks by setting the
:type 'boolean
:version "28.1")
-(defcustom checkdoc-lexical-binding-flag t
- "Non-nil means generate warnings if file is not using lexical binding.
-See Info node `(elisp) Converting to Lexical Binding' for more."
- :type 'boolean
- :version "30.1")
-
;; This is how you can use checkdoc to make mass fixes on the Emacs
;; source tree:
;;
(point-min) (save-excursion (goto-char (point-min))
(line-end-position))))
nil))
- (when checkdoc-lexical-binding-flag
- (setq
- err
- ;; Lexical binding cookie.
- (if (not (save-excursion
- (save-restriction
- (goto-char (point-min))
- (narrow-to-region (point) (pos-eol))
- (re-search-forward
- (rx "-*-" (* (* nonl) ";")
- (* space) "lexical-binding:" (* space) "t" (* space)
- (* ";" (* nonl))
- "-*-")
- nil t))))
- (let ((pos (save-excursion (goto-char (point-min))
- (goto-char (pos-eol))
- (point))))
- (if (checkdoc-y-or-n-p "There is no lexical-binding cookie! Add one?")
- (progn
- (goto-char pos)
- (insert " -*- lexical-binding: t -*-"))
- (checkdoc-create-error
- "The first line should end with \"-*- lexical-binding: t -*-\""
- pos (1+ pos) t)))
- nil)))
(setq
err
(or
(let ((elc (concat ,file-name-var ".elc")))
(if (file-exists-p elc) (delete-file elc))))))
+(defun bytecomp-tests--log-from-compilation (source)
+ "Compile the string SOURCE and return the compilation log output."
+ (let ((text-quoting-style 'grave)
+ (byte-compile-log-buffer (generate-new-buffer " *Compile-Log*")))
+ (with-current-buffer byte-compile-log-buffer
+ (let ((inhibit-read-only t)) (erase-buffer)))
+ (bytecomp-tests--with-temp-file el-file
+ (write-region source nil el-file)
+ (byte-compile-file el-file))
+ (with-current-buffer byte-compile-log-buffer
+ (buffer-string))))
+
+(ert-deftest bytecomp-tests--lexical-binding-cookie ()
+ (cl-flet ((cookie-warning (source)
+ (string-search
+ "file has no `lexical-binding' directive on its first line"
+ (bytecomp-tests--log-from-compilation source))))
+ (let ((some-code "(defun my-fun () 12)\n"))
+ (should-not (cookie-warning
+ (concat ";;; -*-lexical-binding:t-*-\n" some-code)))
+ (should-not (cookie-warning
+ (concat ";;; -*-lexical-binding:nil-*-\n" some-code)))
+ (should (cookie-warning some-code)))))
+
(ert-deftest bytecomp-tests--unescaped-char-literals ()
"Check that byte compiling warns about unescaped character
literals (Bug#20852)."
(byte-compile-debug t)
(text-quoting-style 'grave))
(bytecomp-tests--with-temp-file source
- (write-region "(list ?) ?( ?; ?\" ?[ ?])" nil source)
+ (write-region (concat ";;; -*-lexical-binding:t-*-\n"
+ "(list ?) ?( ?; ?\" ?[ ?])")
+ nil source)
(bytecomp-tests--with-temp-file destination
(let* ((byte-compile-dest-file-function (lambda (_) destination))
(err (should-error (byte-compile-file source))))
"`?\\]' expected!")))))))
;; But don't warn in subsequent compilations (Bug#36068).
(bytecomp-tests--with-temp-file source
- (write-region "(list 1 2 3)" nil source)
+ (write-region (concat ";;; -*-lexical-binding:t-*-\n"
+ "(list 1 2 3)")
+ nil source)
(bytecomp-tests--with-temp-file destination
(let ((byte-compile-dest-file-function (lambda (_) destination)))
(should (byte-compile-file source)))))))
(ert-deftest bytecomp-tests-function-put ()
"Check `function-put' operates during compilation."
(bytecomp-tests--with-temp-file source
+ (insert ";;; -*-lexical-binding:t-*-\n")
(dolist (form '((function-put 'bytecomp-tests--foo 'foo 1)
(function-put 'bytecomp-tests--foo 'bar 2)
(defmacro bytecomp-tests--foobar ()
(byte-compile-error-on-warn t))
(unwind-protect
(progn
- (write-region "" nil input-file nil nil nil 'excl)
+ (write-region ";;; -*-lexical-binding:t-*-\n"
+ nil input-file nil nil nil 'excl)
(write-region "" nil output-file nil nil nil 'excl)
(set-file-modes input-file #o400)
(set-file-modes output-file #o200)
(let* ((default-directory directory)
(byte-compile-dest-file-function (lambda (_) "test.elc"))
(byte-compile-error-on-warn t))
- (write-region "" nil "test.el" nil nil nil 'excl)
+ (write-region ";;; -*-lexical-binding:t-*-\n"
+ nil "test.el" nil nil nil 'excl)
(should (byte-compile-file "test.el"))
(should (file-regular-p "test.elc"))
(should (cl-plusp (file-attribute-size