Function: c-forward-declarator

c-forward-declarator is a byte-compiled function defined in cc-engine.el.gz.

Signature

(c-forward-declarator &optional LIMIT ACCEPT-ANON NOT-TOP)

Source Code

;; Defined in /usr/src/emacs/lisp/progmodes/cc-engine.el.gz
(defun c-forward-declarator (&optional limit accept-anon not-top)
  ;; Assuming point is at the start of a declarator, move forward over it,
  ;; leaving point at the next token after it (e.g. a ) or a ; or a ,), or at
  ;; LIMIT (or end of buffer) if that comes first.
  ;;
  ;; Return a list (ID-START ID-END BRACKETS-AFTER-ID GOT-INIT DECORATED
  ;; ARGLIST), where ID-START and ID-END are the bounds of the declarator's
  ;; identifier, BRACKETS-AFTER-ID is non-nil if a [...] pair is present after
  ;; the id, and ARGLIST is non-nil either when an arglist has been moved
  ;; over, or when we have stopped at an unbalanced open-paren.  GOT-INIT is
  ;; non-nil when the declarator is followed by "=" or "(", DECORATED is
  ;; non-nil when the identifier is embellished by an operator, like "*x", or
  ;; "(*x)".
  ;;
  ;; If ACCEPT-ANON is non-nil, move forward over any "anonymous declarator",
  ;; i.e. something like the (*) in int (*), such as might be found in a
  ;; declaration.  In such a case ID-START and ID-END in the return value are
  ;; both set to nil.  A "null" "anonymous declarator" gives a non-nil result.
  ;;
  ;; If no declarator is found, leave point unmoved and return nil.  LIMIT is
  ;; an optional limit for forward searching.
  ;;
  ;; Note that the global variable `c-last-identifier-range' is written to, so
  ;; the caller should bind it if necessary.

  ;; Inside the following "condition form", we move forward over the
  ;; declarator's identifier up as far as any opening bracket (for array
  ;; size) or paren (for parameters of function-type) or brace (for
  ;; array/struct initialization) or "=" or terminating delimiter
  ;; (e.g. "," or ";" or "}").
  (let ((here (point))
	id-start id-end brackets-after-id paren-depth decorated
	got-init arglist double-double-quote pos)
    (or limit (setq limit (point-max)))
    (if	(and
	 (< (point) limit)

	 ;; The following form moves forward over the declarator's
	 ;; identifier (and what precedes it), returning t.  If there
	 ;; wasn't one, it returns nil.
	 (let (got-identifier)
	   (setq paren-depth 0)
	   ;; Skip over type decl prefix operators, one for each iteration
	   ;; of the while.  These are, e.g. "*" in "int *foo" or "(" and
	   ;; "*" in "int (*foo) (void)" (Note similar code in
	   ;; `c-forward-decl-or-cast-1'.)
	   (while
	       (cond
		((looking-at c-decl-hangon-key)
		 (c-forward-keyword-clause 1))
		((and c-opt-cpp-prefix
		      (looking-at c-noise-macro-with-parens-name-re))
		 (c-forward-noise-clause))
		;; Special handling for operator<op>.
		((and c-opt-op-identifier-prefix
		      (looking-at c-opt-op-identifier-prefix))
		 (goto-char (match-end 1))
		 (c-forward-syntactic-ws limit)
		 (setq id-start (point))
		 (if (looking-at c-overloadable-operators-regexp)
		     (progn
		       (when (and (c-major-mode-is 'c++-mode)
				  (eq (char-after) ?\")
				  (eq (char-after (1+ (point))) ?\"))
			 (setq double-double-quote t))
		       (goto-char (match-end 0))
		       (setq pos (point))
		       (c-forward-syntactic-ws limit)
		       (setq got-identifier t)
		       nil)
		   t))
		((and (looking-at c-type-decl-prefix-key)
		      (if (and (c-major-mode-is 'c++-mode)
			       (match-beginning 4)) ; Was 3 - 2021-01-01
			  ;; If the fourth submatch matches in C++ then
			  ;; we're looking at an identifier that's a
			  ;; prefix only if it specifies a member pointer.
			  (progn
			    (setq id-start (point))
			    (when (c-forward-name t)
			      (setq pos (point))
			      (c-forward-syntactic-ws limit)

			      (if (save-match-data
				    (looking-at "\\(::\\)"))
				  ;; We only check for a trailing "::" and
				  ;; let the "*" that should follow be
				  ;; matched in the next round.
				  t
				;; It turned out to be the real identifier,
				;; so flag that and stop.
				(setq got-identifier t)
				nil)))
			t))
		 (if (save-match-data
		       (looking-at c-type-decl-operator-prefix-key))
		     (setq decorated t))
		 (if (eq (char-after) ?\()
		     (progn
		       (setq paren-depth (1+ paren-depth))
		       (forward-char))
		   (goto-char (or (match-end 1)
				  (match-end 2))))
		 (c-forward-syntactic-ws)
		 t)))

	   ;; If we haven't passed the identifier already, do it now.
	   (unless got-identifier
	     (setq id-start (point)))
	   (cond
	    ((or got-identifier
		 (c-forward-name t))
	     (setq id-end
		   (or pos
		       (point)))
	     (c-forward-syntactic-ws limit)
	     t)
	    (accept-anon
	     (setq id-start nil id-end nil)
	     t)
	    (t nil)))

	 (progn
	   (c-forward-syntactic-ws limit)
	   (when (and double-double-quote	; C++'s operator"" _tag
		      (c-on-identifier))
	     (c-forward-token-2 1 nil limit))
	   t)

	 ;; Skip out of the parens surrounding the identifier.  If closing
	 ;; parens are missing, this form returns nil.
	 (or (= paren-depth 0)
	     (prog1
		 (c-safe (goto-char (scan-lists (point) 1 paren-depth)))
	       (c-forward-syntactic-ws)))

	 ;; Skip over any trailing bit, such as "__attribute__".
	 (progn
	   (while (cond
		   ((looking-at c-decl-hangon-key)
		    (c-forward-keyword-clause 1))
		   ((looking-at c-type-decl-suffix-key)
		    (cond
		     ((save-match-data
			(looking-at c-requires-clause-key))
		      (c-forward-c++-requires-clause))
		     ((eq (char-after) ?\()
		      (if (c-forward-decl-arglist not-top decorated limit)
			  (progn (setq arglist t
				       got-init nil)
				 t)
			(if (c-go-list-forward (point) limit)
			    t
			  (setq arglist t) ; For unbalanced (.
			  nil)))
		     (t (c-forward-keyword-clause 1))))
		   ((and c-opt-cpp-prefix
			 (looking-at c-noise-macro-with-parens-name-re))
		    (c-forward-noise-clause))))
	   (<= (point) limit))

	 ;; Search syntactically to the end of the declarator (";",
	 ;; ",", a closing paren, eob etc) or to the beginning of an
	 ;; initializer or function prototype ("=" or "\\s(").
	 ;; Note that square brackets are now not also treated as
	 ;; initializers, since this broke when there were also
	 ;; initializing brace lists.
	 (or (eq (char-after) ?\()	; Not an arglist.
	     (let (found)
	       (while
		   (and (< (point) limit)
			(progn
			  ;; In the next loop, we keep searching forward
			  ;; whilst we find ":"s which aren't single colons
			  ;; inside C++ "for" statements.
			  (while
			      (and
			       (< (point) limit)
			       (prog1
				   (setq found
					 (c-syntactic-re-search-forward
					  ;; Consider making the next regexp a
					  ;; c-lang-defvar (2023-07-04).
					  (if (c-major-mode-is 'objc-mode)
					      "\\(?:@end\\)\\|[;:,]\\|\\(=\\|[[(]\\)"
					    "[;:,]\\|\\(=\\|\\s(\\)")
					  limit 'limit t))
				 (setq got-init
				       (and found (match-beginning 1))))
			       (eq (char-before) ?:)
                               (not
				(and (c-major-mode-is '(c++-mode java-mode))
                                     (save-excursion
                                       (and
					(c-go-up-list-backward)
					(eq (char-after) ?\()
					(progn (c-backward-syntactic-ws)
                                               (c-simple-skip-symbol-backward))
					(looking-at c-paren-stmt-key)))))
			       (if (looking-at c-:-op-cont-regexp)
				   (progn (goto-char (match-end 0)) t)
				 ;; Does this : introduce the class
				 ;; initialization list, or a bitfield?
				 (not arglist)))) ; Carry on for a bitfield
			  found)
			(when (eq (char-before) ?\[)
			  (setq brackets-after-id t)
			  (prog1 (c-go-up-list-forward)
			    (c-forward-syntactic-ws)))))
	       (when (and found
			  (memq (char-before) '(?\; ?\: ?, ?= ?\( ?\[ ?{)))
		 (backward-char))
	       (<= (point) limit))))
	(list id-start id-end brackets-after-id got-init decorated arglist)

      (goto-char here)
      nil)))