aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2023-10-15 22:01:06 +0200
committerMattias EngdegÄrd2023-10-21 15:12:55 +0200
commita3db503351e9a8720cdea2f1ca42d55d2de684e2 (patch)
tree299791970977df508b580a64040e86f7e1f30782
parent12c8cdb60cc41fb17a85c7e3f75f91cca2d60483 (diff)
downloademacs-a3db503351e9a8720cdea2f1ca42d55d2de684e2.tar.gz
emacs-a3db503351e9a8720cdea2f1ca42d55d2de684e2.zip
Move lexical-binding warning from checkdoc to byte-compiler
This warning is much more appropriate for the compiler, since lexical binding affects what it can reason and warn about, than for checkdoc as the warning has no bearing to documentation at all. The move also improves the reach of the warning. * etc/NEWS: Update. * lisp/emacs-lisp/checkdoc.el (checkdoc-lexical-binding-flag) (checkdoc-file-comments-engine): Move warning from here.... * lisp/emacs-lisp/bytecomp.el (byte-compile-file): ...to here. * test/lisp/emacs-lisp/bytecomp-resources/no-byte-compile.el: * test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--unescaped-char-literals) (bytecomp-tests-function-put, bytecomp-tests--not-writable-directory) (bytecomp-tests--target-file-no-directory): Update tests. (bytecomp-tests--log-from-compilation) (bytecomp-tests--lexical-binding-cookie): New test.
-rw-r--r--etc/NEWS32
-rw-r--r--lisp/emacs-lisp/bytecomp.el4
-rw-r--r--lisp/emacs-lisp/checkdoc.el39
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/no-byte-compile.el2
-rw-r--r--test/lisp/emacs-lisp/bytecomp-tests.el39
5 files changed, 64 insertions, 52 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 3d4cdd876b3..609c3fa1596 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -854,14 +854,6 @@ This can help avoid some awkward skip conditions. For example
854'(skip-unless (not noninteractive))' can be changed to the easier 854'(skip-unless (not noninteractive))' can be changed to the easier
855to read '(skip-when noninteractive)'. 855to read '(skip-when noninteractive)'.
856 856
857** Checkdoc
858
859---
860*** New checkdock warning if not using lexical-binding.
861Checkdoc now warns if the first line of an Emacs Lisp file does not
862end with a "-*- lexical-binding: t -*-" cookie. Customize the user
863option 'checkdoc-lexical-binding-flag' to nil to disable this warning.
864
865** URL 857** URL
866 858
867+++ 859+++
@@ -1180,6 +1172,30 @@ sexp-related motion commands.
1180** New or changed byte-compilation warnings 1172** New or changed byte-compilation warnings
1181 1173
1182--- 1174---
1175*** Warn about missing 'lexical-binding' directive.
1176The compiler now warns if an Elisp file lacks the standard
1177'-*- lexical-binding: ... -*-' cookie on the first line.
1178This line typically looks something like
1179
1180 ;;; My little pony mode -*- lexical-binding: t -*-
1181
1182It is needed to inform the compiler about which dialect of ELisp
1183your code is using: the modern dialect with lexical binding or
1184the old dialect with only dynamic binding.
1185
1186Lexical binding avoids some name conflicts and allows the compiler
1187to detect more mistakes and generate more efficient code. To adapt
1188your code to lexical binding, see the "(elisp) Converting to Lexical
1189Binding" section in the manual.
1190
1191If you are unable to convert the code to lexical binding, you can insert
1192the line
1193
1194 ;;; -*- lexical-binding: nil -*-
1195
1196first in the file to declare that it uses the old dialect.
1197
1198---
1183*** Warn about empty bodies for more special forms and macros. 1199*** Warn about empty bodies for more special forms and macros.
1184The compiler now warns about an empty body argument to 'when', 1200The compiler now warns about an empty body argument to 'when',
1185'unless', 'ignore-error' and 'with-suppressed-warnings' in addition to 1201'unless', 'ignore-error' and 'with-suppressed-warnings' in addition to
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 92abe6b4624..cc68db73c9f 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -2201,6 +2201,10 @@ See also `emacs-lisp-byte-compile-and-load'."
2201 filename buffer-file-name)) 2201 filename buffer-file-name))
2202 ;; Don't inherit lexical-binding from caller (bug#12938). 2202 ;; Don't inherit lexical-binding from caller (bug#12938).
2203 (unless (local-variable-p 'lexical-binding) 2203 (unless (local-variable-p 'lexical-binding)
2204 (let ((byte-compile-current-buffer (current-buffer)))
2205 (byte-compile-warn-x
2206 (position-symbol 'a (point-min))
2207 "file has no `lexical-binding' directive on its first line"))
2204 (setq-local lexical-binding nil)) 2208 (setq-local lexical-binding nil))
2205 ;; Set the default directory, in case an eval-when-compile uses it. 2209 ;; Set the default directory, in case an eval-when-compile uses it.
2206 (setq default-directory (file-name-directory filename))) 2210 (setq default-directory (file-name-directory filename)))
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index 440e133f44b..471a2fbdf48 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -128,14 +128,6 @@
128;; simple style rules to follow which checkdoc will auto-fix for you. 128;; simple style rules to follow which checkdoc will auto-fix for you.
129;; `y-or-n-p' and `yes-or-no-p' should also end in "?". 129;; `y-or-n-p' and `yes-or-no-p' should also end in "?".
130;; 130;;
131;; Lexical binding:
132;;
133;; We recommend always using lexical binding in new code, and
134;; converting old code to use it. Checkdoc warns if you don't have
135;; the recommended string "-*- lexical-binding: t -*-" at the top of
136;; the file. You can disable this check with the user option
137;; `checkdoc-lexical-binding-flag'.
138;;
139;; Adding your own checks: 131;; Adding your own checks:
140;; 132;;
141;; You can experiment with adding your own checks by setting the 133;; You can experiment with adding your own checks by setting the
@@ -347,12 +339,6 @@ See Info node `(elisp) Documentation Tips' for background."
347 :type 'boolean 339 :type 'boolean
348 :version "28.1") 340 :version "28.1")
349 341
350(defcustom checkdoc-lexical-binding-flag t
351 "Non-nil means generate warnings if file is not using lexical binding.
352See Info node `(elisp) Converting to Lexical Binding' for more."
353 :type 'boolean
354 :version "30.1")
355
356;; This is how you can use checkdoc to make mass fixes on the Emacs 342;; This is how you can use checkdoc to make mass fixes on the Emacs
357;; source tree: 343;; source tree:
358;; 344;;
@@ -2391,31 +2377,6 @@ Code:, and others referenced in the style guide."
2391 (point-min) (save-excursion (goto-char (point-min)) 2377 (point-min) (save-excursion (goto-char (point-min))
2392 (line-end-position)))) 2378 (line-end-position))))
2393 nil)) 2379 nil))
2394 (when checkdoc-lexical-binding-flag
2395 (setq
2396 err
2397 ;; Lexical binding cookie.
2398 (if (not (save-excursion
2399 (save-restriction
2400 (goto-char (point-min))
2401 (narrow-to-region (point) (pos-eol))
2402 (re-search-forward
2403 (rx "-*-" (* (* nonl) ";")
2404 (* space) "lexical-binding:" (* space) "t" (* space)
2405 (* ";" (* nonl))
2406 "-*-")
2407 nil t))))
2408 (let ((pos (save-excursion (goto-char (point-min))
2409 (goto-char (pos-eol))
2410 (point))))
2411 (if (checkdoc-y-or-n-p "There is no lexical-binding cookie! Add one?")
2412 (progn
2413 (goto-char pos)
2414 (insert " -*- lexical-binding: t -*-"))
2415 (checkdoc-create-error
2416 "The first line should end with \"-*- lexical-binding: t -*-\""
2417 pos (1+ pos) t)))
2418 nil)))
2419 (setq 2380 (setq
2420 err 2381 err
2421 (or 2382 (or
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/no-byte-compile.el b/test/lisp/emacs-lisp/bytecomp-resources/no-byte-compile.el
index 00ad1947507..1de5cf66b66 100644
--- a/test/lisp/emacs-lisp/bytecomp-resources/no-byte-compile.el
+++ b/test/lisp/emacs-lisp/bytecomp-resources/no-byte-compile.el
@@ -1 +1 @@
;; -*- no-byte-compile: t; -*- ;; -*- no-byte-compile: t; lexical-binding: t; -*-
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el
index e644417c3d4..4aa555f1e92 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -1302,6 +1302,30 @@ byte-compiled. Run with dynamic binding."
1302 (let ((elc (concat ,file-name-var ".elc"))) 1302 (let ((elc (concat ,file-name-var ".elc")))
1303 (if (file-exists-p elc) (delete-file elc)))))) 1303 (if (file-exists-p elc) (delete-file elc))))))
1304 1304
1305(defun bytecomp-tests--log-from-compilation (source)
1306 "Compile the string SOURCE and return the compilation log output."
1307 (let ((text-quoting-style 'grave)
1308 (byte-compile-log-buffer (generate-new-buffer " *Compile-Log*")))
1309 (with-current-buffer byte-compile-log-buffer
1310 (let ((inhibit-read-only t)) (erase-buffer)))
1311 (bytecomp-tests--with-temp-file el-file
1312 (write-region source nil el-file)
1313 (byte-compile-file el-file))
1314 (with-current-buffer byte-compile-log-buffer
1315 (buffer-string))))
1316
1317(ert-deftest bytecomp-tests--lexical-binding-cookie ()
1318 (cl-flet ((cookie-warning (source)
1319 (string-search
1320 "file has no `lexical-binding' directive on its first line"
1321 (bytecomp-tests--log-from-compilation source))))
1322 (let ((some-code "(defun my-fun () 12)\n"))
1323 (should-not (cookie-warning
1324 (concat ";;; -*-lexical-binding:t-*-\n" some-code)))
1325 (should-not (cookie-warning
1326 (concat ";;; -*-lexical-binding:nil-*-\n" some-code)))
1327 (should (cookie-warning some-code)))))
1328
1305(ert-deftest bytecomp-tests--unescaped-char-literals () 1329(ert-deftest bytecomp-tests--unescaped-char-literals ()
1306 "Check that byte compiling warns about unescaped character 1330 "Check that byte compiling warns about unescaped character
1307literals (Bug#20852)." 1331literals (Bug#20852)."
@@ -1310,7 +1334,9 @@ literals (Bug#20852)."
1310 (byte-compile-debug t) 1334 (byte-compile-debug t)
1311 (text-quoting-style 'grave)) 1335 (text-quoting-style 'grave))
1312 (bytecomp-tests--with-temp-file source 1336 (bytecomp-tests--with-temp-file source
1313 (write-region "(list ?) ?( ?; ?\" ?[ ?])" nil source) 1337 (write-region (concat ";;; -*-lexical-binding:t-*-\n"
1338 "(list ?) ?( ?; ?\" ?[ ?])")
1339 nil source)
1314 (bytecomp-tests--with-temp-file destination 1340 (bytecomp-tests--with-temp-file destination
1315 (let* ((byte-compile-dest-file-function (lambda (_) destination)) 1341 (let* ((byte-compile-dest-file-function (lambda (_) destination))
1316 (err (should-error (byte-compile-file source)))) 1342 (err (should-error (byte-compile-file source))))
@@ -1322,7 +1348,9 @@ literals (Bug#20852)."
1322 "`?\\]' expected!"))))))) 1348 "`?\\]' expected!")))))))
1323 ;; But don't warn in subsequent compilations (Bug#36068). 1349 ;; But don't warn in subsequent compilations (Bug#36068).
1324 (bytecomp-tests--with-temp-file source 1350 (bytecomp-tests--with-temp-file source
1325 (write-region "(list 1 2 3)" nil source) 1351 (write-region (concat ";;; -*-lexical-binding:t-*-\n"
1352 "(list 1 2 3)")
1353 nil source)
1326 (bytecomp-tests--with-temp-file destination 1354 (bytecomp-tests--with-temp-file destination
1327 (let ((byte-compile-dest-file-function (lambda (_) destination))) 1355 (let ((byte-compile-dest-file-function (lambda (_) destination)))
1328 (should (byte-compile-file source))))))) 1356 (should (byte-compile-file source)))))))
@@ -1330,6 +1358,7 @@ literals (Bug#20852)."
1330(ert-deftest bytecomp-tests-function-put () 1358(ert-deftest bytecomp-tests-function-put ()
1331 "Check `function-put' operates during compilation." 1359 "Check `function-put' operates during compilation."
1332 (bytecomp-tests--with-temp-file source 1360 (bytecomp-tests--with-temp-file source
1361 (insert ";;; -*-lexical-binding:t-*-\n")
1333 (dolist (form '((function-put 'bytecomp-tests--foo 'foo 1) 1362 (dolist (form '((function-put 'bytecomp-tests--foo 'foo 1)
1334 (function-put 'bytecomp-tests--foo 'bar 2) 1363 (function-put 'bytecomp-tests--foo 'bar 2)
1335 (defmacro bytecomp-tests--foobar () 1364 (defmacro bytecomp-tests--foobar ()
@@ -1636,7 +1665,8 @@ writable (Bug#44631)."
1636 (byte-compile-error-on-warn t)) 1665 (byte-compile-error-on-warn t))
1637 (unwind-protect 1666 (unwind-protect
1638 (progn 1667 (progn
1639 (write-region "" nil input-file nil nil nil 'excl) 1668 (write-region ";;; -*-lexical-binding:t-*-\n"
1669 nil input-file nil nil nil 'excl)
1640 (write-region "" nil output-file nil nil nil 'excl) 1670 (write-region "" nil output-file nil nil nil 'excl)
1641 (set-file-modes input-file #o400) 1671 (set-file-modes input-file #o400)
1642 (set-file-modes output-file #o200) 1672 (set-file-modes output-file #o200)
@@ -1700,7 +1730,8 @@ mountpoint (Bug#44631)."
1700 (let* ((default-directory directory) 1730 (let* ((default-directory directory)
1701 (byte-compile-dest-file-function (lambda (_) "test.elc")) 1731 (byte-compile-dest-file-function (lambda (_) "test.elc"))
1702 (byte-compile-error-on-warn t)) 1732 (byte-compile-error-on-warn t))
1703 (write-region "" nil "test.el" nil nil nil 'excl) 1733 (write-region ";;; -*-lexical-binding:t-*-\n"
1734 nil "test.el" nil nil nil 'excl)
1704 (should (byte-compile-file "test.el")) 1735 (should (byte-compile-file "test.el"))
1705 (should (file-regular-p "test.elc")) 1736 (should (file-regular-p "test.elc"))
1706 (should (cl-plusp (file-attribute-size 1737 (should (cl-plusp (file-attribute-size