CC Mode: Fontify cast types without adding them to c-found-types

* lisp/progmodes/cc-engine.el (c-forward-type): Test for the special new
value `just-one' of c-promote-possible-types, and if found, fontify the type,
but don't add it to c-found-types.
(c-forward-decl-or-cast-1): Add the new &optional parameter inside-macro.
Whilst checking for a cast construct, analyze the text following the closing
paren more rigorously.
Check for, and allow, the closing paren of a macro arglist before the putative
cast construct.

* lisp/progmodes/cc-fonts.el (c-font-lock-declarations): In the lambda
function, pass the parameter inside-macro to c-forward-decl-or-cast-1.

* lisp/progmodes/cc-langs.el (c-primary-expr-regexp-details): New
c-lang-defvar which calculates `c-primary-expr-regexp' and three match
numbers for various sub-expressions in the regexp.
(c-primary-expr-regexp): Now extracted from `c-primary-expr-regexp-details'.
(c-per-++---match, c-per-&*+--match, c-per-\(-match): New
c-lang-defconsts/vars extracted from `c-primary-expr-regexp-details'.
This commit is contained in:
Alan Mackenzie 2022-10-28 17:50:33 +00:00
parent d79cdcd4ff
commit 622724e95d
3 changed files with 209 additions and 78 deletions

View file

