emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] master 230e25f: Fix a loop in C Mode caused by inadequate


From: Alan Mackenzie
Subject: [Emacs-diffs] master 230e25f: Fix a loop in C Mode caused by inadequate analysis of comments.
Date: Mon, 10 Apr 2017 17:04:22 -0400 (EDT)

branch: master
commit 230e25fd67fd654f04b8c744db0e170353a7f3b3
Author: Alan Mackenzie <address@hidden>
Commit: Alan Mackenzie <address@hidden>

    Fix a loop in C Mode caused by inadequate analysis of comments.
    
    After M-;, and the insertion of the opening "/*", the CC Mode after-change
    function got confused, since the new comment opener matched the end of a
    subsequent comment, but moving back over that comment did not come back to 
the
    starting point.  Fix this.
    
    * lisp/progmodes/cc-engine.el (c-end-of-macro): Add a limit parameter, 
wherer
    point is left if no end-of-macro is found before it.
    (c-forward-sws): Change the `safe-start' mechanism.  Now `safe-start' is
    non-nil except where we have an unclosed block comment at the end of a 
macro.
    This enables us to populate the cache more fully, at the cost of some run
    time.
---
 lisp/progmodes/cc-engine.el | 105 ++++++++++++++++++++++++++++++--------------
 1 file changed, 73 insertions(+), 32 deletions(-)

diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index de15d1d..e7a8962 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -319,34 +319,41 @@ comment at the start of cc-engine.el for more info."
            (goto-char here)
            nil))))))
 
