diff options
| author | Mattias EngdegÄrd | 2024-09-27 11:48:14 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2024-09-27 19:26:52 +0200 |
| commit | bba14a27678317eee68e87a343e7314b3949f6c7 (patch) | |
| tree | e0f36001605ef720aa9b94d7dd38bd81d5880e09 | |
| parent | 09d63ba32bbd0ddbd8c9deb4fcfe8e4356ea0e8d (diff) | |
| download | emacs-bba14a27678317eee68e87a343e7314b3949f6c7.tar.gz emacs-bba14a27678317eee68e87a343e7314b3949f6c7.zip | |
Warn about bad face specs in `defface` at compile time
* lisp/emacs-lisp/bytecomp.el (byte-compile--custom-declare-face):
Byte-compile `defface` forms, or the byte-compile handler won't
be called.
(bytecomp--check-cus-face-spec): New.
(bytecomp--custom-declare): Call it.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-defface-spec):
New tests.
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 59 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/bytecomp-tests.el | 26 |
2 files changed, 84 insertions, 1 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 88167fc7ebd..1c84fe0804b 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -2713,7 +2713,7 @@ Call from the source buffer." | |||
| 2713 | (let ((newdocs (byte-compile--docstring docs kind name))) | 2713 | (let ((newdocs (byte-compile--docstring docs kind name))) |
| 2714 | (unless (eq docs newdocs) | 2714 | (unless (eq docs newdocs) |
| 2715 | (setq form (byte-compile--list-with-n form 3 newdocs))))) | 2715 | (setq form (byte-compile--list-with-n form 3 newdocs))))) |
| 2716 | form)) | 2716 | (byte-compile-keep-pending form))) |
| 2717 | 2717 | ||
| 2718 | (put 'require 'byte-hunk-handler 'byte-compile-file-form-require) | 2718 | (put 'require 'byte-hunk-handler 'byte-compile-file-form-require) |
| 2719 | (defun byte-compile-file-form-require (form) | 2719 | (defun byte-compile-file-form-require (form) |
| @@ -5361,6 +5361,56 @@ FORM is used to provide location, `bytecomp--cus-function' and | |||
| 5361 | (bytecomp--cus-warn type "`%s' is not a valid type" type)) | 5361 | (bytecomp--cus-warn type "`%s' is not a valid type" type)) |
| 5362 | ))) | 5362 | ))) |
| 5363 | 5363 | ||
| 5364 | (defun bytecomp--check-cus-face-spec (spec) | ||
| 5365 | "Check for mistakes in a `defface' SPEC argument." | ||
| 5366 | (when (consp spec) | ||
| 5367 | (dolist (sp spec) | ||
| 5368 | (let ((display (car-safe sp)) | ||
| 5369 | (atts (cdr-safe sp))) | ||
| 5370 | (cond ((listp display) | ||
| 5371 | (dolist (condition display) | ||
| 5372 | (unless (memq (car-safe condition) | ||
| 5373 | '(type class background min-colors supports)) | ||
| 5374 | (bytecomp--cus-warn | ||
| 5375 | (list sp spec) | ||
| 5376 | "Bad face display condition `%S'" (car condition))))) | ||
| 5377 | ((not (memq display '(t default))) | ||
| 5378 | (bytecomp--cus-warn | ||
| 5379 | (list sp spec) "Bad face display `%S'" display))) | ||
| 5380 | (when (and (consp atts) (null (cdr atts))) | ||
| 5381 | (setq atts (car atts))) ; old (DISPLAY ATTS) syntax | ||
| 5382 | (while atts | ||
| 5383 | (let ((attr (car atts)) | ||
| 5384 | (val (cadr atts))) | ||
| 5385 | (cond | ||
| 5386 | ((not (keywordp attr)) | ||
| 5387 | (bytecomp--cus-warn | ||
| 5388 | (list atts sp spec) | ||
| 5389 | "Non-keyword in face attribute list: `%S'" attr)) | ||
| 5390 | ((null (cdr atts)) | ||
| 5391 | (bytecomp--cus-warn | ||
| 5392 | (list atts sp spec) "Missing face attribute `%s' value" attr)) | ||
| 5393 | ((memq attr '( :inherit :extend | ||
| 5394 | :family :foundry :width :height :weight :slant | ||
| 5395 | :foreground :distant-foreground :background | ||
| 5396 | :underline :overline :strike-through :box | ||
| 5397 | :inverse-video :stipple :font | ||
| 5398 | ;; FIXME: obsolete keywords, warn about them too? | ||
| 5399 | ;; `:reverse-video' is very rare. | ||
| 5400 | :bold ; :bold t = :weight bold | ||
| 5401 | :italic ; :italic t = :slant italic | ||
| 5402 | :reverse-video ; alias for :inverse-video | ||
| 5403 | )) | ||
| 5404 | (when (eq (car-safe val) 'quote) | ||
| 5405 | (bytecomp--cus-warn | ||
| 5406 | (list val atts sp spec) | ||
| 5407 | "Value for face attribute `%s' should not be quoted" attr))) | ||
| 5408 | (t | ||
| 5409 | (bytecomp--cus-warn | ||
| 5410 | (list atts sp spec) | ||
| 5411 | "`%s' is not a valid face attribute keyword" attr)))) | ||
| 5412 | (setq atts (cddr atts))))))) | ||
| 5413 | |||
| 5364 | ;; Unified handler for multiple functions with similar arguments: | 5414 | ;; Unified handler for multiple functions with similar arguments: |
| 5365 | ;; (NAME SOMETHING DOC KEYWORD-ARGS...) | 5415 | ;; (NAME SOMETHING DOC KEYWORD-ARGS...) |
| 5366 | (byte-defop-compiler-1 define-widget bytecomp--custom-declare) | 5416 | (byte-defop-compiler-1 define-widget bytecomp--custom-declare) |
| @@ -5394,6 +5444,13 @@ FORM is used to provide location, `bytecomp--cus-function' and | |||
| 5394 | (eq (car-safe type-arg) 'quote)) | 5444 | (eq (car-safe type-arg) 'quote)) |
| 5395 | (bytecomp--check-cus-type (cadr type-arg))))))) | 5445 | (bytecomp--check-cus-type (cadr type-arg))))))) |
| 5396 | 5446 | ||
| 5447 | (when (eq fun 'custom-declare-face) | ||
| 5448 | (let ((face-arg (nth 2 form))) | ||
| 5449 | (when (and (eq (car-safe face-arg) 'quote) | ||
| 5450 | (consp (cdr face-arg)) | ||
| 5451 | (null (cddr face-arg))) | ||
| 5452 | (bytecomp--check-cus-face-spec (nth 1 face-arg))))) | ||
| 5453 | |||
| 5397 | ;; Check :group | 5454 | ;; Check :group |
| 5398 | (when (cond | 5455 | (when (cond |
| 5399 | ((memq fun '(custom-declare-variable custom-declare-face)) | 5456 | ((memq fun '(custom-declare-variable custom-declare-face)) |
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el index e3ce87cc9af..cce6b1221fc 100644 --- a/test/lisp/emacs-lisp/bytecomp-tests.el +++ b/test/lisp/emacs-lisp/bytecomp-tests.el | |||
| @@ -1985,6 +1985,32 @@ EXPECTED-POINT BINDINGS (MODES \\='\\='(ruby-mode js-mode python-mode)) \ | |||
| 1985 | (dc 'integerp)) | 1985 | (dc 'integerp)) |
| 1986 | )) | 1986 | )) |
| 1987 | 1987 | ||
| 1988 | (ert-deftest bytecomp-test-defface-spec () | ||
| 1989 | (cl-flet ((df (spec) `(defface mytest ',spec "doc" :group 'test))) | ||
| 1990 | (bytecomp--with-warning-test | ||
| 1991 | (rx "Bad face display condition `max-colors'") | ||
| 1992 | (df '((((class color grayscale) (max-colors 75) (background light)) | ||
| 1993 | :foreground "cyan")))) | ||
| 1994 | (bytecomp--with-warning-test | ||
| 1995 | (rx "Bad face display `defualt'") | ||
| 1996 | (df '((defualt :foreground "cyan")))) | ||
| 1997 | (bytecomp--with-warning-test | ||
| 1998 | (rx "`:inverse' is not a valid face attribute keyword") | ||
| 1999 | (df '((t :background "blue" :inverse t)))) | ||
| 2000 | (bytecomp--with-warning-test | ||
| 2001 | (rx "`:inverse' is not a valid face attribute keyword") | ||
| 2002 | (df '((t (:background "blue" :inverse t))))) ; old attr list syntax | ||
| 2003 | (bytecomp--with-warning-test | ||
| 2004 | (rx "Value for face attribute `:inherit' should not be quoted") | ||
| 2005 | (df '((t :inherit 'other)))) | ||
| 2006 | (bytecomp--with-warning-test | ||
| 2007 | (rx "Missing face attribute `:extend' value") | ||
| 2008 | (df '((t :foundry "abc" :extend)))) | ||
| 2009 | (bytecomp--with-warning-test | ||
| 2010 | (rx "Non-keyword in face attribute list: `\"green\"'") | ||
| 2011 | (df '((t :foreground "white" "green")))) | ||
| 2012 | )) | ||
| 2013 | |||
| 1988 | (ert-deftest bytecomp-function-attributes () | 2014 | (ert-deftest bytecomp-function-attributes () |
| 1989 | ;; Check that `byte-compile' keeps the declarations, interactive spec and | 2015 | ;; Check that `byte-compile' keeps the declarations, interactive spec and |
| 1990 | ;; doc string of the function (bug#55830). | 2016 | ;; doc string of the function (bug#55830). |