Subject: 29.0.92; Tree-Sitter/which-function Narrow/Widen causes modified buffer

From: Troy Brown <[email-masked]>
Date: Tue, 27 Jun 2023 22:23:52 -0400

This problem seems to manifest with multiple tree-sitter modes.  It
appears there is an interaction with which-function-mode and tree-sitter
which causes the buffer to be considered modified either after a narrow
or widen of the buffer.

To reproduce this, use a "hello_world.c" as follows:

--8<---------------cut here---------------start------------->8---
#include <stdio.h>

int main (void)
{
  printf("Hello, world!\n");
  return 0;
}
--8<---------------cut here---------------end--------------->8---

Running "emacs -Q" with the corresponding tree-sitter grammar library
installed.  Move into the main function and narrow-to-defun.  In some
modes, I've seen this cause the buffer to show as modified, however with
this example, it seems to occur after widening.

The following sequence of commands can be used to reproduce the issue:

C-x C-f ~/hello_world.c
M-x c-ts-mode
M-x which-function-mode
C-x n d
C-x n w

At this point, the modeline shows that the buffer is modified, and
running "M-: (buffer-modified-p)" indicates "t".  As previously
mentioned, this appears to only happen with tree-sitter modes when
which-function-mode is enabled in the buffer.

I then repeated the same but also triggered a backtrace on the first
change as follows:

M-: (add-to-list 'first-change-hook #'backtrace)

With that in place, the following is the generated traceback:

  backtrace()
  treesit--font-lock-notifier(((1 . 21)) #<treesit-parser for c>)
  treesit-buffer-root-node(c)
  treesit-node-at(68)
  treesit--things-around(68
"\\(?:class_specifier\\|enum_specifier\\|function_defi..."
c-ts-mode--defun-valid-p)
  treesit-thing-at-point(("\\(?:class_specifier\\|enum_specifier\\|function_defi..."
. c-ts-mode--defun-valid-p) top-level)
  treesit-defun-at-point()
  treesit-add-log-current-defun()
  c-ts-mode--emacs-current-defun-name()
  add-log-current-defun()
  which-function()
  which-func-update-1(#<window 3 on hello_world.c>)
  which-func-update()
  apply(which-func-update nil)
  timer-event-handler([t 0 0 500000 t which-func-update nil idle 0 nil])