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 STOP-AT-END)
Source Code
;; Defined in /usr/src/emacs/lisp/progmodes/cc-engine.el.gz
(defun c-forward-type (&optional brace-block-too stop-at-end)
;; Move forward over a type spec if at the beginning of one,
;; stopping at the next following token (if STOP-AT-END is nil) or
;; at the end of the type spec (otherwise). 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 (C or C++)
;; or the type int was implicit (C).
;; 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
post-prefix-pos prefix-end-pos equals-makes-type)
;; Skip leading type modifiers. If any are found we know it's a
;; prefix of a type.
(catch 'type-error
(when c-maybe-typeless-specifier-re
(while (looking-at c-maybe-typeless-specifier-re)
(save-match-data
(when (looking-at c-no-type-key)
(setq res 'no-id))
(when (looking-at c-no-type-with-equals-key)
(setq equals-makes-type t)))
(if (c-forward-align-clause-throw-if-invalid 'type-error)
(setq prefix-end-pos pos)
(goto-char (match-end 1))
(setq prefix-end-pos (point))
(setq pos (point))
(c-forward-syntactic-ws)
(or (eq res 'no-id)
(setq res 'prefix)))))
(setq post-prefix-pos (point))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(cond
((looking-at c-typeof-key) ; e.g. C++'s "decltype".
(goto-char (match-end 1))
(setq pos (point))
(c-forward-syntactic-ws)
(setq res (and (eq (char-after) ?\()
(c-safe (c-forward-sexp))
'decltype))
(if res
(progn
(setq pos (point))
(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))
(setq pos (point))
(c-forward-syntactic-ws)
(while (cond
((looking-at c-decl-hangon-key)
(c-forward-keyword-clause 1 t)
(setq pos (point))
(c-forward-syntactic-ws))
((looking-at c-pack-key)
(goto-char (match-end 1))
(setq pos (point))
(c-forward-syntactic-ws))
((and c-opt-cpp-prefix
(looking-at c-noise-macro-with-parens-name-re))
(c-forward-noise-clause t)
(setq pos (point))
(c-forward-syntactic-ws))))
(setq id-start (point))
(setq name-res (c-forward-name t))
(setq pos (point))
(setq res (not (null name-res)))
(when (eq name-res t)
;; With some keywords the name can be used without the prefix, so we
;; add the name to `c-found-types' when this is the case.
(when (save-excursion
(goto-char post-prefix-pos)
(looking-at c-self-contained-typename-key))
(c-add-type id-start
(point)))
(when (and c-record-type-identifiers
c-last-identifier-range)
(c-record-type-id c-last-identifier-range)))
(c-forward-syntactic-ws)
(when (and brace-block-too
(memq res '(t nil))
(eq (char-after) ?\{)
(save-excursion
(c-safe
(progn (c-forward-sexp)
(setq pos (point))))))
(goto-char pos)
(c-forward-syntactic-ws)
(setq res t))
(unless res (goto-char start))) ; invalid syntax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
((looking-at c-type-with-paren-key) ; C's "_BitInt".
(goto-char (match-end 1))
(c-forward-syntactic-ws)
(if (and (eq (char-after) ?\()
(c-go-list-forward nil (min (+ (point) 500) (point-max)))
(eq (char-before) ?\)))
(progn
(setq pos (point))
(c-forward-syntactic-ws)
(setq res t))
(goto-char start)
(setq res nil))) ; invalid syntax.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
((and
(not (eq res 'no-id))
(not (and equals-makes-type
(save-excursion
(and (zerop (c-forward-token-2))
(looking-at "=\\([^=]\\|$\\)")))
(setq res 'no-id)))
(progn
(setq pos nil)
(while (and c-opt-cpp-prefix
(looking-at c-noise-macro-with-parens-name-re))
(c-forward-noise-clause))
(if (looking-at c-identifier-start)
(save-excursion
(setq id-start (point)
name-res (c-forward-name t))
(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))
(setq pos (point))
(c-forward-syntactic-ws)
pos))
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))))
(cond
((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 t)
(while (progn
(setq safe-pos (point))
(c-forward-syntactic-ws)
(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))))
(or (c-forward-align-clause-throw-if-invalid 'type-error)
(c-forward-keyword-clause 1 t)))
(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 t)
(setq res t)
(while (progn
(setq safe-pos (point))
(c-forward-syntactic-ws)
(looking-at c-opt-type-component-key))
(c-forward-keyword-clause 1 t)))
(goto-char safe-pos)
(setq res 'prefix))
(setq pos (point))))
((save-match-data (c-forward-keyword-clause 1 t))
(while (progn
(setq pos (point))
(c-forward-syntactic-ws)
(and c-opt-type-component-key
(looking-at c-opt-type-component-key)))
(or (c-forward-align-clause-throw-if-invalid 'type-error)
(c-forward-keyword-clause 1 t))))
(pos (goto-char pos))
(t (goto-char (match-end 1))
(setq pos (point))))
(c-forward-syntactic-ws))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
((and (eq name-res t)
(eq res 'prefix)
(c-major-mode-is 'c-mode)
(save-excursion
(goto-char id-end)
(setq pos (point))
(c-forward-syntactic-ws)
(and (not (looking-at c-symbol-start))
(or
(not (looking-at c-type-decl-prefix-key))
(and (eq (char-after) ?\()
(not (save-excursion
(c-forward-declarator))))))))
;; A C specifier followed by an implicit int, e.g.
;; "register count;"
(goto-char prefix-end-pos)
(setq pos (point))
(unless stop-at-end
(c-forward-syntactic-ws))
(setq res 'no-id))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(name-res
(cond ((eq name-res t)
;; A normal identifier.
(goto-char id-end)
(setq pos (point))
(c-forward-syntactic-ws)
(if (or res c-promote-possible-types)
(progn
(when (not (eq c-promote-possible-types 'just-one))
(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))
(when (eq res 'prefix)
(setq res t)))
(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)
(setq pos (point))
(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))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
((eq res 'prefix)
;; Deal with "extern "C" foo_t my_foo;"
(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"
(unless (c-forward-align-clause-throw-if-invalid 'type-error)
(goto-char (match-end 1))
(setq pos (point))
(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))
(setq pos (point))
(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))
(setq pos (point))
(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 nil t))
(setq pos (point))))
(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))
;; Cause the confirmed types to get fontified.
(let ((cur c-record-found-types))
(while (consp (car-safe cur))
(c-fontify-new-found-type
(buffer-substring-no-properties (caar cur) (cdar cur)))
(setq cur (cdr cur))))
;; 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)
(unless stop-at-end
(c-forward-syntactic-ws))
(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))