Better format string compilation warning

* lisp/emacs-lisp/bytecomp.el (byte-compile-format-warn):
Speed up by eliminating the temporary buffer.
Detect invalid format sequences.  Use plurals properly.
* test/lisp/emacs-lisp/bytecomp-tests.el: Update test.
This commit is contained in:
Mattias Engdegård 2024-04-22 16:29:13 +02:00
parent a2e327cbca
commit e442161f11
2 changed files with 33 additions and 18 deletions

View file

@ -1596,24 +1596,39 @@ extra args."
(when (and (symbolp (car form))
(stringp (nth 1 form))
(get (car form) 'byte-compile-format-like))
(let ((nfields (with-temp-buffer
(insert (nth 1 form))
(goto-char (point-min))
(let ((i 0) (n 0))
(while (re-search-forward "%." nil t)
(backward-char)
(unless (eq ?% (char-after))
(setq i (if (looking-at "\\([0-9]+\\)\\$")
(string-to-number (match-string 1) 10)
(1+ i))
n (max n i)))
(forward-char))
n)))
(nargs (- (length form) 2)))
(let* ((nargs (length (cddr form)))
(nfields 0)
(format-str (nth 1 form))
(len (length format-str))
(start 0))
(while (and (< start len)
(string-match
(rx "%"
(? (group (+ digit)) "$") ; field
(* (in "+ #0-")) ; flags
(* digit) ; width
(? "." (* digit)) ; precision
(? (group (in "sdioxXefgcS%")))) ; spec
format-str start))
(let ((field (if (match-beginning 1)
(string-to-number (match-string 1 format-str))
(1+ nfields)))
(spec (and (match-beginning 2)
(aref format-str (match-beginning 2)))))
(setq start (match-end 0))
(cond
((not spec)
(byte-compile-warn-x
form "Bad format sequence in call to `%s' at string offset %d"
(car form) (match-beginning 0)))
((not (eq spec ?%))
(setq nfields (max field nfields))))))
(unless (= nargs nfields)
(byte-compile-warn-x (car form)
"`%s' called with %d args to fill %d format field(s)" (car form)
nargs nfields)))))
(byte-compile-warn-x
(car form) "`%s' called with %d argument%s to fill %d format field%s"
(car form)
nargs (if (= nargs 1) "" "s")
nfields (if (= nfields 1) "" "s"))))))
(dolist (elt '(format message format-message error))
(put elt 'byte-compile-format-like t))

View file

@ -1135,7 +1135,7 @@ byte-compiled. Run with dynamic binding."
"var.*foo.*lacks a prefix")
(bytecomp--define-warning-file-test "warn-format.el"
"called with 2 args to fill 1 format field")
"called with 2 arguments to fill 1 format field")
(bytecomp--define-warning-file-test "warn-free-setq.el"
"free.*foo")