emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 4bbd542: Checkdoc: use syntax functions instead of


From: Philipp Stephani
Subject: [Emacs-diffs] master 4bbd542: Checkdoc: use syntax functions instead of regex
Date: Sat, 31 Dec 2016 16:31:41 +0000 (UTC)

branch: master
commit 4bbd5424a2290ab4bd88c0af602b7aa7d53a407e
Author: Philipp Stephani <address@hidden>
Commit: Philipp Stephani <address@hidden>

    Checkdoc: use syntax functions instead of regex
    
    In checkdoc.el, get rid of the error-prone regex to find definition
    forms, and use existing syntax-based navigation functions instead.
    This fixes a corner case with one-argument `defvar' forms.
    
    * lisp/emacs-lisp/checkdoc.el (checkdoc--next-docstring): New function.
    (checkdoc-next-docstring, checkdoc-defun): Use it.
    * test/lisp/emacs-lisp/checkdoc-tests.el (checkdoc-tests--next-docstring):
    Add unit test.
---
 lisp/emacs-lisp/checkdoc.el            |   59 +++++++++++++++++---------------
 test/lisp/emacs-lisp/checkdoc-tests.el |   13 +++++++
 2 files changed, 44 insertions(+), 28 deletions(-)

diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index 2c8bc02..55978dd 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -294,12 +294,6 @@ problem discovered.  This is useful for adding additional 
checks.")
 (defvar checkdoc-diagnostic-buffer "*Style Warnings*"
   "Name of warning message buffer.")
 
-(defvar checkdoc-defun-regexp
-  "^(def\\(un\\|var\\|custom\\|macro\\|const\\|subst\\|advice\\)\
-\\s-+\\(\\(\\sw\\|\\s_\\)+\\)[ \t\n]*"
-  "Regular expression used to identify a defun.
-A search leaves the cursor in front of the parameter list.")
-
 (defcustom checkdoc-verb-check-experimental-flag t
   "Non-nil means to attempt to check the voice of the doc string.
 This check keys off some words which are commonly misused.  See the
@@ -938,13 +932,31 @@ is the starting location.  If this is nil, `point-min' is 
used instead."
 (defun checkdoc-next-docstring ()
   "Move to the next doc string after point, and return t.
 Return nil if there are no more doc strings."
-  (if (not (re-search-forward checkdoc-defun-regexp nil t))
-      nil
-    ;; search drops us after the identifier.  The next sexp is either
-    ;; the argument list or the value of the variable.  skip it.
-    (forward-sexp 1)
-    (skip-chars-forward " \n\t")
-    t))
+  (let (found)
+    (while (and (not (setq found (checkdoc--next-docstring)))
+                (beginning-of-defun -1)))
+    found))
+
+(defun checkdoc--next-docstring ()
+  "When looking at a definition with a doc string, find it.
+Move to the next doc string after point, and return t.  When not
+looking at a definition containing a doc string, return nil and
+don't move point."
+  (pcase (save-excursion (condition-case nil
+                             (read (current-buffer))
+                           ;; Conservatively skip syntax errors.
+                           (invalid-read-syntax)))
+    (`(,(or 'defun 'defvar 'defcustom 'defmacro 'defconst 'defsubst 'defadvice)
+       ,(pred symbolp)
+       ;; Require an initializer, i.e. ignore single-argument `defvar'
+       ;; forms, which never have a doc string.
+       ,_ . ,_)
+     (down-list)
+     ;; Skip over function or macro name, symbol to be defined, and
+     ;; initializer or argument list.
+     (forward-sexp 3)
+     (skip-chars-forward " \n\t")
+     t)))
 
 ;;;###autoload
 (defun checkdoc-comments (&optional take-notes)
@@ -1027,21 +1039,12 @@ space at the end of each line."
   (interactive)
   (save-excursion
     (beginning-of-defun)
-    (if (not (looking-at checkdoc-defun-regexp))
-       ;; I found this more annoying than useful.
-       ;;(if (not no-error)
-       ;;    (message "Cannot check this sexp's doc string."))
-       nil
-      ;; search drops us after the identifier.  The next sexp is either
-      ;; the argument list or the value of the variable.  skip it.
-      (goto-char (match-end 0))
-      (forward-sexp 1)
-      (skip-chars-forward " \n\t")
+    (when (checkdoc--next-docstring)
       (let* ((checkdoc-spellcheck-documentation-flag
-             (car (memq checkdoc-spellcheck-documentation-flag
+              (car (memq checkdoc-spellcheck-documentation-flag
                          '(defun t))))
-            (beg (save-excursion (beginning-of-defun) (point)))
-            (end (save-excursion (end-of-defun) (point))))
+             (beg (save-excursion (beginning-of-defun) (point)))
+             (end (save-excursion (end-of-defun) (point))))
         (dolist (fun (list #'checkdoc-this-string-valid
                            (lambda () (checkdoc-message-text-search beg end))
                            (lambda () (checkdoc-rogue-space-check-engine beg 
end))))
@@ -1049,8 +1052,8 @@ space at the end of each line."
             (if msg (if no-error
                         (message "%s" (checkdoc-error-text msg))
                       (user-error "%s" (checkdoc-error-text msg))))))
-       (if (called-interactively-p 'interactive)
-           (message "Checkdoc: done."))))))
+        (if (called-interactively-p 'interactive)
+            (message "Checkdoc: done."))))))
 
 ;;; Ispell interface for forcing a spell check
 ;;
diff --git a/test/lisp/emacs-lisp/checkdoc-tests.el 
b/test/lisp/emacs-lisp/checkdoc-tests.el
index 18b5a49..02db88c 100644
--- a/test/lisp/emacs-lisp/checkdoc-tests.el
+++ b/test/lisp/emacs-lisp/checkdoc-tests.el
@@ -37,4 +37,17 @@
     (insert "(defun foo())")
     (should-error (checkdoc-defun) :type 'user-error)))
 
+(ert-deftest checkdoc-tests--next-docstring ()
+  "Checks that the one-argument form of `defvar' works.
+See the comments in Bug#24998."
+  (with-temp-buffer
+    (emacs-lisp-mode)
+    (insert "(defvar foo)
+\(defvar foo bar \"baz\")
+\(require 'foo)")
+    (goto-char (point-min))
+    (should (checkdoc-next-docstring))
+    (should (looking-at-p "\"baz\")"))
+    (should-not (checkdoc-next-docstring))))
+
 ;;; checkdoc-tests.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]