Subject: 29.0.50; c-ts-mode cannot fontify after macros are encountered

From: Po Lu <[email-masked]>
Date: Tue, 22 Nov 2022 09:50:44 +0800

Insert the following code in a buffer, and enable c-ts-mode.

#define CheckExtension(name)				\
  if (!name)						\
    {							\
      if (display)					\
	eglTerminate (display);				\
      fprintf (stderr, "Missing: egl%s\n", #name + 1);	\
      return False;					\
    }

#define CheckExtensionGl(name)				\
  if (!name)						\
    {							\
      /* If the context remains current, then nothing	\
	 will get released upon eglTerminate.  */	\
      eglMakeCurrent (display, EGL_NO_SURFACE,		\
		      EGL_NO_SURFACE, EGL_NO_CONTEXT);	\
      eglTerminate (display);				\
      fprintf (stderr, "Missing: gl%s\n", #name + 1);	\
      return False;					\
    }

#define LoadProc(name, ext, extname)			\
  if (HaveEglExtension (extname))			\
    I##name						\
      = (void *) eglGetProcAddress ("egl" #name ext)

#define LoadProcGl(name, ext, extname)			\
  if (HaveGlExtension (extname))			\
    I##name						\
      = (void *) eglGetProcAddress ("gl" #name ext)

#define CheckGlExtension(name)			\
  if (!HaveGlExtension (name))			\
    {						\
      fprintf (stderr, "Missing %s\n", name);	\
						\
      eglMakeCurrent (display, EGL_NO_SURFACE,	\
		      EGL_NO_SURFACE,		\
		      EGL_NO_CONTEXT);		\
      eglTerminate (display);			\
      return False;				\
    }

There will be no fontification of types or string constants inside the
macro bodies.  CC Mode works fine.

Now, insert the following code below the macro definition:

static Visual *
FindVisual (VisualID visual, int *depth)
{
  XVisualInfo vinfo, *visuals;
  Visual *value;
  int nvisuals;
  const char *override;
}

visual, depth, visuals, value and override are not fontified as
identifiers.  Line feed characters below the macros are also fontfied as
"errors".

Within the following code:

static BufferActivityRecord *
FindBufferActivityRecord (PictureBuffer *buffer, PictureTarget *target)
{
  BufferActivityRecord *record;

  /* Look through the global activity list for a record matching
     the given values.  */
  record = all_activity.global_next;
  while (record != &all_activity)
    {
      if (record->buffer == buffer
	  && record->target == target)
	return record;

      record = record->global_next;
    }

  return NULL;
}

"record" is fontified as an identifier, but not within the condition in
the while loop.

Within the following code:

static void
compare_single_row_8bpc4 (unsigned char *data, unsigned char *xdata,
			  size_t size,
			  struct image_difference_statistics *statistics)
{
  unsigned char channel_a, channel_b;
  int diff;
  size_t i;

  for (i = 0; i < size; ++i)
    {
      channel_a = data[i];
      channel_b = xdata[i];

      diff = (int) channel_b - (int) channel_a;
      statistics->min_diff = MIN (statistics->min_diff,
				  diff);
      statistics->max_diff = MAX (statistics->max_diff,
				  diff);
    }
}

the "i" in "size_t i" is fontified as an identifier the first time, but
not in future appearances in the function.

Within src/xterm.c, every appearance of ATOM_REFS_INIT is fontified in
the error face.  Also, inside `xm_setup_dnd_targets',

  xm_targets_table_header header;
  xm_targets_table_rec **recs UNINIT;
  xm_byte_order byteorder;

"recs" is fontified in the error face.

	      recs = xmalloc (sizeof *recs);
	      recs[0] = xmalloc (FLEXSIZEOF (struct xm_targets_table_rec,
					     targets, ntargets * 4));

	      recs[0]->n_targets = ntargets;

"struct" is fontified in the error face.  Within
x_sync_note_frame_times:

#ifdef FRAME_DEBUG
  uint_fast64_t last_frame_ms = output->last_frame_time / 1000;
  fprintf (stderr,
	   "Drawing the last frame took: %"PRIuFAST64" ms (%"PRIuFAST64")\n",
	   last_frame_ms, time);
#endif

"PRIuFAST64" is fontified in the error face.  Within
x_dnd_begin_drag_and_drop:

	  if (x_dnd_movement_frame
	      /* FIXME: how come this can end up with movement frames
		 from other displays on GTK builds?  */
	      && (FRAME_X_DISPLAY (x_dnd_movement_frame)
		  == FRAME_X_DISPLAY (f))
	      /* If both those variables are false, then F is no
		 longer protected from deletion by Lisp code.  This
		 can only happen during the final iteration of the DND
		 event loop.  */
	      && (x_dnd_in_progress || x_dnd_waiting_for_finish))
	    {
	      XSETFRAME (frame_object, x_dnd_movement_frame);

is fontified incorrectly: the "if" is not fontified at all, and the last
three lines show up in the error faces.

In addition:

Lisp_Object
x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
			   Lisp_Object return_frame, Atom *ask_action_list,
			   const char **ask_action_names, size_t n_ask_actions,
			   bool allow_current_frame, Atom *target_atoms,
			   int ntargets, Lisp_Object selection_target_list,
			   bool follow_tooltip)

"Lisp_Object" and "x_dnd_begin_drag_and_drop" are not fontified at all.

Here:

/* Select for input extension events used by scroll bars.  This will
   result in the corresponding core events not being generated for
   SCROLL_BAR.  */

MAYBE_UNUSED static void
xi_select_scroll_bar_events (struct x_display_info *dpyinfo,
			     Window scroll_bar)

"void" is fontified in the error face.

Here, in handle_one_xevent:

#ifdef HAVE_XINPUT2
      if (event->type != GenericEvent)
#endif
	any = x_any_window_to_frame (dpyinfo, event->xany.window);
#ifdef HAVE_XINPUT2
      else
	any = NULL;
#endif

the "else" is fontified as a type.

static int
handle_one_xevent (struct x_display_info *dpyinfo,
#ifndef HAVE_XINPUT2
		   const XEvent *event,
#else
		   XEvent *event,
#endif
		   int *finish, struct input_event *hold_quit)

the "const XEvent *" is fontified in the error face.

Here:

    case GraphicsExpose:	/* This occurs when an XCopyArea's
                                   source area was obscured or not
                                   available.  */
      f = x_window_to_frame (dpyinfo, event->xgraphicsexpose.drawable);
      if (f)
        {
          expose_frame (f, event->xgraphicsexpose.x,
                        event->xgraphicsexpose.y,
                        event->xgraphicsexpose.width,
                        event->xgraphicsexpose.height);
#ifndef USE_TOOLKIT_SCROLL_BARS
	  x_scroll_bar_handle_exposure (f, (XEvent *) event);
#endif
#ifdef USE_GTK
	  x_clear_under_internal_border (f);
#endif
#ifdef HAVE_XDBE
	  show_back_buffer (f);
#endif
        }
#ifdef USE_X_TOOLKIT
      else
        goto OTHER;
#endif /* USE_X_TOOLKIT */
      break;

"goto OTHER" is fontified in the error face, and "else" as a type.

Here:

#ifdef HAVE_XINPUT2
	      if (event->xkey.time == pending_keystroke_time)
		{
		  source = xi_device_from_id (dpyinfo,
					      dpyinfo->pending_keystroke_source);

		  if (source)
		    inev.ie.device = source->name;
		}
#endif

"inev" is fontified in the error face.

Here:

#ifdef USE_GTK
      /* See comment in EnterNotify above */
      else if (dpyinfo->last_mouse_glyph_frame)
        x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame,
			       &event->xmotion, Qnil);
#endif

"else" and "dpyinfo" are fontified as types.

#ifdef USE_MOTIF
	    Widget widget;

	    widget = XtWindowToWidget (dpyinfo->display,
				       event->xbutton.window);

	    if (widget && XmIsCascadeButton (widget)
		&& XtIsSensitive (widget))
	      {
#endif
		if (!f->output_data.x->saved_menu_event)
		  f->output_data.x->saved_menu_event = xmalloc (sizeof *event);
		*f->output_data.x->saved_menu_event = *event;
		inev.ie.kind = MENU_BAR_ACTIVATE_EVENT;
		XSETFRAME (inev.ie.frame_or_window, f);
		*finish = X_EVENT_DROP;
#ifdef USE_MOTIF
	      }
#endif

here, the last closing brace is fontified in the error face.

Here:

static void NO_INLINE
x_error_quitter (Display *display, XErrorEvent *event)
{
  char buf[256], buf1[400 + INT_STRLEN_BOUND (int)
		      + INT_STRLEN_BOUND (unsigned long)];

"NO_INLINE" and "unsigned long" are fontified in the error face.

CC mode fontifies all of the examples above fine, and they are not even
pre-standard C.  Would someone please fix c-ts-mode to fontify them
correctly as well?

In GNU Emacs 29.0.50 (build 238, x86_64-pc-linux-gnu) of 2022-11-22
 built on trinity
Repository revision: aeadba1418d8fc18f17b4ae415cde35e9e272e7a
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101099
System Description: Fedora Linux 37 (Workstation Edition)

Configured using:
 'configure --with-x --with-x-toolkit=no --without-cairo
 --with-dumping=unexec --cache-file=/tmp/ccache'

Configured features:
ACL DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG JSON LCMS2
LIBSELINUX LIBSYSTEMD LIBXML2 MODULES NOTIFY INOTIFY OLDXMENU PNG RSVG
SECCOMP SOUND SQLITE3 THREADS TIFF TREE_SITTER UNEXEC WEBP X11 XDBE XFT
XIM XINPUT2 XPM ZLIB

Important settings:
  value of $LANG: en_GB.utf8
  value of $XMODIFIERS: @im=ibus
  locale-coding-system: utf-8-unix

Major mode: C/*l

Minor modes in effect:
  tooltip-mode: t
  global-eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  line-number-mode: t
  indent-tabs-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  abbrev-mode: t

Load-path shadows:
None found.

Features:
(shadow sort emacsbug mail-extr message sendmail mailcap yank-media puny
rfc822 mml mml-sec epa derived epg rfc6068 epg-config gnus-util
time-date mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047
rfc2045 mm-util ietf-drums mail-prsvr mailabbrev mail-utils gmm-utils
mailheader reporter find-dired ffap url-parse auth-source eieio
eieio-core cl-macs password-cache json subr-x map byte-opt gv bytecomp
byte-compile url-vars thingatpt files-x grep compile
text-property-search comint ansi-osc ansi-color ring c-ts-mode rx
treesit cl-seq vc-dispatcher vc-svn cc-mode cc-fonts cc-guess cc-menus
cc-cmds cc-styles cc-align cc-engine cc-vars cc-defs misearch
multi-isearch dired-aux cl-loaddefs cl-lib dired dired-loaddefs rmc
iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook
vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win
term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe
tabulated-list replace newcomment text-mode lisp-mode prog-mode register
page tab-bar menu-bar rfn-eshadow isearch easymenu timer select
scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors
frame minibuffer nadvice seq simple cl-generic indonesian philippine
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese composite emoji-zwj charscript
charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure
cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp
files window text-properties overlay sha1 md5 base64 format env
code-pages mule custom widget keymap hashtable-print-readable backquote
threads dbusbind inotify lcms2 dynamic-setting system-font-setting
font-render-setting xinput2 x multi-tty make-network-process emacs)

Memory information:
((conses 16 171735 10469)
 (symbols 48 26041 14)
 (strings 32 45784 1739)
 (string-bytes 1 1373049)
 (vectors 16 26115)
 (vector-slots 8 653341 15564)
 (floats 8 75 179)
 (intervals 56 3663 0)
 (buffers 992 18))