Subject: bug#25623: CC Mode 5.32.99 (C/l); `c-defun-name' returns wrong result for filescope enums, structs and unions

From: Alan Mackenzie <[email-masked]>
Date: Sun, 23 Apr 2017 21:01:56 +0000

Hello, Mohammed.

Thanks for the fast reply.

On Mon, Apr 24, 2017 at 00:00:07 +0530, Mohammed Sadiq wrote:
> Hi,

> > On April 23, 2017 at 5:48 PM Alan Mackenzie <[email-masked]> wrote:
> > Thanks for the bug report.  This bug is simply a matter of buggy code in
> > CC Mode.  There follows a patch.

> > Would you please apply this patch, compile cc-cmds.el, try it out, then
> > either confirm to me that the bug is fixed, or tell me what still needs
> > looking at.  Thanks in advance!
> > [code snipped]

> Hi. I have a few test cases that this fails (not quiet bad, but may be better not 
> to break)

> enum
>   {
>    A,
>    B,|
>    C,
>   };

> gives 'nil', which would better return 'enum' as it is common to have enums without
> names associated.

I've thought about this.  The problem is that "enum" is not a name - it
is a keyword.

> int a[] = {'h', 'e', 'l', 'l', 'o', '\0'|};

> gives "[" which I believe, should actually return 'nil' when defined at file scope.

It should indeed return nil.  Please see the amended patch (below).

> typedef struct
> {
>   int a;
>   int b;|
> } nice;

> returns "nice". It may be better to return "struct nice" as in "struct nice {...};" definition.

I considered that, too.  Even returning "nice" is a bit bogus, here.  For
example, if we had "typedef struct { ... } nice, easy;" why should we
return "nice" (which we do) rather than "easy"?  I think here, strictly
speaking, we should return nil, since "nice" is an identifier _after_ the
main type definition, not part of it.  But, then again, maybe here is not
the place to be strict.  ;-)

I think returning "struct nice" would be totally wrong, here.  That is
not the name of the struct, the way it is in "struct nice { ... }".

Here's the amended patch:

diff -r f78dfc813575 cc-cmds.el
--- a/cc-cmds.el	Sat Apr 22 14:18:55 2017 +0000
+++ b/cc-cmds.el	Sun Apr 23 20:38:14 2017 +0000
@@ -1769,19 +1769,25 @@
 	  (unless (eq where 'at-header)
 	    (c-backward-to-nth-BOF-{ 1 where)
 	    (c-beginning-of-decl-1))
+	  (when (looking-at c-typedef-key)
+	    (goto-char (match-end 0))
+	    (c-forward-syntactic-ws))
 
 	  ;; Pick out the defun name, according to the type of defun.
 	  (cond
 	   ;; struct, union, enum, or similar:
-	   ((and (looking-at c-type-prefix-key)
-		 (progn (c-forward-token-2 2) ; over "struct foo "
-			(or (eq (char-after) ?\{)
-			    (looking-at c-symbol-key)))) ; "struct foo bar ..."
-	    (save-match-data (c-forward-token-2))
-	    (when (eq (char-after) ?\{)
-	      (c-backward-token-2)
-	      (looking-at c-symbol-key))
-	    (match-string-no-properties 0))
+	   ((looking-at c-type-prefix-key)
+	    (let ((key-pos (point)))
+	      (c-forward-token-2 1)	; over "struct ".
+	      (cond
+	       ((looking-at c-symbol-key)	; "struct foo { ..."
+		(buffer-substring-no-properties key-pos (match-end 0)))
+	       ((eq (char-after) ?{)	; "struct { ... } foo"
+		(when (c-go-list-forward)
+		  (c-forward-syntactic-ws)
+		  (when (looking-at c-symbol-key) ; a bit bogus - there might
+						  ; be several identifiers.
+		    (match-string-no-properties 0)))))))
 
 	   ((looking-at "DEFUN\\s-*(") ;"DEFUN\\_>") think of XEmacs!
 	    ;; DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory, ...) ==> Ffile_name_directory
@@ -1808,7 +1814,8 @@
 		(c-backward-syntactic-ws))
 	      (setq name-end (point))
 	      (c-backward-token-2)
-	      (buffer-substring-no-properties (point) name-end)))))))))
+	      (and (looking-at c-symbol-start)
+		   (buffer-substring-no-properties (point) name-end))))))))))
 
 (defun c-declaration-limits (near)
   ;; Return a cons of the beginning and end positions of the current

> Thanks
 
-- 
Alan Mackenzie (Nuremberg, Germany).