Subject: Re: bug#58772: CC Mode 5.35.1 (C/*l); CC Mode fails to fontify source_y in Fx_translate_coordinates

From: Alan Mackenzie <[email-masked]>
Date: Fri, 28 Oct 2022 19:54:08 +0000

Hello again, Po.

On Tue, Oct 25, 2022 at 18:37:10 +0800, Po Lu via CC-Mode-help wrote:
> Package: cc-mode

> Go to src/xfns.c in the Emacs 29 source code.  Somewhere around line
> 7935, there will be the following function definition:

> DEFUN ("x-translate-coordinates", Fx_translate_coordinates,
>        Sx_translate_coordinates,
>        1, 5, 0, doc: /* Translate coordinates from FRAME.
> Translate the given coordinates SOURCE-X and SOURCE-Y from
> SOURCE-WINDOW's coordinate space to that of DEST-WINDOW, on FRAME.

> If SOURCE-X and SOURCE-Y are nil, use 0 instead.

> FRAME can either be a terminal or a frame.  If nil, it defaults to the
> selected frame.  SOURCE-WINDOW must be an X window ID, 0 (which means
> to use the root window), or nil, which means to use FRAME's inner
> window.  DEST-WINDOW must be another X window ID, or nil (which means
> to use the root window).

> Return a list of (X Y CHILD) if the given coordinates are on the same
> screen, or nil otherwise, where X and Y are the coordinates in
> DEST-WINDOW's coordinate space, and CHILD is the window ID of any
> mapped child in DEST-WINDOW at those coordinates, or nil if there is
> no such window.  */)
>   (Lisp_Object frame, Lisp_Object source_window,
>    Lisp_Object dest_window, Lisp_Object source_x,
>    Lisp_Object source_y)
> {

> In that function definition, "Lisp_Object source_y" is not fontified.
> This did not happen in Emacs 28.

This was an unintended consequence of some recent changes.  Sorry.

I can't explain in any reasonable way what was wrong, but I think the
attached patch should fix it.  Would you please do the usual with the
patch, and let me know whether or not the bug really is fixed, and
whether anything else untoward is caused by it.  Thanks!

> Emacs  : GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu)
>  of 2022-10-17
> Package: CC Mode 5.35.1 (C/*l)
> Buffer Style: GNU
> c-emacs-features: (pps-extended-state col-0-paren posix-char-classes gen-string-delim gen-comment-delim syntax-properties category-properties 1-bit)

[ .... ]

-- 
Alan Mackenzie (Nuremberg, Germany).

diff -r ebb9daec71c9 cc-fonts.el
--- a/cc-fonts.el	Fri Oct 28 17:11:41 2022 +0000
+++ b/cc-fonts.el	Fri Oct 28 19:49:21 2022 +0000
@@ -1221,134 +1221,145 @@
 		    (c-backward-syntactic-ws)
 		    (eq (char-before) ?\()))))
       (c-get-fontification-context (point) not-front-decl toplev))
-	  ((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)
-		  (cond
-		   ((looking-at c-paren-stmt-key)
-		    ;; Allow comma separated <> arglists in for statements.
-		    (cons nil nil))
-		   ((or (looking-at c-block-stmt-2-key)
-			(looking-at c-block-stmt-1-2-key)
-			(looking-at c-typeof-key))
-		    (cons nil t))
-		   (t nil)))))
-	  ;; 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) ?{)
-		(c-inside-bracelist-p (1- match-pos)
-				      (cdr (c-parse-state))
-				      nil))
-	   (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))
-	  ;; We're at a C++ uniform initialization.
-	  ((and (c-major-mode-is 'c++-mode)
-		(eq (char-before match-pos) ?\()
-		(save-excursion
-		  (goto-char match-pos)
-		  (and
-		   (zerop (c-backward-token-2 2))
-		   (looking-at c-identifier-start)
-		   (c-got-face-at (point)
-				  '(font-lock-variable-name-face)))))
-	   (cons 'not-decl nil))
-	  ((and not-front-decl
+     ((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)
+	     (cond
+	      ((looking-at c-paren-stmt-key)
+	       ;; Allow comma separated <> arglists in for statements.
+	       (cons nil nil))
+	      ((or (looking-at c-block-stmt-2-key)
+		   (looking-at c-block-stmt-1-2-key)
+		   (looking-at c-typeof-key))
+	       (cons nil t))
+	      (t nil)))))
+     ;; 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) ?{)
+	   (c-inside-bracelist-p (1- match-pos)
+				 (cdr (c-parse-state))
+				 nil))
+      (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))
+     ;; We're at a C++ uniform initialization.
+     ((and (c-major-mode-is 'c++-mode)
+	   (eq (char-before match-pos) ?\()
+	   (save-excursion
+	     (goto-char match-pos)
+	     (and
+	      (zerop (c-backward-token-2 2))
+	      (looking-at c-identifier-start)
+	      (c-got-face-at (point)
+			     '(font-lock-variable-name-face)))))
+      (cons 'not-decl nil))
+     ((and 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.
-		(or (not c-recognize-paren-inits)
-		    (save-excursion
-		      (goto-char match-pos)
-		      (not (c-back-over-member-initializers)))))
-	   ;; 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(s) preceded by an arith operator.
-	  ((and (eq (char-before match-pos) ?\()
-		(save-excursion
-		  (goto-char match-pos)
-		  (while
-		      (and (zerop (c-backward-token-2))
-			   (eq (char-after) ?\()))
-		  (looking-at c-arithmetic-op-regexp)))
-	   (cons nil nil))
-	  ;; In a C++ member initialization list.
-	  ((and (eq (char-before match-pos) ?,)
-	  	(c-major-mode-is 'c++-mode)
-	  	(save-excursion
-		  (goto-char match-pos)
-		  (c-back-over-member-initializers)))
-	   (c-put-char-property (1- match-pos) 'c-type 'c-not-decl)
-	   (cons 'not-decl nil))
-	  ;; At start of a declaration inside a declaration paren.
-	  ((save-excursion
+	   (or (not c-recognize-paren-inits)
+	       (save-excursion
+		 (goto-char match-pos)
+		 (not (c-back-over-member-initializers)))))
+      ;; 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(s) preceded by an arith operator.
+     ((and (eq (char-before match-pos) ?\()
+	   (save-excursion
+	     (goto-char match-pos)
+	     (while
+		 (and (zerop (c-backward-token-2))
+		      (eq (char-after) ?\()))
+	     (looking-at c-arithmetic-op-regexp)))
+      (cons nil nil))
+     ;; In a C++ member initialization list.
+     ((and (eq (char-before match-pos) ?,)
+	   (c-major-mode-is 'c++-mode)
+	   (save-excursion
 	     (goto-char match-pos)
-	     (and (memq (char-before match-pos) '(?\( ?\,))
-		  (c-go-up-list-backward match-pos
-					  ; c-determine-limit is too slow, here.
-					 (max (- (point) 2000) (point-min)))
-		  (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)
-			 (or
-			  (and
-		           (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))))))
-			  (and (zerop (c-backward-token-2))
-			       (looking-at c-fun-name-substitute-key))))))))
-	   (cons 'decl nil))
-	  (t (cons 'arglist t)))))
+	     (c-back-over-member-initializers)))
+      (c-put-char-property (1- match-pos) 'c-type 'c-not-decl)
+      (cons 'not-decl nil))
+     ;; At start of a declaration inside a declaration paren.
+     ((save-excursion
+	(goto-char match-pos)
+	(and (memq (char-before match-pos) '(?\( ?\,))
+	     (c-go-up-list-backward match-pos
+					; c-determine-limit is too slow, here.
+				    (max (- (point) 2000) (point-min)))
+	     (eq (char-after) ?\()
+	     (let ((type (c-get-char-property (point) 'c-type)))
+	       (or (memq type '(c-decl-arg-start c-decl-type-start))
+		   (progn
+		     (c-backward-syntactic-ws)
+		     (cond
+		      ((and toplev
+			    (eq (char-before) ?\)))
+		       (save-excursion
+			 (and (c-go-list-backward nil (max (- (point) 2000)
+							   (point-min)))
+			      (eq (char-after) ?\()
+			      (progn (c-backward-syntactic-ws)
+				     (c-back-over-compound-identifier)))))
+		      ((save-excursion
+			 (and
+			  (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))))))))
+		      ((and (zerop (c-backward-token-2))
+			    (looking-at c-fun-name-substitute-key)))))))))
+      ;; Cache the result of this test for next time around.
+      (c-put-char-property (1- match-pos) 'c-type 'c-decl-arg-start)
+      (cons 'decl nil))
+     (t (cons 'arglist t)))))
 
 (defun c-font-lock-single-decl (limit decl-or-cast match-pos context toplev)
   ;; Try to fontify a single declaration, together with all its declarators.