1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

; elisp-scope.el: Improve face specification handling.

Replace the use of 'elisp-scope-face(-1)' for analyzing face
specifications with 'elisp-scope-1' calls with an
appropriate OUTSPEC argument.  This allows us to analyze
face specifications even when they are not passed directly
to relevant functions, but rather appear in a tail position
of a form that evaluates to a face specification.

* lisp/emacs-lisp/elisp-scope.el
(elisp-scope--match-spec-to-arg): Add new 'face' spec.
Use it instead of...
(elisp-scope-face, elisp-scope-face-1): ...these functions.
Remove them, no longer used.

* test/lisp/progmodes/elisp-mode-resources/semantic-highlighting.el:
Add test.
This commit is contained in:
Eshel Yaron 2025-10-29 17:20:03 +01:00
parent b9aa420bc4
commit 330aa07f00
No known key found for this signature in database
GPG key ID: EF3EE9CA35D78618
2 changed files with 42 additions and 52 deletions

View file

@ -1151,31 +1151,6 @@ Optional argument LOCAL is a local context to extend."
(elisp-scope--report 'function beg bare))
(elisp-scope-n rest))
(defun elisp-scope-face (face)
(if (or (elisp-scope--sym-bare face)
(keywordp (elisp-scope--sym-bare (car-safe face))))
(elisp-scope-face-1 face)
(mapc #'elisp-scope-face-1 face)))
(defun elisp-scope-face-1 (face)
(cond
((symbol-with-pos-p face)
(when-let* ((beg (elisp-scope--sym-pos face)) (bare (elisp-scope--sym-bare face)))
(elisp-scope--report 'face beg bare)))
((keywordp (elisp-scope--sym-bare (car-safe face)))
(let ((l face))
(while l
(let ((kw (car l))
(vl (cadr l)))
(setq l (cddr l))
(when-let* ((bare (elisp-scope--sym-bare kw))
((keywordp bare)))
(when-let* ((beg (elisp-scope--sym-pos kw)))
(elisp-scope--report 'constant beg bare))
(when (eq bare :inherit)
(when-let* ((beg (elisp-scope--sym-pos vl)) (fbare (elisp-scope--sym-bare vl)))
(elisp-scope--report 'face beg fbare))))))))))
(defun elisp-scope-deftype (name args body)
(when-let* ((beg (elisp-scope--sym-pos name)) (bare (elisp-scope--sym-bare name)))
(elisp-scope--report 'deftype beg bare))
@ -1546,10 +1521,10 @@ Optional argument LOCAL is a local context to extend."
(elisp-scope-1 (cadr format)))
(:propertize
(elisp-scope-mode-line-construct-1 (cadr format))
(when-let* ((props (cdr format))
(when-let* ((props (cddr format))
(symbols-with-pos-enabled t)
(val-form (plist-get props 'face)))
(elisp-scope-face-1 val-form)))
(elisp-scope-quote val-form 'face)))
(otherwise
(elisp-scope-mode-line-construct-1 (cadr format))
(elisp-scope-mode-line-construct-1 (caddr format))))))))))
@ -1879,17 +1854,16 @@ ARGS bound to the analyzed arguments."
(elisp-scope-define-function-analyzer overlay-put (&optional ov prop val)
(elisp-scope-1 ov)
(elisp-scope-1 prop) ;TODO: Recognize overlay props.
(if-let* ((q (elisp-scope--unquote prop))
((eq (elisp-scope--sym-bare q) 'face))
(face (elisp-scope--unquote val)))
;; TODO: Use `elisp-scope-1' with an appropriate outspec.
(elisp-scope-face face)
(elisp-scope-1 val)))
(elisp-scope-1
val
(let* ((q (elisp-scope--unquote prop)))
(when (memq (elisp-scope--sym-bare q) '(face mouse-face))
'face))))
(elisp-scope-define-function-analyzer add-face-text-property (&optional start end face &rest rest)
(elisp-scope-1 start)
(elisp-scope-1 end)
(elisp-scope-1 face '(symbol . face))
(elisp-scope-1 face 'face)
(elisp-scope-n rest))
(elisp-scope-define-function-analyzer facep (&optional face &rest rest)
@ -1946,12 +1920,11 @@ ARGS bound to the analyzed arguments."
(elisp-scope-1 beg)
(elisp-scope-1 end)
(elisp-scope-1 prop)
(if-let* (((memq (elisp-scope--sym-bare (elisp-scope--unquote prop))
'(mouse-face face)))
(q (elisp-scope--unquote val)))
;; TODO: Use `elisp-scope-1' with an appropriate outspec.
(elisp-scope-face q)
(elisp-scope-1 val))
(elisp-scope-1
val
(let* ((q (elisp-scope--unquote prop)))
(when (memq (elisp-scope--sym-bare q) '(face mouse-face))
'face)))
(elisp-scope-1 obj))
(put 'remove-overlays 'elisp-scope-analyzer #'elisp-scope--analyze-put-text-property)
@ -1960,13 +1933,11 @@ ARGS bound to the analyzed arguments."
(elisp-scope-1 string)
(while props
(elisp-scope-1 (car props))
(cl-case (elisp-scope--sym-bare (elisp-scope--unquote (car props)))
((face mouse-face)
(if-let* ((q (elisp-scope--unquote (cadr props))))
;; TODO: Use `elisp-scope-1' with an appropriate outspec.
(elisp-scope-face q)
(elisp-scope-1 (cadr props))))
(otherwise (elisp-scope-1 (cadr props))))
(elisp-scope-1
(cadr props)
(let* ((q (elisp-scope--unquote (car props))))
(when (memq (elisp-scope--sym-bare q) '(face mouse-face))
'face)))
(setq props (cddr props)))
(when props (elisp-scope-n props)))
@ -2377,11 +2348,7 @@ ARGS bound to the analyzed arguments."
(bkw (elisp-scope--sym-bare kw))
((keywordp bkw)))
(elisp-scope-report-s kw 'constant)
(cl-case bkw
(:face
(if-let* ((q (elisp-scope--unquote (cadr props)))) (elisp-scope-face-1 q)
(elisp-scope-1 (cadr props))))
(otherwise (elisp-scope-1 (cadr props))))
(elisp-scope-1 (cadr props) (when (eq bkw :face) 'face))
(setq props (cddr props))))
(elisp-scope-define-macro-analyzer cl-letf (bindings &rest body)
@ -2592,6 +2559,18 @@ ARGS bound to the analyzed arguments."
(cons (member plist-and-then) . (repeat . (cons (symbol . constant) . spec))))
arg))
(cl-defmethod elisp-scope--match-spec-to-arg ((_spec (eql 'face)) arg)
(elisp-scope--match-spec-to-arg
(if (consp arg)
(if (keywordp (elisp-scope--sym-bare (car arg)))
;; One face, given as a plist of face attributes.
'(plist (:inherit . (symbol . face)))
;; Multiple faces.
'(repeat . (or (symbol . face)
(plist (:inherit . (symbol . face))))))
'(symbol . face))
arg))
(cl-defmethod elisp-scope--match-spec-to-arg ((_spec (eql 'cl-type)) arg)
(elisp-scope--match-spec-to-arg
;; Unfold `cl-type'.

View file

@ -171,3 +171,14 @@
"Face for highlighting symbol role names in Emacs Lisp code."
:version "31.1")
;; ^ (elisp-constant font-lock-builtin-face)
(propertize foo
'face
(cond
((random) '(success (:foreground "green" :inherit default)))
;; ^ elisp-face
;; ^ elisp-face
((foobar) 'font-lock-keyword-face)
;; ^ elisp-face
(t '(:inherit error))))
;; ^ elisp-face