@ -8194,7 +8194,8 @@ multi-line strings (but not C++, for example)."
;; treat possible types (i.e. those that it normally returns 'maybe or
;; 'found for) as actual types (and always return 'found for them).
;; This means that it records them in `c-record-type-identifiers' if
;; that is set, and that it adds them to `c-found-types'.
;; that is set, and that if its value is t (not 'just-one), it adds
;; them to `c-found-types'.
(defvar c-promote-possible-types nil)
;; Dynamically bound variable that instructs `c-forward-<>-arglist' to
@ -9191,10 +9192,11 @@ multi-line strings (but not C++, for example)."
(goto-char id-end)
(if (or res c-promote-possible-types)
(progn
(c-add-type id-start (save-excursion
(goto-char id-end)
(c-backward-syntactic-ws)
(point)))
(when (not (eq c-promote-possible-types 'just-one))
(c-add-type id-start (save-excursion
(goto-char id-end)
(c-backward-syntactic-ws)
(point))))
(when (and c-record-type-identifiers id-range)
(c-record-type-id id-range))
(unless res
@ -10029,7 +10031,8 @@ This function might do hidden buffer changes."
;; This identifier is bound only in the inner let.
'(setq start id-start))))
(defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end)
(defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end
&optional inside-macro)
;; Move forward over a declaration or a cast if at the start of one.
;; The point is assumed to be at the start of some token. Nil is
;; returned if no declaration or cast is recognized, and the point
@ -10118,6 +10121,10 @@ This function might do hidden buffer changes."
;; matched. In that case it's used to discover chains of casts like
;; "(a) (b) c".
;;
;; INSIDE-MACRO is t when we definitely know we're inside a macro, nil
;; otherwise. We use it to disambiguate things like "(a) (b);", which is
;; likely a function call in a macro, but a cast outside of one.
;;
;; This function records identifier ranges on
;; `c-record-type-identifiers' and `c-record-ref-identifiers' if
;; `c-record-type-identifiers' is non-nil.
@ -11102,11 +11109,17 @@ This function might do hidden buffer changes."
;; Check if the expression begins with a prefix keyword.
(match-beginning 2)
(if (match-beginning 1)
;; Expression begins with an ambiguous operator. Treat
;; it as a cast if it's a type decl or if we've
;; recognized the type somewhere else.
(or at-decl-or-cast
(memq at-type '(t known found)))
;; Expression begins with an ambiguous operator.
(cond
((match-beginning c-per-&*+--match)
(memq at-type '(t known found)))
((match-beginning c-per-++---match)
t)
((match-beginning c-per-\(-match)
(or
(memq at-type '(t known found))
(not inside-macro)))
(t nil))
;; Unless it's a keyword, it's the beginning of a primary
;; expression.
(not (looking-at c-keywords-regexp)))))
@ -11132,18 +11145,33 @@ This function might do hidden buffer changes."
;; surrounding parens).
(looking-at c-simple-stmt-key)
(and
;; Check that it isn't a close paren (block close is ok,
;; though).
(not (memq (char-before) '(?\) ?\])))
;; Check that it isn't a close paren (block close , or a
;; macro arglist is ok, though).
(or
(not (memq (char-before) '(?\) ?\])))
;; Have we moved back to a macro arglist?
(and c-opt-cpp-prefix
(eq (char-before) ?\))
(save-excursion
(and
(c-go-list-backward)
(let (pos)
(c-backward-syntactic-ws)
(and (setq pos (c-on-identifier))
(goto-char pos)))
(zerop (c-backward-token-2 2))
(looking-at c-opt-cpp-macro-define-start)))))
;; Check that it isn't a nonsymbol identifier.
(not (c-on-identifier)))))))))
;; Handle the cast.
(when (and c-record-type-identifiers
at-type
(not (memq at-type '(t maybe)))) ; 'maybe isn't strong enough
; evidence to promote the type.
(let ((c-promote-possible-types t))
(not (eq at-type t)))
(let ((c-promote-possible-types (if (eq at-type 'maybe)
'just-one
t)))
(goto-char type-start)
(c-forward-type)))

View file

@ -1585,7 +1585,7 @@ casts and declarations are fontified. Used on level 2 and higher."
nil)
(setq decl-or-cast
(c-forward-decl-or-cast-1
match-pos context last-cast-end))
match-pos context last-cast-end inside-macro))
;; Ensure that c-<>-arg-sep c-type properties are in place on the
;; commas separating the arguments inside template/generic <..>s.

View file

@ -3489,6 +3489,150 @@ Note that Java specific rules are currently applied to tell this from
(c-lang-defvar c-regular-keywords-regexp
(c-lang-const c-regular-keywords-regexp))
(c-lang-defconst c-primary-expr-regexp-details
;; A list of c-primary-expr-regexp and three numbers identifying particular
;; matches in it.
t (let* ((prefix-ops
;All prefix ops
(c-filter-ops (c-lang-const c-operators)
'(prefix)
(lambda (op)
;; Filter out the special case prefix
;; operators that are close parens.
(not (string-match "\\s)" op)))))
(postfix-ops
;; All postfix ops.
(c-filter-ops (c-lang-const c-operators)
'(postfix)
(lambda (op) (not (string-match "\\s)" op)))))
(in-or-postfix-ops
;; All ops which are postfix, etc.
(c-filter-ops (c-lang-const c-operators)
'(postfix
postfix-if-paren
left-assoc
right-assoc
right-assoc-sequence)
t))
(nonkeyword-prefix-ops
;; All prefix ops apart from those which are keywords.
(c-filter-ops prefix-ops
t
"\\`\\(\\s.\\|\\s(\\|\\s)\\)+\\'"))
(nonkeyword-postfix-ops
;; All postfix ops apart from those which are keywords.
(c-filter-ops postfix-ops
t
"\\`\\(\\s.\\|\\s(\\|\\s)\\)+\\'"))
(cast-ops
;; All prefix ops which have syntax open-paren.
(c-filter-ops prefix-ops
t
"\\`\\s(\\'"))
(ambiguous-pre/postfix-ops
;; All non-keyword ops which are both prefix and postfix, apart
;; from (.
(c--set-difference (c--intersection nonkeyword-prefix-ops
nonkeyword-postfix-ops
:test 'string-equal)
cast-ops :test 'string-equal))
(unambiguous-prefix-ops
;; All non-keyword ops which are prefix ops and not any other type
;; of op.
(c--set-difference nonkeyword-prefix-ops
in-or-postfix-ops
:test 'string-equal))
(ambiguous-prefix-ops
;; All non-keyword ops which are prefix ops and also some other
;; type of op.
(c--intersection nonkeyword-prefix-ops
in-or-postfix-ops
:test 'string-equal)) ; This has everything we
; need, plus (, ++, --.
(ambiguous-prefix-non-postfix-ops
;; All non-keyword prefix ops which are also other types of ops
;; apart from postfix ops.
(c--set-difference (c--set-difference ambiguous-prefix-ops
ambiguous-pre/postfix-ops
:test 'string-equal)
cast-ops :test 'string-equal))
(primary-expression-keywords-string
;; Take out all symbol class operators from `prefix-ops' and make
;; the first submatch from them together with
;; `c-primary-expr-kwds'.
(c-make-keywords-re t
(append (c-lang-const c-primary-expr-kwds)
(c--set-difference prefix-ops nonkeyword-prefix-ops
:test 'string-equal))))
(primary-expression-keywords-string-depth
(regexp-opt-depth primary-expression-keywords-string))
(ambiguous-pre/postfix-string
(c-make-keywords-re nil ambiguous-pre/postfix-ops))
(ambiguous-pre/postfix-string-depth
(regexp-opt-depth ambiguous-pre/postfix-string))
(ambiguous-prefix-non-postfix-string
(c-make-keywords-re nil ambiguous-prefix-non-postfix-ops))
(ambiguous-prefix-non-postfix-string-depth
(regexp-opt-depth ambiguous-prefix-non-postfix-string))
(per-++---match (+ 2 primary-expression-keywords-string-depth))
(per-&*+--match (+ 1 per-++---match
ambiguous-pre/postfix-string-depth))
(per-\(-match (+ 1 per-&*+--match
ambiguous-prefix-non-postfix-string-depth)))
(list
(concat
"\\(" ; 1
primary-expression-keywords-string
"\\|"
;; Match all ambiguous operators.
"\\(" ; 2 + primary-expression-keywords-string-depth
ambiguous-pre/postfix-string
"\\)\\|\\(" ; 3 + primary-expression-keywords-string-depth
; + ambiguous-pre/postfix-string-depth
ambiguous-prefix-non-postfix-string
"\\)\\|"
"\\((\\)" ; 4 + primary-expression-keywords-string-depth
; + ambiguous-pre/postfix-string-depth
; + ambiguous-prefix-non-postfix-string-depth
"\\)"
"\\|"
;; Now match all other symbols.
(c-lang-const c-symbol-start)
"\\|"
;; The chars that can start integer and floating point
;; constants.
"\\.?[0-9]"
"\\|"
;; The unambiguous operators from `prefix-ops'.
(c-make-keywords-re nil
;; (c--set-difference nonkeyword-prefix-ops in-or-postfix-ops
;; :test 'string-equal)
unambiguous-prefix-ops
)
"\\|"
;; Match string and character literals.
"\\s\""
(if (memq 'gen-string-delim c-emacs-features)
"\\|\\s|"
""))
per-++---match
per-&*+--match
per-\(-match)))
(c-lang-defconst c-primary-expr-regexp
;; Regexp matching the start of any primary expression, i.e. any
;; literal, symbol, prefix operator, and '('. It doesn't need to
@ -3497,68 +3641,27 @@ Note that Java specific rules are currently applied to tell this from
;; matches then it is an ambiguous primary expression; it could also
;; be a match of e.g. an infix operator. (The case with ambiguous
;; keyword operators isn't handled.)
t (let* ((prefix-ops
(c-filter-ops (c-lang-const c-operators)
'(prefix)
(lambda (op)
;; Filter out the special case prefix
;; operators that are close parens.
(not (string-match "\\s)" op)))))
(nonkeyword-prefix-ops
(c-filter-ops prefix-ops
t
"\\`\\(\\s.\\|\\s(\\|\\s)\\)+\\'"))
(in-or-postfix-ops
(c-filter-ops (c-lang-const c-operators)
'(postfix
postfix-if-paren
left-assoc
right-assoc
right-assoc-sequence)
t)))
(concat
"\\("
;; Take out all symbol class operators from `prefix-ops' and make the
;; first submatch from them together with `c-primary-expr-kwds'.
(c-make-keywords-re t
(append (c-lang-const c-primary-expr-kwds)
(c--set-difference prefix-ops nonkeyword-prefix-ops
:test 'string-equal)))
"\\|"
;; Match all ambiguous operators.
(c-make-keywords-re nil
(c--intersection nonkeyword-prefix-ops in-or-postfix-ops
:test 'string-equal))
"\\)"
"\\|"
;; Now match all other symbols.
(c-lang-const c-symbol-start)
"\\|"
;; The chars that can start integer and floating point
;; constants.
"\\.?[0-9]"
"\\|"
;; The unambiguous operators from `prefix-ops'.
(c-make-keywords-re nil
(c--set-difference nonkeyword-prefix-ops in-or-postfix-ops
:test 'string-equal))
"\\|"
;; Match string and character literals.
"\\s\""
(if (memq 'gen-string-delim c-emacs-features)
"\\|\\s|"
""))))
t (car (c-lang-const c-primary-expr-regexp-details)))
(c-lang-defvar c-primary-expr-regexp (c-lang-const c-primary-expr-regexp))
(c-lang-defconst c-per-++---match
;; Match number for group in `c-primary-expr-regexp' which matches (in C)
;; the ++ and -- operators, and any similar ones in other languages.
t (cadr (c-lang-const c-primary-expr-regexp-details)))
(c-lang-defvar c-per-++---match (c-lang-const c-per-++---match))
(c-lang-defconst c-per-&*+--match
;; Match number for group in `c-primary-expr-regexp' which matches (in C)
;; the &, *, +, and - operators, and any similar ones in other languages.
t (car (cddr (c-lang-const c-primary-expr-regexp-details))))
(c-lang-defvar c-per-&*+--match (c-lang-const c-per-&*+--match))
(c-lang-defconst c-per-\(-match
;; Match number for group in `c-primary-expr-regexp' which matches (in C)
;; the ( operator, and any similar ones in other languages.
t (cadr (cddr (c-lang-const c-primary-expr-regexp-details))))
(c-lang-defvar c-per-\(-match (c-lang-const c-per-\(-match))
;;; Additional constants for parser-level constructs.