* faces.el (face-all-attributes): Improved documentation (Bug#6767).
[bpt/emacs.git] / lisp / progmodes / cc-engine.el
index 0e6358a..9bbf82a 100644 (file)
@@ -2245,50 +2245,50 @@ comment at the start of cc-engine.el for more info."
            (setq cnt (1- cnt)))))
     (point)))
 
-(defun c-state-balance-parens-backwards (here top)
-  ;; Return the position of the opening paren/brace/bracket before HERE which
-  ;; matches the outermost close p/b/b between HERE and TOP, like this:
-  ;;
-  ;;      ......................................
-  ;;      |                                    |
-  ;;      (    [ ( ...........  )      ( )  ]  )
-  ;;      ^                 ^                       ^
-  ;;      |                 |                       |
-  ;;   return             HERE                     TOP
+(defun c-state-balance-parens-backwards (here- here+ top)
+  ;; Return the position of the opening paren/brace/bracket before HERE- which
+  ;; matches the outermost close p/b/b between HERE+ and TOP.  Except when
+  ;; there's a macro, HERE- and HERE+ are the same.  Like this:
+  ;;
+  ;;     ............................................
+  ;;     |                                          |
+  ;;     (    [ ( .........#macro.. )      ( )  ]  )
+  ;;     ^                 ^     ^                         ^
+  ;;     |                 |     |                         |
+  ;;   return            HERE- HERE+                      TOP
   ;;
   ;; If there aren't enough opening paren/brace/brackets, return the position
-  ;; of the outermost one found, or HERE it there are none.  If there are no
-  ;; closeing p/b/bs between HERE and TOP, return HERE.  HERE and TOP must not
-  ;; be inside literals.  Only the accessible portion of the buffer will be
-  ;; scanned.
-
-  ;; PART 1: scan from `here' up to `top', accumulating ")"s which enclose
-  ;; `here'.  Go round the next loop each time we pass over such a ")".  These
-  ;; probably match "("s before `here'.
+  ;; of the outermost one found, or HERE- if there are none.  If there are no
+  ;; closeing p/b/bs between HERE+ and TOP, return HERE-.  HERE-/+ and TOP
+  ;; must not be inside literals.  Only the accessible portion of the buffer
+  ;; will be scanned.
+
+  ;; PART 1: scan from `here+' up to `top', accumulating ")"s which enclose
+  ;; `here'.  Go round the next loop each time we pass over such a ")".         These
+  ;; probably match "("s before `here-'.
   (let (pos pa ren+1 lonely-rens)
     (save-excursion
       (save-restriction
        (narrow-to-region (point-min) top) ; This can move point, sometimes.
-       (setq pos here)
+       (setq pos here+)
        (c-safe
          (while
              (setq ren+1 (scan-lists pos 1 1)) ; might signal
            (setq lonely-rens (cons ren+1 lonely-rens)
                  pos ren+1)))))
 
-      ;; PART 2: Scan back before `here' searching for the "("s
+      ;; PART 2: Scan back before `here-' searching for the "("s
       ;; matching/mismatching the ")"s found above. We only need to direct the
       ;; caller to scan when we've encountered unmatched right parens.
-      (when lonely-rens
-       (setq pos here)
-       (c-safe
-         (while
-             (and lonely-rens          ; actual values aren't used.
-                  (setq pa (scan-lists pos -1 1)))
-           (setq pos pa)
-           (setq lonely-rens (cdr lonely-rens)))) ;)
-       )
-      pos))
+    (setq pos here-)
+    (when lonely-rens
+      (c-safe
+       (while
+           (and lonely-rens            ; actual values aren't used.
+                (setq pa (scan-lists pos -1 1)))
+         (setq pos pa)
+         (setq lonely-rens (cdr lonely-rens)))))
+    pos))
 
 (defun c-parse-state-get-strategy (here good-pos)
   ;; Determine the scanning strategy for adjusting `c-parse-state', attempting
@@ -2591,7 +2591,7 @@ comment at the start of cc-engine.el for more info."
   (save-restriction
     (narrow-to-region 1 (point-max))
     (save-excursion
-      (let* ((in-macro-start   ; point-max or beginning of macro containing it
+      (let* ((in-macro-start   ; start of macro containing (point-max) or nil.
              (save-excursion
                (goto-char (point-max))
                (and (c-beginning-of-macro)
@@ -2624,7 +2624,7 @@ comment at the start of cc-engine.el for more info."
                           (< (point-max) c-state-old-cpp-end)))
                  (point-max)
                (min (point-max) c-state-old-cpp-beg)))
-       (while (and c-state-cache (> (c-state-cache-top-lparen) upper-lim))
+       (while (and c-state-cache (>= (c-state-cache-top-lparen) upper-lim))
          (setq c-state-cache (cdr c-state-cache)))
        ;; If `upper-lim' is inside the last recorded brace pair, remove its
        ;; RBrace and indicate we'll need to search backwards for a previous
@@ -2641,7 +2641,9 @@ comment at the start of cc-engine.el for more info."
        ;; (car c-state-cache).  There can be no open parens/braces/brackets
        ;; between `good-pos'/`good-pos-actual-macro-start' and (point-max),
        ;; due to the interface spec to this function.
-       (setq pos (if good-pos-actual-macro-end
+       (setq pos (if (and good-pos-actual-macro-end
+                          (not (eq good-pos-actual-macro-start
+                                   in-macro-start)))
                      (1+ good-pos-actual-macro-end) ; get outside the macro as
                                        ; marked by a `category' text property.
                    good-pos))
@@ -2744,6 +2746,7 @@ comment at the start of cc-engine.el for more info."
        lit         ; (START . END) of a literal containing some point.
        here-lit-start here-lit-end     ; bounds of literal containing `here'
                                        ; or `here' itself.
+       here- here+                  ; start/end of macro around HERE, or HERE
        (here-bol (c-point 'bol here))
        (too-far-back (max (- here c-state-cache-too-far) 1)))
 
@@ -2756,57 +2759,73 @@ comment at the start of cc-engine.el for more info."
     ;; At this stage, (> pos here);
     ;; (< (c-state-cache-top-lparen) here)  (or is nil).
 
-    ;; CASE 1: The top of the cache is a brace pair which now encloses `here'.
-    ;; As good-pos, return the address. of the "{".
-    (if (and (consp (car c-state-cache))
-            (> (cdar c-state-cache) here))
-       ;; Since we've no knowledge of what's inside these braces, we have no
-       ;; alternative but to direct the caller to scan the buffer from the
-       ;; opening brace.
-       (progn
-         (setq pos (caar c-state-cache))
-         (setcar c-state-cache pos)
-         (list (1+ pos) pos t)) ; return value.  We've just converted a brace
-                                ; pair entry into a { entry, so the caller
-                                ; needs to search for a brace pair before the
-                                ; {.
-
-      ;; ;; `here' might be inside a literal.  Check for this.
-      (setq lit (c-state-literal-at here)
-           here-lit-start (or (car lit) here)
-           here-lit-end (or (cdr lit) here))
-
-      ;; `here' might be nested inside any depth of parens (or brackets but
-      ;; not braces).  Scan backwards to find the outermost such opening
-      ;; paren, if there is one.  This will be the scan position to return.
-      (save-restriction
-       (narrow-to-region cache-pos (point-max))
-       (setq pos (c-state-balance-parens-backwards here-lit-end pos)))
-
-      (if (< pos here-lit-start)
-         ;; CASE 2: Address of outermost ( or [ which now encloses `here',
-         ;; but didn't enclose the (previous) `c-state-cache-good-pos'.  If
-         ;; there is a brace pair preceding this, it will already be in
-         ;; `c-state-cache', unless there was a brace pair after it,
-         ;; i.e. there'll only be one to scan for if we've just deleted one.
-         (list pos (and dropped-cons pos) t) ; Return value.
-
-       ;; `here' isn't enclosed in a (previously unrecorded) bracket/paren.
-       ;; Further forward scanning isn't needed, but we still need to find a
-       ;; GOOD-POS.  Step out of all enclosing "("s on HERE's line.
+    (cond
+     ((and (consp (car c-state-cache))
+          (> (cdar c-state-cache) here))
+      ;; CASE 1: The top of the cache is a brace pair which now encloses
+      ;; `here'.  As good-pos, return the address. of the "{".  Since we've no
+      ;; knowledge of what's inside these braces, we have no alternative but
+      ;; to direct the caller to scan the buffer from the opening brace.
+      (setq pos (caar c-state-cache))
+      (setcar c-state-cache pos)
+      (list (1+ pos) pos t)) ; return value.  We've just converted a brace pair
+                            ; entry into a { entry, so the caller needs to
+                            ; search for a brace pair before the {.
+
+     ;; `here' might be inside a literal.  Check for this.
+     ((progn
+       (setq lit (c-state-literal-at here)
+             here-lit-start (or (car lit) here)
+             here-lit-end (or (cdr lit) here))
+       ;; Has `here' just "newly entered" a macro?
+       (save-excursion
+         (goto-char here-lit-start)
+         (if (and (c-beginning-of-macro)
+                  (or (null c-state-old-cpp-beg)
+                      (not (= (point) c-state-old-cpp-beg))))
+             (progn
+               (setq here- (point))
+               (c-end-of-macro)
+               (setq here+ (point)))
+           (setq here- here-lit-start
+                 here+ here-lit-end)))
+
+       ;; `here' might be nested inside any depth of parens (or brackets but
+       ;; not braces).  Scan backwards to find the outermost such opening
+       ;; paren, if there is one.  This will be the scan position to return.
+       (save-restriction
+         (narrow-to-region cache-pos (point-max))
+         (setq pos (c-state-balance-parens-backwards here- here+ pos)))
+       nil))                           ; for the cond
+
+     ((< pos here-lit-start)
+      ;; CASE 2: Address of outermost ( or [ which now encloses `here', but
+      ;; didn't enclose the (previous) `c-state-cache-good-pos'.  If there is
+      ;; a brace pair preceding this, it will already be in `c-state-cache',
+      ;; unless there was a brace pair after it, i.e. there'll only be one to
+      ;; scan for if we've just deleted one.
+      (list pos (and dropped-cons pos) t)) ; Return value.
+
+      ;; `here' isn't enclosed in a (previously unrecorded) bracket/paren.
+      ;; Further forward scanning isn't needed, but we still need to find a
+      ;; GOOD-POS.  Step out of all enclosing "("s on HERE's line.
+     ((progn
        (save-restriction
          (narrow-to-region here-bol (point-max))
          (setq pos here-lit-start)
          (c-safe (while (setq pa (scan-lists pos -1 1))
                    (setq pos pa))))    ; might signal
-       (if (setq ren (c-safe-scan-lists pos -1 -1 too-far-back))
-           ;; CASE 3: After a }/)/] before `here''s BOL.
-           (list (1+ ren) (and dropped-cons pos) nil) ; Return value
+       nil))                           ; for the cond
+
+     ((setq ren (c-safe-scan-lists pos -1 -1 too-far-back))
+       ;; CASE 3: After a }/)/] before `here''s BOL.
+      (list (1+ ren) (and dropped-cons pos) nil)) ; Return value
 
-         ;; CASE 4; Best of a bad job: BOL before `here-bol', or beginning of
-         ;; literal containing it.
-         (setq good-pos (c-state-lit-beg (c-point 'bopl here-bol)))
-         (list good-pos (and dropped-cons good-pos) nil))))))
+     (t
+      ;; CASE 4; Best of a bad job: BOL before `here-bol', or beginning of
+      ;; literal containing it.
+      (setq good-pos (c-state-lit-beg (c-point 'bopl here-bol)))
+      (list good-pos (and dropped-cons good-pos) nil)))))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2996,9 +3015,11 @@ comment at the start of cc-engine.el for more info."
   ;; containing point.  We can then call `c-invalidate-state-cache-1' without
   ;; worrying further about macros and template delimiters.
   (c-with-<->-as-parens-suppressed
-   (if c-state-old-cpp-beg
+   (if (and c-state-old-cpp-beg
+           (< c-state-old-cpp-beg here))
        (c-with-all-but-one-cpps-commented-out
-       c-state-old-cpp-beg c-state-old-cpp-end
+       c-state-old-cpp-beg
+       (min c-state-old-cpp-end here)
        (c-invalidate-state-cache-1 here))
      (c-with-cpps-commented-out
       (c-invalidate-state-cache-1 here)))))
@@ -3029,8 +3050,9 @@ comment at the start of cc-engine.el for more info."
              (c-parse-state-1))
           (c-with-cpps-commented-out
            (c-parse-state-1))))
-      (setq c-state-old-cpp-beg here-cpp-beg
-           c-state-old-cpp-end here-cpp-end))))
+      (setq c-state-old-cpp-beg (and here-cpp-beg (copy-marker here-cpp-beg t))
+           c-state-old-cpp-end (and here-cpp-end (copy-marker here-cpp-end t)))
+      )))
 
 ;; Debug tool to catch cache inconsistencies.  This is called from
 ;; 000tests.el.
@@ -4877,7 +4899,186 @@ comment at the start of cc-engine.el for more info."
        )))
 
 \f
-;; Handling of small scale constructs like types and names.
+;; Setting and removing syntax properties on < and > in languages (C++
+;; and Java) where they can be template/generic delimiters as well as
+;; their normal meaning of "less/greater than".
+
+;; Normally, < and > have syntax 'punctuation'.  When they are found to
+;; be delimiters, they are marked as such with the category properties
+;; c-<-as-paren-syntax, c->-as-paren-syntax respectively.
+
+;; STRATEGY:
+;;
+;; It is impossible to determine with certainty whether a <..> pair in
+;; C++ is two comparison operators or is template delimiters, unless
+;; one duplicates a lot of a C++ compiler.  For example, the following
+;; code fragment:
+;;
+;;     foo (a < b, c > d) ;
+;;
+;; could be a function call with two integer parameters (each a
+;; relational expression), or it could be a constructor for class foo
+;; taking one parameter d of templated type "a < b, c >".  They are
+;; somewhat easier to distinguish in Java.
+;;
+;; The strategy now (2010-01) adopted is to mark and unmark < and
+;; > IN MATCHING PAIRS ONLY.  [Previously, they were marked
+;; individually when their context so indicated.  This gave rise to
+;; intractible problems when one of a matching pair was deleted, or
+;; pulled into a literal.]
+;;
+;; At each buffer change, the syntax-table properties are removed in a
+;; before-change function and reapplied, when needed, in an
+;; after-change function.  It is far more important that the
+;; properties get removed when they they are spurious than that they
+;; be present when wanted.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun c-clear-<-pair-props (&optional pos)
+  ;; POS (default point) is at a < character.  If it is marked with
+  ;; open paren syntax-table text property, remove the property,
+  ;; together with the close paren property on the matching > (if
+  ;; any).
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c-<-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-list-forward))
+      (when (equal (c-get-char-property (1- (point)) 'syntax-table)
+                  c->-as-paren-syntax) ; should always be true.
+       (c-clear-char-property (1- (point)) 'category))
+      (c-clear-char-property pos 'category))))
+
+(defun c-clear->-pair-props (&optional pos)
+  ;; POS (default point) is at a > character.  If it is marked with
+  ;; close paren syntax-table property, remove the property, together
+  ;; with the open paren property on the matching < (if any).
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c->-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-up-list-backward))
+      (when (equal (c-get-char-property (point) 'syntax-table)
+                       c-<-as-paren-syntax) ; should always be true.
+       (c-clear-char-property (point) 'category))
+      (c-clear-char-property pos 'category))))
+
+(defun c-clear-<>-pair-props (&optional pos)
+  ;; POS (default point) is at a < or > character.  If it has an
+  ;; open/close paren syntax-table property, remove this property both
+  ;; from the current character and its partner (which will also be
+  ;; thusly marked).
+  (cond
+   ((eq (char-after) ?\<)
+    (c-clear-<-pair-props pos))
+   ((eq (char-after) ?\>)
+    (c-clear->-pair-props pos))
+   (t (c-benign-error
+       "c-clear-<>-pair-props called from wrong position"))))
+
+(defun c-clear-<-pair-props-if-match-after (lim &optional pos)
+  ;; POS (default point) is at a < character.  If it is both marked
+  ;; with open/close paren syntax-table property, and has a matching >
+  ;; (also marked) which is after LIM, remove the property both from
+  ;; the current > and its partner.  Return t when this happens, nil
+  ;; when it doesn't.
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c-<-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-list-forward))
+      (when (and (>= (point) lim)
+                (equal (c-get-char-property (1- (point)) 'syntax-table)
+                       c->-as-paren-syntax)) ; should always be true.
+       (c-unmark-<->-as-paren (1- (point)))
+       (c-unmark-<->-as-paren pos))
+      t)))
+
+(defun c-clear->-pair-props-if-match-before (lim &optional pos)
+  ;; POS (default point) is at a > character.  If it is both marked
+  ;; with open/close paren syntax-table property, and has a matching <
+  ;; (also marked) which is before LIM, remove the property both from
+  ;; the current < and its partner.  Return t when this happens, nil
+  ;; when it doesn't.
+  (save-excursion
+    (if pos
+       (goto-char pos)
+      (setq pos (point)))
+    (when (equal (c-get-char-property (point) 'syntax-table)
+                c->-as-paren-syntax)
+      (with-syntax-table c-no-parens-syntax-table ; ignore unbalanced [,{,(,..
+       (c-go-up-list-backward))
+      (when (and (<= (point) lim)
+                (equal (c-get-char-property (point) 'syntax-table)
+                       c-<-as-paren-syntax)) ; should always be true.
+       (c-unmark-<->-as-paren (point))
+       (c-unmark-<->-as-paren pos))
+      t)))
+
+(defun c-before-change-check-<>-operators (beg end)
+  ;; Unmark certain pairs of "< .... >" which are currently marked as
+  ;; template/generic delimiters.  (This marking is via syntax-table
+  ;; text properties).
+  ;;
+  ;; These pairs are those which are in the current "statement" (i.e.,
+  ;; the region between the {, }, or ; before BEG and the one after
+  ;; END), and which enclose any part of the interval (BEG END).
+  ;;
+  ;; Note that in C++ (?and Java), template/generic parens cannot
+  ;; enclose a brace or semicolon, so we use these as bounds on the
+  ;; region we must work on.
+  ;;
+  ;; This function is called from before-change-functions (via
+  ;; c-get-state-before-change-functions).  Thus the buffer is widened,
+  ;; and point is undefined, both at entry and exit.
+  ;;
+  ;; FIXME!!!  This routine ignores the possibility of macros entirely.
+  ;; 2010-01-29.
+  (save-excursion
+    (let ((beg-lit-limits (progn (goto-char beg) (c-literal-limits)))
+         (end-lit-limits (progn (goto-char end) (c-literal-limits)))
+         new-beg new-end need-new-beg need-new-end)
+      ;; Locate the barrier before the changed region
+      (goto-char  (if beg-lit-limits (car beg-lit-limits) beg))
+      (c-syntactic-skip-backward "^;{}" (max (- beg 2048) (point-min)))
+      (setq new-beg (point))
+
+      ;; Remove the syntax-table properties from each pertinent <...> pair.
+      ;; Firsly, the ones with the < before beg and > after beg.
+      (while (c-search-forward-char-property 'category 'c-<-as-paren-syntax beg)
+       (if (c-clear-<-pair-props-if-match-after beg (1- (point)))
+           (setq need-new-beg t)))
+
+      ;; Locate the barrier after END.
+      (goto-char (if end-lit-limits (cdr end-lit-limits) end))
+      (c-syntactic-re-search-forward "[;{}]"
+                                    (min (+ end 2048) (point-max)) 'end)
+      (setq new-end (point))
+
+      ;; Remove syntax-table properties from the remaining pertinent <...>
+      ;; pairs, those with a > after end and < before end.
+      (while (c-search-backward-char-property 'category 'c->-as-paren-syntax end)
+       (if (c-clear->-pair-props-if-match-before end)
+           (setq need-new-end t)))
+
+      ;; Extend the fontification region, if needed.
+      (when need-new-beg
+       (goto-char new-beg)
+       (c-forward-syntactic-ws)
+       (and (< (point) c-new-BEG) (setq c-new-BEG (point))))
+
+      (when need-new-end
+       (and (> new-end c-new-END) (setq c-new-END new-end))))))
+
+
 
 (defun c-after-change-check-<>-operators (beg end)
   ;; This is called from `after-change-functions' when
@@ -4899,7 +5100,7 @@ comment at the start of cc-engine.el for more info."
                 (< beg (setq beg (match-end 0))))
        (while (progn (skip-chars-forward "^<>" beg)
                      (< (point) beg))
-         (c-clear-char-property (point) 'syntax-table)
+         (c-clear-<>-pair-props)
          (forward-char))))
 
     (when (< beg end)
@@ -4914,9 +5115,13 @@ comment at the start of cc-engine.el for more info."
                   (< end (setq end (match-end 0))))
          (while (progn (skip-chars-forward "^<>" end)
                        (< (point) end))
-           (c-clear-char-property (point) 'syntax-table)
+           (c-clear-<>-pair-props)
            (forward-char)))))))
 
+
+\f
+;; Handling of small scale constructs like types and names.
+
 ;; Dynamically bound variable that instructs `c-forward-type' to also
 ;; treat possible types (i.e. those that it normally returns 'maybe or
 ;; 'found for) as actual types (and always return 'found for them).