Subject: Re: bug#63328: CC Mode 5.35.2 (Java//l); Constructor function not fontified as such

From: Alan Mackenzie <[email-masked]>
Date: Fri, 26 May 2023 10:14:04 +0000

Hello, Po.

On Fri, May 12, 2023 at 10:42:21 +0800, Po Lu wrote:
> Alan Mackenzie <[email-masked]> writes:

[ .... ]

> > To fix this reuired some tweaking of the low level syntactic analysis
> > code.  Could I ask you, please, to test the enclosed patch (which should
> > apply cleanly to either master or the emacs-29 branch).  Then please let
> > me know how the test went.

> It seems to work, but perhaps it would be safer to change that code only
> in Java mode, and not in the rest of the CC modes?

Sorry it's taken me so long.  I wasn't really happy with that last patch
I sent you - it slowed Java Mode's fontification by around 15%, because
it was testing every function call for being a constructor.  I've settled
on a scheme where the code checks for an argument list and the opening
brace of the statement block before fontifying as a constructor.  So, on
typing a new constructor, the fontification gets delayed until the brace
gets typed.  This isn't ideal, though I think it's better than the 15%
slowdown.

After consideration, I think it's better to leave the check in for all
modes, not just Java Mode.  I don't think there's any valid syntax in any
CC Mode mode which could accidentally trigger the mechanism, and the
problem with the lack of fontification might well occur in some derived
mode, too.

Anyhow, I have attached a patch, so would you please test it on your real
code and let me know how well it works.  Thanks!

-- 
Alan Mackenzie (Nuremberg, Germany).

diff -r 3d663572d4bf cc-engine.el
--- a/cc-engine.el	Wed May 03 09:45:37 2023 +0000
+++ b/cc-engine.el	Fri May 26 09:54:22 2023 +0000
@@ -10646,6 +10646,10 @@
 	  got-parens
 	  ;; True if there is a terminated argument list.
 	  got-arglist
+	  ;; True when `got-arglist' and the token after the end of the
+	  ;; arglist is an opening brace.  Used only when we have a
+	  ;; suspected typeless function name.
+	  got-stmt-block
 	  ;; True if there is an identifier in the declarator.
 	  got-identifier
 	  ;; True if we find a number where an identifier was expected.
@@ -10798,6 +10802,10 @@
 		    (setq got-arglist t))
 		  t)
 	      (when (cond
+		      ((and (eq (char-after) ?\()
+			    (c-safe (c-forward-sexp 1) t))
+		       (when (eq (char-before) ?\))
+			 (setq got-arglist t)))
 		     ((save-match-data (looking-at "\\s("))
 		      (c-safe (c-forward-sexp 1) t))
 		     ((save-match-data
@@ -10812,6 +10820,11 @@
 		  (setq got-suffix-after-parens (match-beginning 0)))
 		(setq got-suffix t))))
 
+	   ((and got-arglist
+		 (eq (char-after) ?{))
+	    (setq got-stmt-block t)
+	    nil)
+
 	   (t
 	    ;; No suffix matched.  We might have matched the
 	    ;; identifier as a type and the open paren of a
@@ -10880,9 +10893,17 @@
 		     (not (memq context '(arglist decl))))
 		 (or (and new-style-auto
 			  (looking-at c-auto-ops-re))
-		     (and (or maybe-typeless backup-maybe-typeless)
-			  (not got-prefix)
-			  at-type)))
+		     (and (not got-prefix)
+			  at-type
+			  (or maybe-typeless backup-maybe-typeless
+			      ;; Do we have a (typeless) constructor?
+			      (and got-stmt-block
+				   (save-excursion
+				     (goto-char type-start)
+				     (and
+				      (looking-at c-identifier-key)
+				      (c-directly-in-class-called-p
+				       (match-string 0)))))))))
 	;; Have found no identifier but `c-typeless-decl-kwds' has
 	;; matched so we know we're inside a declaration.  The
 	;; preceding type must be the identifier instead.
@@ -12561,7 +12582,8 @@
 		   (looking-at c-class-key))
 	  (goto-char (match-end 1))
 	  (c-forward-syntactic-ws)
-	  (looking-at name))))))
+	  (and (looking-at c-identifier-key)
+	       (string= (match-string 0) name)))))))
 
 (defun c-search-uplist-for-classkey (paren-state)
   ;; Check if the closest containing paren sexp is a declaration