Function: c-forward-type

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

Signature

(c-forward-type &optional BRACE-BLOCK-TOO)

Source Code

;; Defined in /usr/src/emacs/lisp/progmodes/cc-engine.el.gz
(defun c-forward-type (&optional brace-block-too)
  ;; Move forward over a type spec if at the beginning of one,
  ;; stopping at the next following token.  The keyword "typedef"
  ;; isn't part of a type spec here.
  ;;
  ;; BRACE-BLOCK-TOO, when non-nil, means move over the brace block in
  ;; constructs like "struct foo {...} bar ;" or "struct {...} bar;".
  ;; The current (2009-03-10) intention is to convert all uses of
  ;; `c-forward-type' to call with this parameter set, then to
  ;; eliminate it.
  ;;
  ;; Return
  ;;   o - t if it's a known type that can't be a name or other
  ;;     expression;
  ;;   o - 'known if it's an otherwise known type (according to
  ;;     `*-font-lock-extra-types');
  ;;   o - 'prefix if it's a known prefix of a type;
  ;;   o - 'found if it's a type that matches one in `c-found-types';
  ;;   o - 'maybe if it's an identifier that might be a type;
  ;;   o - 'decltype if it's a decltype(variable) declaration; - or
  ;;   o - 'no-id if "auto" precluded parsing a type identifier.
  ;;   o -  nil if it can't be a type (the point isn't moved then).
  ;;
  ;; The point is assumed to be at the beginning of a token.
  ;;
  ;; Note that this function doesn't skip past the brace definition
  ;; that might be considered part of the type, e.g.
  ;; "enum {a, b, c} foo".
  ;;
  ;; This function records identifier ranges on
  ;; `c-record-type-identifiers' and `c-record-ref-identifiers' if
  ;; `c-record-type-identifiers' is non-nil.
  ;;
  ;; This function might do hidden buffer changes.
  (when (and c-recognize-<>-arglists
	     (looking-at "<"))
    (c-forward-<>-arglist t)
    (c-forward-syntactic-ws))

  (let ((start (point)) pos res name-res id-start id-end id-range)

    ;; Skip leading type modifiers.  If any are found we know it's a
    ;; prefix of a type.
    (when c-opt-type-modifier-prefix-key ; e.g. "const" "volatile", but NOT "typedef"
      (while (looking-at c-opt-type-modifier-prefix-key)
	(when (looking-at c-no-type-key)
	  (setq res 'no-id))
	(goto-char (match-end 1))
	(c-forward-syntactic-ws)
	(or (eq res 'no-id)
	    (setq res 'prefix))))

    (cond
     ((looking-at c-typeof-key) ; e.g. C++'s "decltype".
      (goto-char (match-end 1))
      (c-forward-syntactic-ws)
      (setq res (and (eq (char-after) ?\()
		     (c-safe (c-forward-sexp))
		     'decltype))
      (if res
	  (c-forward-syntactic-ws)
	(goto-char start)))

     ((looking-at c-type-prefix-key) ; e.g. "struct", "class", but NOT
				     ; "typedef".
      (goto-char (match-end 1))
      (c-forward-syntactic-ws)

      (while (cond
	      ((looking-at c-decl-hangon-key)
	       (c-forward-keyword-clause 1))
	      ((looking-at c-pack-key)
	       (goto-char (match-end 1))
	       (c-forward-syntactic-ws))
	      ((and c-opt-cpp-prefix
		    (looking-at c-noise-macro-with-parens-name-re))
	       (c-forward-noise-clause))))

      (setq pos (point))

      (setq name-res (c-forward-name))
      (setq res (not (null name-res)))
      (when (eq name-res t)
	;; In many languages the name can be used without the
	;; prefix, so we add it to `c-found-types'.
	(c-add-type pos (point))
	(when (and c-record-type-identifiers
		   c-last-identifier-range)
	  (c-record-type-id c-last-identifier-range)))
      (when (and brace-block-too
		 (memq res '(t nil))
		 (eq (char-after) ?\{)
		 (save-excursion
		   (c-safe
		     (progn (c-forward-sexp)
			    (c-forward-syntactic-ws)
			    (setq pos (point))))))
	(goto-char pos)
	(setq res t))
      (unless res (goto-char start)))	; invalid syntax

     ((and
       (not (eq res 'no-id))
       (progn
	 (setq pos nil)
	 (if (looking-at c-identifier-start)
	     (save-excursion
	       (setq id-start (point)
		     name-res (c-forward-name))
	       (when name-res
		 (setq id-end (point)
		       id-range c-last-identifier-range))))
	 (and (cond ((looking-at c-primitive-type-key)
		     (setq res t))
		    ((c-with-syntax-table c-identifier-syntax-table
		       (looking-at c-known-type-key))
		     (setq res 'known)))
	      (or (not id-end)
		  (>= (save-excursion
			(save-match-data
			  (goto-char (match-end 1))
			  (c-forward-syntactic-ws)
			  (setq pos (point))))
		      id-end)
		  (setq res nil)))))
      ;; Looking at a primitive or known type identifier.  We've
      ;; checked for a name first so that we don't go here if the
      ;; known type match only is a prefix of another name.

      (setq id-end (match-end 1))

      (when (and c-record-type-identifiers
		 (or c-promote-possible-types (eq res t)))
	(c-record-type-id (cons (match-beginning 1) (match-end 1))))

      (if (and c-opt-type-component-key
	       (save-match-data
		 (looking-at c-opt-type-component-key)))
	  ;; There might be more keywords for the type.
	  (let (safe-pos)
	    (c-forward-keyword-clause 1)
	    (while (progn
		     (setq safe-pos (point))
		     (looking-at c-opt-type-component-key))
	      (when (and c-record-type-identifiers
			 (looking-at c-primitive-type-key))
		(c-record-type-id (cons (match-beginning 1)
					(match-end 1))))
	      (c-forward-keyword-clause 1))
	    (if (looking-at c-primitive-type-key)
		(progn
		  (when c-record-type-identifiers
		    (c-record-type-id (cons (match-beginning 1)
					    (match-end 1))))
		  (c-forward-keyword-clause 1)
		  (setq res t))
	      (goto-char safe-pos)
	      (setq res 'prefix)))
	(unless (save-match-data (c-forward-keyword-clause 1))
	  (if pos
	      (goto-char pos)
	    (goto-char (match-end 1))
	    (c-forward-syntactic-ws)))))

     (name-res
      (cond ((eq name-res t)
	     ;; A normal identifier.
	     (goto-char id-end)
	     (if (or res c-promote-possible-types)
		 (progn
		   (c-add-type id-start id-end)
		   (when (and c-record-type-identifiers id-range)
		     (c-record-type-id id-range))
		   (unless res
		     (setq res 'found)))
	       (setq res (if (c-check-qualified-type id-start)
			     ;; It's an identifier that has been used as
			     ;; a type somewhere else.
			     'found
			   ;; It's an identifier that might be a type.
			   'maybe))))
	    ((eq name-res 'template)
	     ;; A template is sometimes a type.
	     (goto-char id-end)
	     (c-forward-syntactic-ws)
	     (setq res
		   (if (eq (char-after) ?\()
		       (if (c-check-qualified-type id-start)
			   ;; It's an identifier that has been used as
			   ;; a type somewhere else.
			   'found
			 ;; It's an identifier that might be a type.
			 'maybe)
		     t)))
	    (t
	     ;; Otherwise it's an operator identifier, which is not a type.
	     (goto-char start)
	     (setq res nil)))))

    (when (not (memq res '(nil no-id)))
      ;; Skip trailing type modifiers.  If any are found we know it's
      ;; a type.
      (when c-opt-type-modifier-key
	(while (looking-at c-opt-type-modifier-key) ; e.g. "const", "volatile"
	  (goto-char (match-end 1))
	  (c-forward-syntactic-ws)
	  (setq res t)))

      ;; Step over any type suffix operator.  Do not let the existence
      ;; of these alter the classification of the found type, since
      ;; these operators typically are allowed in normal expressions
      ;; too.
      (when c-opt-type-suffix-key	; e.g. "..."
	(while (looking-at c-opt-type-suffix-key)
	  (goto-char (match-end 1))
	  (c-forward-syntactic-ws)))

      ;; Skip any "WS" identifiers (e.g. "final" or "override" in C++)
      (while (looking-at c-type-decl-suffix-ws-ids-key)
	(goto-char (match-end 1))
	(c-forward-syntactic-ws)
	(setq res t))

      (when c-opt-type-concat-key	; Only/mainly for pike.
	;; Look for a trailing operator that concatenates the type
	;; with a following one, and if so step past that one through
	;; a recursive call.  Note that we don't record concatenated
	;; types in `c-found-types' - it's the component types that
	;; are recorded when appropriate.
	(setq pos (point))
	(let* ((c-promote-possible-types (or (memq res '(t known))
					     c-promote-possible-types))
	       ;; If we can't promote then set `c-record-found-types' so that
	       ;; we can merge in the types from the second part afterwards if
	       ;; it turns out to be a known type there.
	       (c-record-found-types (and c-record-type-identifiers
					  (not c-promote-possible-types)))
	       subres)
	  (if (and (looking-at c-opt-type-concat-key)

		   (progn
		     (goto-char (match-end 1))
		     (c-forward-syntactic-ws)
		     (setq subres (c-forward-type))))

	      (progn
		;; If either operand certainly is a type then both are, but we
		;; don't let the existence of the operator itself promote two
		;; uncertain types to a certain one.
		(cond ((eq res t))
		      ((eq subres t)
		       (unless (eq name-res 'template)
			 (c-add-type id-start id-end))
		       (when (and c-record-type-identifiers id-range)
			 (c-record-type-id id-range))
		       (setq res t))
		      ((eq res 'known))
		      ((eq subres 'known)
		       (setq res 'known))
		      ((eq res 'found))
		      ((eq subres 'found)
		       (setq res 'found))
		      (t
		       (setq res 'maybe)))

		(when (and (eq res t)
			   (consp c-record-found-types))
		  ;; Merge in the ranges of any types found by the second
		  ;; `c-forward-type'.
		  (setq c-record-type-identifiers
			;; `nconc' doesn't mind that the tail of
			;; `c-record-found-types' is t.
			(nconc c-record-found-types
			       c-record-type-identifiers))))

	    (goto-char pos))))

      (when (and c-record-found-types (memq res '(known found)) id-range)
	(setq c-record-found-types
	      (cons id-range c-record-found-types))))

    ;;(message "c-forward-type %s -> %s: %s" start (point) res)

    res))