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)

Source Code

;; Defined in /usr/src/emacs/lisp/progmodes/cc-engine.el.gz
;; Handling of large scale constructs like statements and declarations.

(defun c-forward-declarator (&optional limit accept-anon)
  ;; 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 ,).
  ;;
  ;; Return a list (ID-START ID-END BRACKETS-AFTER-ID GOT-INIT DECORATED),
  ;; where ID-START and ID-END are the bounds of the declarator's identifier,
  ;; and BRACKETS-AFTER-ID is non-nil if a [...] pair is present after the id.
  ;; 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)
    (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))
		   ((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 third 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))
			       (c-forward-name)
			       (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))
	     (save-excursion
	       (c-backward-syntactic-ws)
	       (setq id-end (point))))
	    (accept-anon
	     (setq id-start nil id-end nil)
	     t)
	    (t (/= (point) here))))

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

	 (<= (point) limit)

	 ;; Skip over any trailing bit, such as "__attribute__".
	 (progn
	      (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))))
	      (<= (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.
	 (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)
			   (setq found
				 (c-syntactic-re-search-forward
				  "[;:,]\\|\\s)\\|\\(=\\|\\s(\\)"
				  limit t t))
			   (eq (char-before) ?:)
			   (if (looking-at c-:-op-cont-regexp)
			       (progn (goto-char (match-end 0)) t)
			     (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))))))))
		      found)
		    (eq (char-before) ?\[)
		    (c-go-up-list-forward))
	     (setq brackets-after-id t))
	   (when found (backward-char))
	   (<= (point) limit)))
	(list id-start id-end brackets-after-id (match-beginning 1) decorated)

      (goto-char here)
      nil)))