-(defun c-end-of-macro ()
+(defun c-end-of-macro (&optional lim)
   "Go to the end of a preprocessor directive.
 More accurately, move the point to the end of the closest following
 line that doesn't end with a line continuation backslash - no check is
 done that the point is inside a cpp directive to begin with.
 
+If LIM is provided, it is a limit position at which point is left
+if the end of the macro doesn't occur earlier.
+
 Note that this function might do hidden buffer changes.  See the
 comment at the start of cc-engine.el for more info."
-   (if (and (cdr c-macro-cache)
-           (<= (point) (cdr c-macro-cache))
-           (>= (point) (car c-macro-cache)))
-       (goto-char (cdr c-macro-cache))
-     (unless (and (car c-macro-cache)
-                 (<= (point) c-macro-cache-start-pos)
-                 (>= (point) (car c-macro-cache)))
-       (setq c-macro-cache nil
-            c-macro-cache-start-pos nil
-            c-macro-cache-syntactic nil
-            c-macro-cache-no-comment nil))
-     (while (progn
-             (end-of-line)
-             (when (and (eq (char-before) ?\\)
-                        (not (eobp)))
-               (forward-char)
-               t)))
-     (when (car c-macro-cache)
-       (setcdr c-macro-cache (point))
-       (setq c-macro-cache-syntactic nil))))
+  (save-restriction
+    (if lim (narrow-to-region (point-min) lim))
+    (if (and (cdr c-macro-cache)
+            (<= (point) (cdr c-macro-cache))
+            (>= (point) (car c-macro-cache)))
+       (goto-char (cdr c-macro-cache))
+      (unless (and (car c-macro-cache)
+                  (<= (point) c-macro-cache-start-pos)
+                  (>= (point) (car c-macro-cache)))
+       (setq c-macro-cache nil
+             c-macro-cache-start-pos nil
+             c-macro-cache-syntactic nil
+             c-macro-cache-no-comment nil))
+      (while (progn
+              (end-of-line)
+              (when (and (eq (char-before) ?\\)
+                         (not (eobp)))
+                (forward-char)
+                t)))
+      (when (and (car c-macro-cache)
+                (bolp)
+                (not (eq (char-before (1- (point))) ?\\)))
+       (setcdr c-macro-cache (point))
+       (setq c-macro-cache-syntactic nil)))))
 
 (defun c-syntactic-end-of-macro ()
   ;; Go to the end of a CPP directive, or a "safe" pos just before.
@@ -1842,13 +1849,10 @@ comment at the start of cc-engine.el for more info."
   (let (;; `rung-pos' is set to a position as early as possible in the
        ;; unmarked part of the simple ws region.
        (rung-pos (point)) next-rung-pos rung-end-pos last-put-in-sws-pos
-       rung-is-marked next-rung-is-marked simple-ws-end
+       rung-is-marked next-rung-is-marked simple-ws-end macro-start macro-end
        ;; `safe-start' is set when it's safe to cache the start position.
-       ;; It's not set if we've initially skipped over comments and line
-       ;; continuations since we might have gone out through the end of a
-       ;; macro then.  This provision makes `c-forward-sws' not populate the
-       ;; cache in the majority of cases, but otoh is `c-backward-sws' by far
-       ;; more common.
+       ;; This is the case except when we have an unterminated block comment
+       ;; within a macro.
        safe-start)
 
     ;; Skip simple ws and do a quick check on the following character to see
@@ -1925,7 +1929,33 @@ comment at the start of cc-engine.el for more info."
 
            ;; Now move over any comments (x)or a CPP construct.
            (setq simple-ws-end (point))
-           (c-forward-comments)
+           (setq safe-start t)
+           ;; Take elaborate precautions to detect an open block comment at
+           ;; the end of a macro.  If we find one, we set `safe-start' to nil
+           ;; and break off any further scanning of comments.
+           (let ((com-begin (point)) com-end in-macro)
+             (when (and (c-forward-single-comment)
+                        (setq com-end (point))
+                        (save-excursion
+                          (goto-char com-begin)
+                          (c-beginning-of-macro)))
+               (setq in-macro t)
+               (goto-char com-begin)
+               (if (progn (c-end-of-macro com-end)
+                          (< (point) com-end))
+                   (setq safe-start nil)))
+             (if in-macro
+                 (while (and safe-start
+                             com-end (> com-end com-begin)
+                             (setq com-begin (point))
+                             (when (and (c-forward-single-comment)
+                                        (setq com-end (point)))
+                               (goto-char com-begin)
+                               (if (progn (c-end-of-macro com-end)
+                                          (< (point) com-end))
+                                   (setq safe-start nil))
+                               safe-start)))
+               (c-forward-comments)))
 
            (cond
             ((/= (point) simple-ws-end)
@@ -1936,6 +1966,7 @@ comment at the start of cc-engine.el for more info."
             ((save-excursion
                (and c-opt-cpp-prefix
                     (looking-at c-opt-cpp-start)
+                    (setq macro-start (point))
                     (progn (skip-chars-backward " \t")
                            (bolp))
                     (or (bobp)
@@ -1946,8 +1977,20 @@ comment at the start of cc-engine.el for more info."
              (while (and (eq (char-before) ?\\)
                          (= (forward-line 1) 0))
                (end-of-line))
+             (setq macro-end (point))
+             ;; Check for an open block comment at the end of the macro.
+             (goto-char macro-start)
+             (let (s in-block-comment)
+               (while
+                   (progn
+                     (setq s (parse-partial-sexp (point) macro-end
+                                                 nil nil s 'syntax-table))
+                     (< (point) macro-end))
+                 (setq in-block-comment
+                       (and (elt s 4)       ; in a comment
+                            (null (elt s 7))))) ; a block comment
+               (if in-block-comment (setq safe-start nil)))
              (forward-line 1)
-             (setq safe-start t)
              ;; Don't cache at eob in case the buffer is narrowed.
              (not (eobp)))
 
@@ -1955,7 +1998,6 @@ comment at the start of cc-engine.el for more info."
                   (looking-at c-noise-macro-name-re))
              ;; Skip over a noise macro.
              (goto-char (match-end 1))
-             (setq safe-start t)
              (not (eobp)))))
 
        ;; We've searched over a piece of non-white syntactic ws.  See if this
@@ -2018,8 +2060,7 @@ comment at the start of cc-engine.el for more info."
          (if (setq rung-is-marked next-rung-is-marked)
              (setq rung-pos (1- (c-next-single-property-change
                                  rung-is-marked 'c-is-sws nil rung-end-pos)))
-           (setq rung-pos next-rung-pos))
-         (setq safe-start t)))
+           (setq rung-pos next-rung-pos))))
 
       ;; Make sure that the newly marked `c-in-sws' region doesn't connect to
       ;; another one after the point (which might occur when editing inside a



reply via email to

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