how-many is an interactive and byte-compiled function defined in
replace.el.gz.

Signature
(how-many REGEXP &optional RSTART REND INTERACTIVE)

Documentation
Print and return number of matches for REGEXP following point.

When called from Lisp and INTERACTIVE is omitted or nil, just return
the number, do not print it; if INTERACTIVE is t, the function behaves
in all respects as if it had been called interactively.

If REGEXP contains upper case characters (excluding those preceded by \)
and search-upper-case is non-nil, the matching is case-sensitive.

Second and third arg RSTART and REND specify the region to operate on.

Interactively, in Transient Mark mode when the mark is active, operate
on the contents of the region.  Otherwise, operate from point to the
end of (the accessible portion of) the buffer.

This function starts looking for the next match from the end of
the previous match.  Hence, it ignores matches that overlap
a previously found match.

View in manual

Key Bindings
embark-become-match-map c

References
how-many is unused in replace.el.gz.

Find all references Functions used by how-many

Debugging
Enable edebug Enable tracing
Disassemble Forget

Aliases
count-matches

Source Code
;; Defined in /usr/share/emacs/29.4/lisp/replace.el.gz
(defun how-many (regexp &optional rstart rend interactive)
  "Print and return number of matches for REGEXP following point.
When called from Lisp and INTERACTIVE is omitted or nil, just return
the number, do not print it; if INTERACTIVE is t, the function behaves
in all respects as if it had been called interactively.

If REGEXP contains upper case characters (excluding those preceded by `\\')
and `search-upper-case' is non-nil, the matching is case-sensitive.

Second and third arg RSTART and REND specify the region to operate on.

Interactively, in Transient Mark mode when the mark is active, operate
on the contents of the region.  Otherwise, operate from point to the
end of (the accessible portion of) the buffer.

This function starts looking for the next match from the end of
the previous match.  Hence, it ignores matches that overlap
a previously found match."
  (interactive
   (keep-lines-read-args "How many matches for regexp"))
  (save-excursion
    (if rstart
        (if rend
            (progn
              (goto-char (min rstart rend))
              (setq rend (max rstart rend)))
          (goto-char rstart)
          (setq rend (point-max)))
      (if (and interactive (use-region-p))
	  (setq rstart (region-beginning)
		rend (region-end))
	(setq rstart (point)
	      rend (point-max)))
      (goto-char rstart))
    (let ((count 0)
	  (case-fold-search
	   (if (and case-fold-search search-upper-case)
	       (isearch-no-upper-case-p regexp t)
	     case-fold-search)))
      (while (and (< (point) rend)
		  (re-search-forward regexp rend t))
        ;; Ensure forward progress on zero-length matches like "^$".
        (when (and (= (match-beginning 0) (match-end 0))
                   (not (eobp)))
          (forward-char 1))
	(setq count (1+ count)))
      (when interactive (message (ngettext "%d occurrence"
					   "%d occurrences"
					   count)
				 count))
      count)))

Symbol Properties
event-symbol-element-mask
  (how-many 0)
event-symbol-elements
  (how-many)
modifier-cache
  ((0 . how-many))