summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2021-04-19 02:06:01 +0200
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2021-04-19 02:06:01 +0200
commit628bb4f324b664f4ef75f1d60406eca92ee5e7d3 (patch)
treed5bc8096a6a481b7c745893349601fa92b6510ad
parent772f7acb6511699c701eb7af8b3c42ac3195f5ca (diff)
downloadorg-mode-628bb4f324b664f4ef75f1d60406eca92ee5e7d3.tar.gz
lint: Improve checks for internal macros
* lisp/org-lint.el (org-lint-invalid-macro-argument-and-template): Add arity checks for internal macros. * testing/lisp/test-org-lint.el (test-org-lint/invalid-macro-argument-and-template): Add tests.
-rw-r--r--lisp/org-lint.el81
-rw-r--r--testing/lisp/test-org-lint.el6
2 files changed, 60 insertions, 27 deletions
diff --git a/lisp/org-lint.el b/lisp/org-lint.el
index 94db816..87ab78b 100644
--- a/lisp/org-lint.el
+++ b/lisp/org-lint.el
@@ -687,15 +687,42 @@ Use \"export %s\" instead"
reports))
(defun org-lint-invalid-macro-argument-and-template (ast)
- (let ((extract-placeholders
- (lambda (template)
- (let ((start 0)
- args)
- (while (string-match "\\$\\([1-9][0-9]*\\)" template start)
- (setf start (match-end 0))
- (push (string-to-number (match-string 1 template)) args))
- (sort (org-uniquify args) #'<))))
- reports)
+ (let* ((reports nil)
+ (extract-placeholders
+ (lambda (template)
+ (let ((start 0)
+ args)
+ (while (string-match "\\$\\([1-9][0-9]*\\)" template start)
+ (setf start (match-end 0))
+ (push (string-to-number (match-string 1 template)) args))
+ (sort (org-uniquify args) #'<))))
+ (check-arity
+ (lambda (arity macro)
+ (let* ((name (org-element-property :key macro))
+ (pos (org-element-property :begin macro))
+ (args (org-element-property :args macro))
+ (l (length args)))
+ (cond
+ ((< l (1- (car arity)))
+ (push (list pos (format "Missing arguments in macro %S" name))
+ reports))
+ ((< l (car arity))
+ (push (list pos (format "Missing argument in macro %S" name))
+ reports))
+ ((> l (1+ (cdr arity)))
+ (push (let ((spurious-args (nthcdr (cdr arity) args)))
+ (list pos
+ (format "Spurious arguments in macro %S: %s"
+ name
+ (mapconcat #'org-trim spurious-args ", "))))
+ reports))
+ ((> l (cdr arity))
+ (push (list pos
+ (format "Spurious argument in macro %S: %s"
+ name
+ (org-last args)))
+ reports))
+ (t nil))))))
;; Check arguments for macro templates.
(org-element-map ast 'keyword
(lambda (k)
@@ -730,31 +757,31 @@ Use \"export %s\" instead"
(org-element-map ast 'macro
(lambda (macro)
(let* ((name (org-element-property :key macro))
+ (args (org-element-property :args macro))
(template (cdr (assoc-string name templates t))))
(pcase template
(`nil
(push (list (org-element-property :begin macro)
(format "Undefined macro %S" name))
reports))
- ((pred functionp) nil) ;ignore it
+ ((guard (string= name "keyword"))
+ (funcall check-arity '(1 . 1) macro))
+ ((guard (string= name "modification-time"))
+ (funcall check-arity '(1 . 2) macro))
+ ((guard (string= name "n"))
+ (funcall check-arity '(0 . 2) macro))
+ ((guard (string= name "property"))
+ (funcall check-arity '(1 . 2) macro))
+ ((guard (string= name "time"))
+ (funcall check-arity '(1 . 1) macro))
+ ((pred functionp)) ;ignore (eval ...) templates
(_
- (let ((arg-numbers (funcall extract-placeholders template)))
- (when arg-numbers
- (let ((spurious-args
- (nthcdr (apply #'max arg-numbers)
- (org-element-property :args macro))))
- (when spurious-args
- (push
- (list (org-element-property :begin macro)
- (pcase spurious-args
- (`(,arg)
- (format "Unused argument in macro %S: %s"
- name arg))
- (args
- (format "Unused arguments in macro %S: %s"
- name
- (mapconcat #'org-trim args ", ")))))
- reports)))))))))))
+ (let* ((arg-numbers (funcall extract-placeholders template))
+ (arity (if (null arg-numbers)
+ '(0 . 0)
+ (let ((m (apply #'max arg-numbers)))
+ (cons m m)))))
+ (funcall check-arity arity macro))))))))
reports))
(defun org-lint-undefined-footnote-reference (ast)
diff --git a/testing/lisp/test-org-lint.el b/testing/lisp/test-org-lint.el
index 800599e..e57993c 100644
--- a/testing/lisp/test-org-lint.el
+++ b/testing/lisp/test-org-lint.el
@@ -339,6 +339,12 @@ This is not a node property
(should-not
(org-test-with-temp-text
"#+macro: valid $1 $2\n{{{valid(1, 2)}}}"
+ (org-lint '(invalid-macro-argument-and-template))))
+ (should
+ (org-test-with-temp-text "{{{keyword}}}"
+ (org-lint '(invalid-macro-argument-and-template))))
+ (should
+ (org-test-with-temp-text "{{{keyword(one, too many)}}}"
(org-lint '(invalid-macro-argument-and-template)))))
(ert-deftest test-org-lint/undefined-footnote-reference ()