summaryrefslogtreecommitdiff
path: root/test/lisp/emacs-lisp
diff options
context:
space:
mode:
authorMattias EngdegÄrd <mattiase@acm.org>2022-06-17 17:06:05 +0200
committerMattias EngdegÄrd <mattiase@acm.org>2022-06-17 17:25:29 +0200
commit73e75e18d170826e1838324d39ac0698948071f8 (patch)
tree7ef1b3359cdb6ad2f78c4a90c05e8063384ea0bb /test/lisp/emacs-lisp
parente9c50055ff989a670d024045aba0050371a28fef (diff)
downloademacs-73e75e18d170826e1838324d39ac0698948071f8.tar.gz
emacs-73e75e18d170826e1838324d39ac0698948071f8.tar.bz2
emacs-73e75e18d170826e1838324d39ac0698948071f8.zip
Warn about misplaced or duplicated function/macro declarations
Doc strings, `declare` and `interactive` forms must appear in that order and at most once each. Complain if they don't, instead of silently ignoring the problem (bug#55905). * lisp/emacs-lisp/byte-run.el (byte-run--parse-body) (byte-run--parse-declarations): New. (defmacro, defun): Check for declaration well-formedness as described above. Clarify doc strings. Refactor some common code. * test/lisp/emacs-lisp/bytecomp-resources/fun-attr-warn.el: * test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-fun-attr-warn): New test.
Diffstat (limited to 'test/lisp/emacs-lisp')
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/fun-attr-warn.el266
-rw-r--r--test/lisp/emacs-lisp/bytecomp-tests.el63
2 files changed, 329 insertions, 0 deletions
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/fun-attr-warn.el b/test/lisp/emacs-lisp/bytecomp-resources/fun-attr-warn.el
new file mode 100644
index 00000000000..be907b32f47
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/fun-attr-warn.el
@@ -0,0 +1,266 @@
+;;; -*- lexical-binding: t -*-
+
+;; Correct
+
+(defun faw-str-decl-code (x)
+ "something"
+ (declare (pure t))
+ (print x))
+
+(defun faw-doc-decl-code (x)
+ (:documentation "something")
+ (declare (pure t))
+ (print x))
+
+(defun faw-str-int-code (x)
+ "something"
+ (interactive "P")
+ (print x))
+
+(defun faw-doc-int-code (x)
+ (:documentation "something")
+ (interactive "P")
+ (print x))
+
+(defun faw-decl-int-code (x)
+ (declare (pure t))
+ (interactive "P")
+ (print x))
+
+(defun faw-str-decl-int-code (x)
+ "something"
+ (declare (pure t))
+ (interactive "P")
+ (print x))
+
+(defun faw-doc-decl-int-code (x)
+ (:documentation "something")
+ (declare (pure t))
+ (interactive "P")
+ (print x))
+
+
+;; Correct (last string is return value)
+
+(defun faw-str ()
+ "something")
+
+(defun faw-decl-str ()
+ (declare (pure t))
+ "something")
+
+(defun faw-decl-int-str ()
+ (declare (pure t))
+ (interactive)
+ "something")
+
+(defun faw-str-str ()
+ "something"
+ "something else")
+
+(defun faw-doc-str ()
+ (:documentation "something")
+ "something else")
+
+
+;; Incorrect (bad order)
+
+(defun faw-int-decl-code (x)
+ (interactive "P")
+ (declare (pure t))
+ (print x))
+
+(defun faw-int-str-code (x)
+ (interactive "P")
+ "something"
+ (print x))
+
+(defun faw-int-doc-code (x)
+ (interactive "P")
+ (:documentation "something")
+ (print x))
+
+(defun faw-decl-str-code (x)
+ (declare (pure t))
+ "something"
+ (print x))
+
+(defun faw-decl-doc-code (x)
+ (declare (pure t))
+ (:documentation "something")
+ (print x))
+
+(defun faw-str-int-decl-code (x)
+ "something"
+ (interactive "P")
+ (declare (pure t))
+ (print x))
+
+(defun faw-doc-int-decl-code (x)
+ (:documentation "something")
+ (interactive "P")
+ (declare (pure t))
+ (print x))
+
+(defun faw-int-str-decl-code (x)
+ (interactive "P")
+ "something"
+ (declare (pure t))
+ (print x))
+
+(defun faw-int-doc-decl-code (x)
+ (interactive "P")
+ (:documentation "something")
+ (declare (pure t))
+ (print x))
+
+(defun faw-int-decl-str-code (x)
+ (interactive "P")
+ (declare (pure t))
+ "something"
+ (print x))
+
+(defun faw-int-decl-doc-code (x)
+ (interactive "P")
+ (declare (pure t))
+ (:documentation "something")
+ (print x))
+
+(defun faw-decl-int-str-code (x)
+ (declare (pure t))
+ (interactive "P")
+ "something"
+ (print x))
+
+(defun faw-decl-int-doc-code (x)
+ (declare (pure t))
+ (interactive "P")
+ (:documentation "something")
+ (print x))
+
+(defun faw-decl-str-int-code (x)
+ (declare (pure t))
+ "something"
+ (interactive "P")
+ (print x))
+
+(defun faw-decl-doc-int-code (x)
+ (declare (pure t))
+ (:documentation "something")
+ (interactive "P")
+ (print x))
+
+
+;; Incorrect (duplication)
+
+(defun faw-str-str-decl-int-code (x)
+ "something"
+ "something else"
+ (declare (pure t))
+ (interactive "P")
+ (print x))
+
+(defun faw-str-doc-decl-int-code (x)
+ "something"
+ (:documentation "something else")
+ (declare (pure t))
+ (interactive "P")
+ (print x))
+
+(defun faw-doc-str-decl-int-code (x)
+ (:documentation "something")
+ "something else"
+ (declare (pure t))
+ (interactive "P")
+ (print x))
+
+(defun faw-doc-doc-decl-int-code (x)
+ (:documentation "something")
+ (:documentation "something else")
+ (declare (pure t))
+ (interactive "P")
+ (print x))
+
+(defun faw-str-decl-str-int-code (x)
+ "something"
+ (declare (pure t))
+ "something else"
+ (interactive "P")
+ (print x))
+
+(defun faw-doc-decl-str-int-code (x)
+ (:documentation "something")
+ (declare (pure t))
+ "something else"
+ (interactive "P")
+ (print x))
+
+(defun faw-str-decl-doc-int-code (x)
+ "something"
+ (declare (pure t))
+ (:documentation "something else")
+ (interactive "P")
+ (print x))
+
+(defun faw-doc-decl-doc-int-code (x)
+ (:documentation "something")
+ (declare (pure t))
+ (:documentation "something else")
+ (interactive "P")
+ (print x))
+
+(defun faw-str-decl-decl-int-code (x)
+ "something"
+ (declare (pure t))
+ (declare (indent 1))
+ (interactive "P")
+ (print x))
+
+(defun faw-doc-decl-decl-int-code (x)
+ (:documentation "something")
+ (declare (pure t))
+ (declare (indent 1))
+ (interactive "P")
+ (print x))
+
+(defun faw-str-decl-int-decl-code (x)
+ "something"
+ (declare (pure t))
+ (interactive "P")
+ (declare (indent 1))
+ (print x))
+
+(defun faw-doc-decl-int-decl-code (x)
+ (:documentation "something")
+ (declare (pure t))
+ (interactive "P")
+ (declare (indent 1))
+ (print x))
+
+(defun faw-str-decl-int-int-code (x)
+ "something"
+ (declare (pure t))
+ (interactive "P")
+ (interactive "p")
+ (print x))
+
+(defun faw-doc-decl-int-int-code (x)
+ (:documentation "something")
+ (declare (pure t))
+ (interactive "P")
+ (interactive "p")
+ (print x))
+
+(defun faw-str-int-decl-int-code (x)
+ "something"
+ (interactive "P")
+ (declare (pure t))
+ (interactive "p")
+ (print x))
+
+(defun faw-doc-int-decl-int-code (x)
+ (:documentation "something")
+ (interactive "P")
+ (declare (pure t))
+ (interactive "p")
+ (print x))
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el
index 9abc17a1c41..fbc00b30c54 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -1580,6 +1580,69 @@ EXPECTED-POINT BINDINGS (MODES \\='\\='(ruby-mode js-mode python-mode)) \
(should (equal (get fname 'lisp-indent-function) 1))
(should (equal (aref bc 4) "tata\n\n(fn X)")))))
+(ert-deftest bytecomp-fun-attr-warn ()
+ ;; Check that warnings are emitted when doc strings, `declare' and
+ ;; `interactive' forms don't come in the proper order, or more than once.
+ (let* ((filename "fun-attr-warn.el")
+ (el (ert-resource-file filename))
+ (elc (concat el "c"))
+ (text-quoting-style 'grave))
+ (with-current-buffer (get-buffer-create "*Compile-Log*")
+ (let ((inhibit-read-only t))
+ (erase-buffer))
+ (byte-compile-file el)
+ (let ((expected
+ '("70:4: Warning: `declare' after `interactive'"
+ "74:4: Warning: Doc string after `interactive'"
+ "79:4: Warning: Doc string after `interactive'"
+ "84:4: Warning: Doc string after `declare'"
+ "89:4: Warning: Doc string after `declare'"
+ "96:4: Warning: `declare' after `interactive'"
+ "102:4: Warning: `declare' after `interactive'"
+ "108:4: Warning: `declare' after `interactive'"
+ "106:4: Warning: Doc string after `interactive'"
+ "114:4: Warning: `declare' after `interactive'"
+ "112:4: Warning: Doc string after `interactive'"
+ "118:4: Warning: Doc string after `interactive'"
+ "119:4: Warning: `declare' after `interactive'"
+ "124:4: Warning: Doc string after `interactive'"
+ "125:4: Warning: `declare' after `interactive'"
+ "130:4: Warning: Doc string after `declare'"
+ "136:4: Warning: Doc string after `declare'"
+ "142:4: Warning: Doc string after `declare'"
+ "148:4: Warning: Doc string after `declare'"
+ "159:4: Warning: More than one doc string"
+ "165:4: Warning: More than one doc string"
+ "171:4: Warning: More than one doc string"
+ "178:4: Warning: More than one doc string"
+ "186:4: Warning: More than one doc string"
+ "192:4: Warning: More than one doc string"
+ "200:4: Warning: More than one doc string"
+ "206:4: Warning: More than one doc string"
+ "215:4: Warning: More than one `declare' form"
+ "222:4: Warning: More than one `declare' form"
+ "230:4: Warning: More than one `declare' form"
+ "237:4: Warning: More than one `declare' form"
+ "244:4: Warning: More than one `interactive' form"
+ "251:4: Warning: More than one `interactive' form"
+ "258:4: Warning: More than one `interactive' form"
+ "257:4: Warning: `declare' after `interactive'"
+ "265:4: Warning: More than one `interactive' form"
+ "264:4: Warning: `declare' after `interactive'")))
+ (goto-char (point-min))
+ (let ((actual nil))
+ (while (re-search-forward
+ (rx bol (* (not ":")) ":"
+ (group (+ digit) ":" (+ digit) ": Warning: "
+ (or "More than one " (+ nonl) " form"
+ (: (+ nonl) " after " (+ nonl))))
+ eol)
+ nil t)
+ (push (match-string 1) actual))
+ (setq actual (nreverse actual))
+ (should (equal actual expected)))))))
+
+
;; Local Variables:
;; no-byte-compile: t
;; End: