Check keyword args of make-process

The functions make-process and make-network-process have many
keyword args and it's easy to misspell some of them.

Use a compiler macro to warn about some possible mistakes.

* lisp/emacs-lisp/bytecomp.el (bytecomp--check-keyword-args): New
  helper.
  (make-process, make-network-process): Define a compiler macro that
  performs some checks but doesn't anything else.

* test/lisp/emacs-lisp/bytecomp-tests.el: Add some tests.

* test/lisp/emacs-lisp/bytecomp-resources/:
  (warn-make-process-missing-keyword-arg.el,
   warn-make-process-missing-keyword-value.el,
   warn-make-process-repeated-keyword-arg.el,
   warn-make-process-unknown-keyword-arg.el): New test files
This commit is contained in:
Helmut Eller 2023-08-03 08:33:40 +02:00 committed by Mattias Engdegård
parent efb3ef0fe0
commit 3e79fd3d4e
6 changed files with 90 additions and 0 deletions

View file

@ -5782,6 +5782,67 @@ and corresponding effects."
form ; arity error
`(forward-word (- (or ,arg 1)))))
(defun bytecomp--check-keyword-args (form arglist allowed-keys required-keys)
(let ((fun (car form)))
(cl-flet ((missing (form keyword)
(byte-compile-warn-x
form
"`%S´ called without required keyword argument %S"
fun keyword))
(unrecognized (form keyword)
(byte-compile-warn-x
form
"`%S´ called with unknown keyword argument %S"
fun keyword))
(duplicate (form keyword)
(byte-compile-warn-x
form
"`%S´ called with repeated keyword argument %S"
fun keyword))
(missing-val (form keyword)
(byte-compile-warn-x
form
"missing value for keyword argument %S"
keyword)))
(let* ((seen '())
(l arglist))
(while (consp l)
(let ((key (car l)))
(cond ((and (keywordp key) (memq key allowed-keys))
(cond ((memq key seen)
(duplicate l key))
(t
(push key seen))))
(t (unrecognized l key)))
(when (null (cdr l))
(missing-val l key)))
(setq l (cddr l)))
(dolist (key required-keys)
(unless (memq key seen)
(missing form key))))))
form)
(put 'make-process 'compiler-macro
#'(lambda (form &rest args)
(bytecomp--check-keyword-args
form args
'(:name
:buffer :command :coding :noquery :stop :connection-type
:filter :sentinel :stderr :file-handler)
'(:name :command))))
(put 'make-network-process 'compiler-macro
#'(lambda (form &rest args)
(bytecomp--check-keyword-args
form args
'(:name
:buffer :host :service :type :family :local :remote :coding
:nowait :noquery :stop :filter :filter-multibyte :sentinel
:log :plist :tls-parameters :server :broadcast :dontroute
:keepalive :linger :oobinline :priority :reuseaddr :bindtodevice
:use-external-socket)
'(:name :service))))
(provide 'byte-compile)
(provide 'bytecomp)

View file

@ -0,0 +1,3 @@
;;; -*- lexical-binding: t -*-
(defun foo ()
(make-process :name "ls"))

View file

@ -0,0 +1,3 @@
;;; -*- lexical-binding: t -*-
(defun foo ()
(make-process :name "ls" :command))

View file

@ -0,0 +1,3 @@
;;; -*- lexical-binding: t -*-
(defun foo ()
(make-process :name "ls" :command "ls" :name "ls"))

View file

@ -0,0 +1,4 @@
;;; -*- lexical-binding: t -*-
(defun foo ()
(make-process :name "ls" :command "ls"
:coding-system 'binary))

View file

@ -1204,6 +1204,22 @@ byte-compiled. Run with dynamic binding."
"nowarn-inline-after-defvar.el"
"Lexical argument shadows" 'reverse)
(bytecomp--define-warning-file-test
"warn-make-process-missing-keyword-arg.el"
"called without required keyword argument :command")
(bytecomp--define-warning-file-test
"warn-make-process-unknown-keyword-arg.el"
"called with unknown keyword argument :coding-system")
(bytecomp--define-warning-file-test
"warn-make-process-repeated-keyword-arg.el"
"called with repeated keyword argument :name")
(bytecomp--define-warning-file-test
"warn-make-process-missing-keyword-value.el"
"missing value for keyword argument :command")
;;;; Macro expansion.