Subject: bug#60769: CC Mode 5.35.2 (C/*l); More incorrect type recognition

From: Alan Mackenzie <[email-masked]>
Date: Wed, 18 Jan 2023 15:24:15 +0000

Hello, Po.

On Tue, Jan 17, 2023 at 13:16:22 +0800, Po Lu wrote:
> Alan Mackenzie <[email-masked]> writes:

> > Hello, Po.

> > On Fri, Jan 13, 2023 at 11:01:44 +0800, Po Lu via CC-Mode-help wrote:
> >> Package: cc-mode

> >> Here is another example of incorrect type recognition in C Mode as a
> >> result of a typo:

> >> static Lisp_Object
> >> frame_geometry (Lisp_Object frame, Lisp_Object attribute)
> >> {
> >>   struct frame *f = decode_live_frame (frame);
> >>   /**   XWindowAttributes atts; **/
> >>   Window rootw;
> >>   unsigned int ign, native_width, native_height, x_border_width = 0;
> >>   int x_native = 0, y_native = 0, xptr = 0, yptr = 0;
> >>   int left_off = 0, right_off = 0, top_off = 0, bottom_off = 0;
> >>   int outer_left, outer_top, outer_right, outer_bottom;
> >>   int native_left, native_top, native_right, native_bottom;
> >>   int inner_left, inner_top, inner_right, inner_bottom;
> >>   int internal_border_width;
> >>   bool menu_bar_external = false, tool_bar_external = false;
> >>   int menu_bar_height = 0, menu_bar_width = 0;
> >>   int tab_bar_height = 0, tab_bar_width = 0;
> >>   int tool_bar_height = 0, tool_bar_width = 0;

> >>   if (FRAME_INITIAL_P (f) || !FRAME_ANDROID_P (f)
> >>       || !FRAME_ANDROID_WINDOW (f))
> >>     return Qnil;

> >>   block_input ();
> >>   android_get_geometry (FRAME_ANDROID_WINDOW (f),
> >> 			&rootw, &x_native, &y_native,
> >> 			&native_width, &native_height, &x_border_width,
> >> 			&ign);
> >>   unblock_input ();
> >> }

> >> Place point after "android_get_geometry (", and accidentally type:

> >>   d

> >> (this was meant to be C-M-d.)

> >> Now, FRAME_ANDROID_WINDOW and android_get_geometry are stuck in
> >> c-found-types.

> > I'm afraid I can't reproduce this on either master or emacs-29.  Am I
> > correct in assuming that you mean insert the one single character "d"
> > after the "(" in that line?  Even when I additionally insert a space,
> > M-: (c-list-found-types) just lists "Window", which seems correct.

> Sorry for the confusion, Alan.  I meant to insert the character "d"
> immediately before "(".

Ah!  Yes, that's different.  ;-)

I can now reproduce the bug, and analysing it, it actually turned out to
be two distinct cases, one for android_get_geometry and the other for
FRAME_ANDROID_WINDOW.  I've fixed both of them with the now familiar
"unsafe-maybe" mechanism.

Would you please do the usual with the attached patch, and let me know if
anything is amiss.  In particular, if you notice any types which were
(correctly) fontified as types, but now no longer get fontified, please
tell me.  Thanks!

I look forward to hearing from you again.

-- 
Alan Mackenzie (Nuremberg, Germany).

> Thanks.
diff -r 17edbd3947aa cc-engine.el
--- a/cc-engine.el	Tue Jan 17 17:54:41 2023 +0000
+++ b/cc-engine.el	Wed Jan 18 15:15:25 2023 +0000
@@ -10495,6 +10495,8 @@
 	  got-prefix
 	  ;; True if the declarator is surrounded by a parenthesis pair.
 	  got-parens
+	  ;; True if there is a terminated argument list.
+	  got-arglist
 	  ;; True if there is an identifier in the declarator.
 	  got-identifier
 	  ;; True if we find a number where an identifier was expected.
@@ -10642,13 +10644,17 @@
 		(when (> paren-depth 0)
 		  (setq paren-depth (1- paren-depth))
 		  (forward-char)
+		  (when (and (not got-parens)
+			     (eq paren-depth 0))
+		    (setq got-arglist t))
 		  t)
-	      (when (if (save-match-data (looking-at "\\s("))
-			(c-safe (c-forward-sexp 1) t)
-		      (if (save-match-data
-			    (looking-at c-fun-name-substitute-key)) ; requires
-			  (c-forward-c++-requires-clause)
-			(goto-char (match-end 1))
+	      (when (cond
+		     ((save-match-data (looking-at "\\s("))
+		      (c-safe (c-forward-sexp 1) t))
+		     ((save-match-data
+			(looking-at c-fun-name-substitute-key))
+		      (c-forward-c++-requires-clause))
+		     (t (goto-char (match-end 1))
 			t))
 		(when (and (not got-suffix-after-parens)
 			   (= paren-depth 0))
@@ -10710,8 +10716,11 @@
 			     (goto-char pos)
 			     (setq pd (1- pd)))
 			   t)))
-		 (c-fdoc-shift-type-backward)
-		 t)))
+	      (c-fdoc-shift-type-backward)
+	      (when (and (not got-parens)
+			 (eq paren-depth 0))
+		(setq got-arglist t))
+	      t)))
 
 	(c-forward-syntactic-ws))
 
@@ -10779,6 +10788,9 @@
 			  (not (or got-prefix got-parens)))
 		 ;; Got another identifier directly after the type, so it's a
 		 ;; declaration.
+		 (when (and got-arglist
+			    (eq at-type 'maybe))
+		   (setq unsafe-maybe t))
 		 (throw 'at-decl-or-cast t))
 
 	       (when (and got-parens
@@ -11167,9 +11179,17 @@
 	 ;; inside an arglist that contains declarations.  Update (2017-09): We
 	 ;; now recognize a top-level "foo(bar);" as a declaration in C.
 	 ;; CASE 19
-	 (or (eq context 'decl)
-	     (and (c-major-mode-is 'c-mode)
-		  (or (eq context 'top) make-top))))))
+	 (when
+	     (or (eq context 'decl)
+		 (and (c-major-mode-is 'c-mode)
+		      (or (eq context 'top) make-top)))
+	   (when (and (eq at-type 'maybe)
+		      got-parens)
+	     ;; If we've got "foo d(bar () ...)", the d could be a typing
+	     ;; mistake, so we don't promote the 'maybe type "bar" to a 'found
+	     ;; type.
+	     (setq unsafe-maybe t))
+	   t))))
 
     ;; The point is now after the type decl expression.