Explorar el Código

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.
Nicolas Goaziou hace 3 años
padre
commit
628bb4f324
Se han modificado 2 ficheros con 60 adiciones y 27 borrados
  1. 54 27
      lisp/org-lint.el
  2. 6 0
      testing/lisp/test-org-lint.el

+ 54 - 27
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)

+ 6 - 0
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 ()