Fix spurious fontification of "for (; a * b;)" in CC Mode.

This fixes bug #7918 (again).

* lisp/progmodes/cc-engine.el (c-delq-from-dotted-list): New function.
(c-forward-decl-or-cast-1): Return a 4 element list in place of the previous
cons cell - additionally, return a flag indicating whether the declaration
parsed might have been an expression, and the position of the type identifier
in the said declaration.

* lisp/progmodes/cc-fonts.el (c-font-lock-declarations): When
c-forward-decl-or-cast-1 has indicated it might have parsed an expression,
check for it being a spurious declaration in a "for" statement.
This commit is contained in:
Alan Mackenzie 2016-05-16 11:27:39 +00:00
parent 65c8c7cb96
commit 116acebfbd
2 changed files with 66 additions and 10 deletions

View file

@ -385,6 +385,25 @@ comment at the start of cc-engine.el for more info."
;;; Basic utility functions.
(defun c-delq-from-dotted-list (elt dlist)
;; If ELT is a member of the (possibly dotted) list DLIST, remove all
;; occurrences of it (except for any in the last cdr of DLIST).
;;
;; Call this as (setq DLIST (c-delq-from-dotted-list ELT DLIST)), as
;; sometimes the original structure is changed, sometimes it's not.
;;
;; This function is needed in Emacs < 24.5, and possibly XEmacs, because
;; `delq' throws an error in these versions when given a dotted list.
(let ((tail dlist) prev)
(while (consp tail)
(if (eq (car tail) elt)
(if prev
(setcdr prev (cdr tail))
(setq dlist (cdr dlist)))
(setq prev tail))
(setq tail (cdr tail)))
dlist))
(defun c-syntactic-content (from to paren-level)
;; Return the given region as a string where all syntactic
;; whitespace is removed or, where necessary, replaced with a single
@ -7020,9 +7039,9 @@ comment at the start of cc-engine.el for more info."
;; If a declaration is parsed:
;;
;; The point is left at the first token after the first complete
;; declarator, if there is one. The return value is a cons where
;; the car is the position of the first token in the declarator. (See
;; below for the cdr.)
;; declarator, if there is one. The return value is a list of 4 elements,
;; where the first is the position of the first token in the declarator.
;; (See below for the other three.)
;; Some examples:
;;
;; void foo (int a, char *b) stuff ...
@ -7053,7 +7072,7 @@ comment at the start of cc-engine.el for more info."
;;
;;
;;
;; The cdr of the return value is non-nil when a
;; The second element of the return value is non-nil when a
;; `c-typedef-decl-kwds' specifier is found in the declaration.
;; Specifically it is a dotted pair (A . B) where B is t when a
;; `c-typedef-kwds' ("typedef") is present, and A is t when some
@ -7061,6 +7080,10 @@ comment at the start of cc-engine.el for more info."
;; specifier is present. I.e., (some of) the declared
;; identifier(s) are types.
;;
;; The third element of the return value is non-nil when the declaration
;; parsed might be an expression. The fourth element is the position of
;; the start of the type identifier.
;;
;; If a cast is parsed:
;;
;; The point is left at the first token after the closing paren of
@ -7161,7 +7184,10 @@ comment at the start of cc-engine.el for more info."
;; speculatively and should be thrown away if it turns out
;; that it isn't a declaration or cast.
(save-rec-type-ids c-record-type-identifiers)
(save-rec-ref-ids c-record-ref-identifiers))
(save-rec-ref-ids c-record-ref-identifiers)
;; Set when we parse a declaration which might also be an expression,
;; such as "a *b". See CASE 16 and CASE 17.
maybe-expression)
(save-excursion
(goto-char preceding-token-end)
@ -7799,6 +7825,7 @@ comment at the start of cc-engine.el for more info."
;; the construct look like a function call) when
;; `at-decl-start' provides additional evidence that we do
;; have a declaration.
(setq maybe-expression t)
(throw 'at-decl-or-cast t))
;; CASE 17
@ -7810,6 +7837,7 @@ comment at the start of cc-engine.el for more info."
;; be an odd expression or it could be a declaration. Treat
;; it as a declaration if "a" has been used as a type
;; somewhere else (if it's a known type we won't get here).
(setq maybe-expression t)
(throw 'at-decl-or-cast t)))
;; CASE 18
@ -7933,9 +7961,11 @@ comment at the start of cc-engine.el for more info."
(goto-char type-start)
(c-forward-type))))
(cons id-start
(list id-start
(and (or at-type-decl at-typedef)
(cons at-type-decl at-typedef))))
(cons at-type-decl at-typedef))
maybe-expression
type-start))
(t
;; False alarm. Restore the recorded ranges.

View file

@ -1336,6 +1336,32 @@ casts and declarations are fontified. Used on level 2 and higher."
(when (> (point) max-type-decl-end)
(setq max-type-decl-end (point))))
;; Do we have an expression as the second or third clause of
;; a "for" paren expression?
(if (save-excursion
(and
(car (cddr decl-or-cast)) ; maybe-expression flag.
(goto-char start-pos)
(c-go-up-list-backward)
(eq (char-after) ?\()
(progn (c-backward-syntactic-ws)
(c-simple-skip-symbol-backward))
(looking-at c-paren-stmt-key)
(progn (goto-char match-pos)
(while (and (eq (char-before) ?\))
(c-go-list-backward))
(c-backward-syntactic-ws))
(eq (char-before) ?\;))))
;; We've got an expression in "for" parens. Remove the
;; "type" that would spuriously get fontified.
(let ((elt (and (consp c-record-type-identifiers)
(assq (cadr (cddr decl-or-cast))
c-record-type-identifiers))))
(when elt
(setq c-record-type-identifiers
(c-delq-from-dotted-list
elt c-record-type-identifiers)))
t)
;; Back up to the type to fontify the declarator(s).
(goto-char (car decl-or-cast))
@ -1361,17 +1387,17 @@ casts and declarations are fontified. Used on level 2 and higher."
(c-backward-syntactic-ws)
(unless (bobp)
(c-put-char-property (1- (point)) 'c-type
(if (cdr decl-or-cast)
(if (cadr decl-or-cast)
'c-decl-type-start
'c-decl-id-start)))))
(c-font-lock-declarators
(point-max) decl-list (cdr decl-or-cast)))
(point-max) decl-list (cadr decl-or-cast)))
;; A declaration has been successfully identified, so do all the
;; fontification of types and refs that've been recorded.
(c-fontify-recorded-types-and-refs)
nil)
nil))
;; Restore point, since at this point in the code it has been
;; left undefined by c-forward-decl-or-cast-1 above.