Hello again, Ryan.
On Fri, Mar 10, 2017 at 12:27:25 +0000, Dixon Ryan (ETAS/ERS-PD2) wrote:
[ .... ]
Post by Dixon Ryan (ETAS/ERS-PD2)I have a constructor with three arguments. The first and second
arguments are not highlighted correctly. The issue is with references
or pointers to user-defined types and seems to manifest mostly when
there is no scope resolution involved with the user defined type -
Class OneClassHere : public AnotherClassThere[]
{
/// lots of stuff
Constructor( MyType1& ref,
NS1::MyType2& ref1,
MyType3& ref2 );
/// lots of stuff
};
This is all highlighted correctly on initial entry to the file.
However, when I put the cursor at [] and add a space the ref2 and its
type are no longer highlighted. Then, when I click anywhere on the
screen ref and its type are not highlighted. Ref1 stays highlighted.
If I reload the file it is all highlighted correctly. Also, this bug
only occurs when there is a newline at the end of the arguments. For
Constructor(MyType1& ref, NS1::MyType2& ref1, MyType3& ref2 );
It is always hlight correctly no matter what.
I have a reproducible MyClass.h file (I then invoke c++-mode since it's a .h)
[ .... ]
Post by Dixon Ryan (ETAS/ERS-PD2)Upon load all is hlighted. Then, I move to the {} and press space.
Ref1 and its type is white. Then I left click somewhere on the buffer
and someType and its type is white.
IF, I remove the doxygen comment block - all those lines with ///
then the problem does not happen. It therefore looks like the parsing
of doxygen is causing the issue?
Thank you.
OK, I think I've fixed these things, or at least most of them. Part of
the fix is implementing the "asymmetric fontification" rule that we've
discussed elsewhere on the thread. You can disable this by setting the
new user option `c-asymmetric-fontification-flag' to nil.
Here's a patch. Would you try it out, please. (In the unlikely event
you want help patching or building CC Mode, feel free to send me private
email.) Please confirm that it fixes the problems in your real code, or
alternatively let me know what's still not right.
Thanks!
diff -r 51f7a9ff5450 cc-engine.el
--- a/cc-engine.el Sat Feb 25 14:39:10 2017 +0000
+++ b/cc-engine.el Wed Mar 22 20:44:25 2017 +0000
@@ -6252,9 +6252,9 @@
(eq (char-before) ?<))
(c-backward-token-2)
(when (eq (char-after) ?<)
- (c-clear-<-pair-props-if-match-after beg)))
+ (c-clear-<-pair-props-if-match-after beg)
+ (setq new-beg (point))))
(c-forward-syntactic-ws)
- (setq new-beg (point))
;; ...Then the ones with < before end and > after end.
(goto-char (if end-lit-limits (cdr end-lit-limits) end))
@@ -6263,9 +6263,9 @@
(eq (char-before) ?>))
(c-end-of-current-token)
(when (eq (char-before) ?>)
- (c-clear->-pair-props-if-match-before end (1- (point)))))
+ (c-clear->-pair-props-if-match-before end (1- (point)))
+ (setq new-end (point))))
(c-backward-syntactic-ws)
- (setq new-end (point))
;; Extend the fontification region, if needed.
(and new-beg
@@ -8863,7 +8863,29 @@
;; 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)))
+ (throw 'at-decl-or-cast t))
+
+ ;; CASE 17.5
+ (when (and c-asymmetry-fontification-flag
+ got-prefix-before-parens
+ at-type
+ (or (not got-suffix)
+ at-decl-start))
+ (let ((space-before-id
+ (save-excursion
+ (goto-char name-start)
+ (or (bolp) (memq (char-before) '(?\ ?\t)))))
+ (space-after-type
+ (save-excursion
+ (goto-char type-start)
+ (and (c-forward-type)
+ (progn (c-backward-syntactic-ws) t)
+ (or (eolp)
+ (memq (char-after) '(?\ ?\t)))))))
+ (when (not (eq (not space-before-id)
+ (not space-after-type)))
+ (setq maybe-expression t)
+ (throw 'at-decl-or-cast t)))))
;; CASE 18
(when (and (not (memq context '(nil top)))
diff -r 51f7a9ff5450 cc-fonts.el
--- a/cc-fonts.el Sat Feb 25 14:39:10 2017 +0000
+++ b/cc-fonts.el Wed Mar 22 20:44:25 2017 +0000
@@ -1116,6 +1116,121 @@
(setq pos (point)))))) ; acts to make the `while' form continue.
nil)
+(defun c-get-fontification-context (match-pos not-front-decl &optional toplev)
+ ;; Return a cons (CONTEXT . RESTRICTED-<>-ARGLISTS) for MATCH-POS.
+ ;;
+ ;; CONTEXT is the fontification context of MATCH-POS, and is one of the
+ ;; following:
+ ;; 'decl In a comma-separated declaration context (typically
+ ;; inside a function declaration arglist).
+ ;; '<> In an angle bracket arglist.
+ ;; 'arglist Some other type of arglist.
+ ;; 'top Some other context and point is at the top-level (either
+ ;; outside any braces or directly inside a class or namespace,
+ ;; etc.)
+ ;; nil Some other context or unknown context. Includes
+ ;; within the parens of an if, for, ... construct.
+ ;; 'not-decl Definitely not in a declaration.
+ ;;
+ ;; RESTRICTED-<>-ARGLISTS is non-nil ......
+ (let ((type (and (> match-pos (point-min))
+ (c-get-char-property (1- match-pos) 'c-type))))
+ (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?< ?{)))
+ (cons (and toplev 'top) nil))
+ ;; A control flow expression or a decltype
+ ((and (eq (char-before match-pos) ?\()
+ (save-excursion
+ (goto-char match-pos)
+ (backward-char)
+ (c-backward-token-2)
+ (or (looking-at c-block-stmt-2-key)
+ (looking-at c-block-stmt-1-2-key)
+ (looking-at c-typeof-key))))
+ (cons nil t)) ; (2017-03-19): perhaps 'not-decl???
+ ;; Near BOB.
+ ((<= match-pos (point-min))
+ (cons 'arglist t))
+ ;; Got a cached hit in a declaration arglist.
+ ((eq type 'c-decl-arg-start)
+ (cons 'decl nil))
+ ;; We're inside (probably) a brace list.
+ ((eq type 'c-not-decl)
+ (cons 'not-decl nil))
+ ;; Inside a C++11 lambda function arglist.
+ ((and (c-major-mode-is 'c++-mode)
+ (eq (char-before match-pos) ?\()
+ (save-excursion
+ (goto-char match-pos)
+ (c-backward-token-2)
+ (and
+ (c-safe (goto-char (scan-sexps (point) -1)))
+ (c-looking-at-c++-lambda-capture-list))))
+ (c-put-char-property (1- match-pos) 'c-type
+ 'c-decl-arg-start)
+ (cons 'decl nil))
+ ;; We're inside a brace list.
+ ((and (eq (char-before match-pos) ?{)
+ (save-excursion
+ (goto-char (1- match-pos))
+ (consp
+ (c-looking-at-or-maybe-in-bracelist))))
+ (c-put-char-property (1- match-pos) 'c-type
+ 'c-not-decl)
+ (cons 'not-decl nil))
+ ;; We're inside an "ordinary" open brace.
+ ((eq (char-before match-pos) ?{)
+ (cons (and toplev 'top) nil))
+ ;; Inside an angle bracket arglist.
+ ((or (eq type 'c-<>-arg-sep)
+ (eq (char-before match-pos) ?<))
+ (cons '<> nil))
+ ;; Got a cached hit in some other type of arglist.
+ (type
+ (cons 'arglist t))
+ (;; (if inside-macro
+ ;; (< match-pos max-type-decl-end-before-token)
+ ;; (< match-pos max-type-decl-end))
+ not-front-decl
+ ;; The point is within the range of a previously
+ ;; encountered type decl expression, so the arglist
+ ;; is probably one that contains declarations.
+ ;; However, if `c-recognize-paren-inits' is set it
+ ;; might also be an initializer arglist.
+ ;;
+ ;; The result of this check is cached with a char
+ ;; property on the match token, so that we can look
+ ;; it up again when refontifying single lines in a
+ ;; multiline declaration.
+ (c-put-char-property (1- match-pos)
+ 'c-type 'c-decl-arg-start)
+ (cons 'decl nil))
+ ;; Got an open paren preceded by an arith operator.
+ ((and (eq (char-before match-pos) ?\()
+ (save-excursion
+ (and (zerop (c-backward-token-2 2))
+ (looking-at c-arithmetic-op-regexp))))
+ (cons nil nil)) ; (2017-03-19): perhaps 'not-decl???
+ ;; At start of a declaration inside a declaration paren.
+ ((save-excursion
+ (and (memq (char-before match-pos) '(?\( ?\,))
+ (c-go-up-list-backward match-pos)
+ (eq (char-after) ?\()
+ (let ((type (c-get-char-property (point) 'c-type)))
+ (or (memq type '(c-decl-arg-start c-decl-type-start))
+ (and
+ (progn (c-backward-syntactic-ws) t)
+ (c-back-over-compound-identifier)
+ (progn
+ (c-backward-syntactic-ws)
+ (or (bobp)
+ (progn
+ (setq type (c-get-char-property (1- (point))
+ 'c-type))
+ (memq type '(c-decl-arg-start
+ c-decl-type-start))))))))))
+ (cons 'decl nil))
+ (t (cons 'arglist t)))))
+
(defun c-font-lock-declarations (limit)
;; Fontify all the declarations, casts and labels from the point to LIMIT.
;; Assumes that strings and comments have been fontified already.
@@ -1230,95 +1345,15 @@
;; "<" for the sake of C++-style template arglists.
;; Ignore "(" when it's part of a control flow construct
;; (e.g. "for (").
- (let ((type (and (> match-pos (point-min))
- (c-get-char-property (1- match-pos) 'c-type))))
- (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?< ?{)))
- (setq context (and toplev 'top)
- c-restricted-<>-arglists nil))
- ;; A control flow expression or a decltype
- ((and (eq (char-before match-pos) ?\()
- (save-excursion
- (goto-char match-pos)
- (backward-char)
- (c-backward-token-2)
- (or (looking-at c-block-stmt-2-key)
- (looking-at c-block-stmt-1-2-key)
- (looking-at c-typeof-key))))
- (setq context nil
- c-restricted-<>-arglists t))
- ;; Near BOB.
- ((<= match-pos (point-min))
- (setq context 'arglist
- c-restricted-<>-arglists t))
- ;; Got a cached hit in a declaration arglist.
- ((eq type 'c-decl-arg-start)
- (setq context 'decl
- c-restricted-<>-arglists nil))
- ;; We're inside (probably) a brace list.
- ((eq type 'c-not-decl)
- (setq context 'not-decl
- c-restricted-<>-arglists nil))
- ;; Inside a C++11 lambda function arglist.
- ((and (c-major-mode-is 'c++-mode)
- (eq (char-before match-pos) ?\()
- (save-excursion
- (goto-char match-pos)
- (c-backward-token-2)
- (and
- (c-safe (goto-char (scan-sexps (point) -1)))
- (c-looking-at-c++-lambda-capture-list))))
- (setq context 'decl
- c-restricted-<>-arglists nil)
- (c-put-char-property (1- match-pos) 'c-type
- 'c-decl-arg-start))
- ;; We're inside a brace list.
- ((and (eq (char-before match-pos) ?{)
- (save-excursion
- (goto-char (1- match-pos))
- (consp
- (c-looking-at-or-maybe-in-bracelist))))
- (setq context 'not-decl
- c-restricted-<>-arglists nil)
- (c-put-char-property (1- match-pos) 'c-type
- 'c-not-decl))
- ;; We're inside an "ordinary" open brace.
- ((eq (char-before match-pos) ?{)
- (setq context (and toplev 'top)
- c-restricted-<>-arglists nil))
- ;; Inside an angle bracket arglist.
- ((or (eq type 'c-<>-arg-sep)
- (eq (char-before match-pos) ?<))
- (setq context '<>
- c-restricted-<>-arglists nil))
- ;; Got a cached hit in some other type of arglist.
- (type
- (setq context 'arglist
- c-restricted-<>-arglists t))
- ((if inside-macro
- (< match-pos max-type-decl-end-before-token)
- (< match-pos max-type-decl-end))
- ;; The point is within the range of a previously
- ;; encountered type decl expression, so the arglist
- ;; is probably one that contains declarations.
- ;; However, if `c-recognize-paren-inits' is set it
- ;; might also be an initializer arglist.
- (setq context 'decl
- c-restricted-<>-arglists nil)
- ;; The result of this check is cached with a char
- ;; property on the match token, so that we can look
- ;; it up again when refontifying single lines in a
- ;; multiline declaration.
- (c-put-char-property (1- match-pos)
- 'c-type 'c-decl-arg-start))
- ;; Got an open paren preceded by an arith operator.
- ((and (eq (char-before match-pos) ?\()
- (save-excursion
- (and (zerop (c-backward-token-2 2))
- (looking-at c-arithmetic-op-regexp))))
- (setq context nil
- c-restricted-<>-arglists nil))
- (t (setq context 'arglist
- c-restricted-<>-arglists t))))
+ (let ((got-context
+ (c-get-fontification-context
+ match-pos
+ (< match-pos (if inside-macro
+ max-type-decl-end-before-token
+ max-type-decl-end))
+ toplev)))
+ (setq context (car got-context)
+ c-restricted-<>-arglists (cdr got-context)))
;; Check we haven't missed a preceding "typedef".
(when (not (looking-at c-typedef-key))
diff -r 51f7a9ff5450 cc-mode.el
--- a/cc-mode.el Sat Feb 25 14:39:10 2017 +0000
+++ b/cc-mode.el Wed Mar 22 20:44:25 2017 +0000
@@ -1339,6 +1339,7 @@
;; This function is called indirectly from font locking stuff - either from
;; c-after-change (to prepare for after-change font-locking) or from font
;; lock context (etc.) fontification.
+ (goto-char pos)
(let ((lit-start (c-literal-start))
(new-pos pos)
capture-opener
diff -r 51f7a9ff5450 cc-vars.el
--- a/cc-vars.el Sat Feb 25 14:39:10 2017 +0000
+++ b/cc-vars.el Wed Mar 22 20:44:25 2017 +0000
@@ -1633,6 +1633,18 @@
:type 'c-extra-types-widget
:group 'c)
+(defcustom c-asymmetry-fontification-flag t
+ "Whether to fontify certain ambiguous constructs by white space asymmetry.
+
+In the fontification engine, it is sometimes impossible to determine
+whether a construct is a declaration or an expression. This happens
+particularly in C++, due to ambiguities in the language. When such a
+construct is like \"foo * bar\" or \"foo &bar\", and this variable is non-nil
+(the default), the construct will be fontified as a declaration if there is
+white space either before or after the operator, but not both."
+ :type 'boolean
+ :group 'c)
+
(defvar c-noise-macro-with-parens-name-re "\\<\\>")
(defvar c-noise-macro-name-re "\\<\\>")
--
Alan Mackenzie (Nuremberg, Germany).