]> git.eshelyaron.com Git - emacs.git/commitdiff
CC Mode: Refactor c-forward-delarator and callers
authorAlan Mackenzie <acm@muc.de>
Thu, 29 Sep 2022 15:22:42 +0000 (15:22 +0000)
committerAlan Mackenzie <acm@muc.de>
Thu, 29 Sep 2022 15:22:42 +0000 (15:22 +0000)
c-forward-declarator now moves over a complete declarator, including any
arglist expression, but possibly not including certain C++20 constructs.

* lisp/progmodes/cc-engine.el (c-forward-decl-arglist): New function,
extracted from c-do-declarators.
(c-forward-declarator): Extend the result list by one element, denoting
whether the function parsed an argument list.  Insert special handling for a
C++ operator<op> construct.  If there is a parenthesis expression, and it is
an argument list, move forward over it.
(c-do-declarators): Append an optional parameter, cdd-anon-accepted
instructing the function to handle declarators without identifiers.  Extract
c-forward-decl-arglist.

* lisp/progmodes/cc-fonts.el (c-font-lock-declarators): New &optional
parameter accept-anon, as above.  Analyze and use the identifier location
returned by c-do-declarators, rather than using c-last-identifier-range.
(c-font-lock-single-decl): Determine accept-anon from the context, passing it
as argument to c-font-lock-declarators.

* lisp/progmodes/cc-langs.el (c-opt-identifier-prefix-key): Make a
c-lang-defvar out of this existing c-lang-defconst.

* lisp/progmodes/cc-mode.el (c-fl-decl-end): Adapt for the new
c-forward-declarator which now moves over arglists.  Amend better to handle
certain syntactically invalid constructs in C++.

lisp/progmodes/cc-engine.el
lisp/progmodes/cc-fonts.el
lisp/progmodes/cc-langs.el
lisp/progmodes/cc-mode.el

index e0aef2b2ee6c4c41a406089dff6553e4166002c9..fc00518360488c1529439954522d8093985572e4 100644 (file)
@@ -9590,14 +9590,71 @@ point unchanged and return nil."
       (goto-char here)
       nil)))
 
-(defun c-forward-declarator (&optional limit accept-anon)
+(defun c-forward-decl-arglist (not-top id-in-parens &optional limit)
+  ;; Point is at an open parenthesis, assumed to be the arglist of a function
+  ;; declaration.  Move over this arglist and following syntactic whitespace,
+  ;; and return non-nil.  If the construct isn't such an arglist, leave point
+  ;; unmoved and return nil.
+  ;;
+  ;; Note that point is assumed to be at a place where an arglist is expected.
+  ;; Only for C++, where there are other possibilities, is any actual
+  ;; processing done.  Otherwise, t is simply returned.
+  (let ((here (point)) got-type)
+    (if        (or
+        (not (c-major-mode-is 'c++-mode))
+        (and
+         (or (not not-top)
+             id-in-parens              ; Id is in parens, etc.
+             (save-excursion
+               (forward-char)
+               (c-forward-syntactic-ws limit)
+               (looking-at "[*&]")))
+         (when
+             (save-excursion
+               (let (c-last-identifier-range)
+                 (forward-char)
+                 (c-forward-syntactic-ws limit)
+                 (catch 'is-function
+                   (while
+                       ;; Go forward one argument at each iteration.
+                       (progn
+                         (while
+                             (cond
+                              ((looking-at c-decl-hangon-key)
+                               (c-forward-keyword-clause 1))
+                              ((looking-at
+                                c-noise-macro-with-parens-name-re)
+                               (c-forward-noise-clause))))
+                         (when (eq (char-after) ?\))
+                           (forward-char)
+                           (c-forward-syntactic-ws limit)
+                           (throw 'is-function t))
+                         (setq got-type (c-forward-type))
+                         (cond
+                          ((null got-type)
+                           (throw 'is-function nil))
+                          ((not (eq got-type 'maybe))
+                           (throw 'is-function t)))
+                         (c-forward-declarator limit t t)
+                         (eq (char-after) ?,))
+                     (forward-char)
+                     (c-forward-syntactic-ws))
+                   t)))
+           (and (c-go-list-forward (point) limit)
+                (progn (c-forward-syntactic-ws limit) t)))))
+       t
+      (goto-char here)
+      nil)))
+
+(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
   ;; end of buffer if there is no such token.
   ;;
-  ;; 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.
+  ;; 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 if an arglist has been moved over.
   ;; 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)".
@@ -9619,7 +9676,8 @@ point unchanged and return nil."
   ;; array/struct initialization) or "=" or terminating delimiter
   ;; (e.g. "," or ";" or "}").
   (let ((here (point))
-       id-start id-end brackets-after-id paren-depth decorated)
+       id-start id-end brackets-after-id paren-depth decorated
+       got-init arglist)
     (or limit (setq limit (point-max)))
     (if        (and
         (< (point) limit)
@@ -9640,6 +9698,18 @@ point unchanged and return nil."
                ((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
+                      (goto-char (match-end 0))
+                      (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
@@ -9648,17 +9718,17 @@ point unchanged and return nil."
                          ;; 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))
+                           (when (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))
@@ -9684,7 +9754,7 @@ point unchanged and return nil."
            (accept-anon
             (setq id-start nil id-end nil)
             t)
-           (t (/= (point) here))))
+           (t nil)))
 
         ;; Skip out of the parens surrounding the identifier.  If closing
         ;; parens are missing, this form returns nil.
@@ -9725,10 +9795,13 @@ point unchanged and return nil."
                      (while
                          (and
                           (< (point) limit)
-                          (setq found
-                                (c-syntactic-re-search-forward
-                                 "[;:,]\\|\\s)\\|\\(=\\|\\s(\\)"
-                                 limit t t))
+                          (prog1
+                              (setq found
+                                    (c-syntactic-re-search-forward
+                                     "[;:,]\\|\\s)\\|\\(=\\|\\s(\\)"
+                                     limit t t))
+                            (setq got-init
+                                  (and found (match-beginning 1))))
                           (eq (char-before) ?:)
                           (if (looking-at c-:-op-cont-regexp)
                               (progn (goto-char (match-end 0)) t)
@@ -9742,18 +9815,30 @@ point unchanged and return nil."
                                             (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))
+                   (cond ((eq (char-before) ?\[)
+                          (setq brackets-after-id t)
+                          (prog1 (c-go-up-list-forward)
+                            (c-forward-syntactic-ws)))
+                         ((and (not brackets-after-id)
+                               (eq (char-before) ?\())
+                          (backward-char)
+                          (if (c-forward-decl-arglist not-top decorated limit)
+                              (setq arglist t
+                                    got-init nil)
+                            (forward-char))
+                          nil))))      ; To end the loop.
+          (when (and found
+                     (memq (char-before) '(?\; ?\: ?, ?= ?\( ?\[ ?{)))
+              (backward-char))
           (<= (point) limit)))
-       (list id-start id-end brackets-after-id (match-beginning 1) decorated)
+       (list id-start id-end brackets-after-id got-init decorated arglist)
 
       (goto-char here)
       nil)))
 
 (defun c-do-declarators
-    (cdd-limit cdd-list cdd-not-top cdd-comma-prop cdd-function)
+    (cdd-limit cdd-list cdd-not-top cdd-comma-prop cdd-function
+              &optional cdd-accept-anon)
   "Assuming point is at the start of a comma separated list of declarators,
 apply CDD-FUNCTION to each declarator (when CDD-LIST is non-nil) or just the
 first declarator (when CDD-LIST is nil).  When CDD-FUNCTION is nil, no
@@ -9778,6 +9863,9 @@ Stop at or before CDD-LIMIT (which may NOT be nil).
 If CDD-NOT-TOP is non-nil, we are not at the top-level (\"top-level\" includes
 being directly inside a class or namespace, etc.).
 
+If CDD-ACCEPT-ANON is non-nil, we also process declarators without names,
+e.g. \"int (*)(int)\" in a function prototype.
+
 Return non-nil if we've reached the token after the last declarator (often a
 semicolon, or a comma when CDD-LIST is nil); otherwise (when we hit CDD-LIMIT,
 or fail otherwise) return nil, leaving point at the beginning of the putative
@@ -9789,67 +9877,25 @@ This function might do hidden buffer changes."
   ;; CDD-FUNCTION.
   (let
       ((cdd-pos (point)) cdd-next-pos cdd-id-start cdd-id-end
-       cdd-decl-res cdd-got-func cdd-got-type cdd-got-init
+       cdd-decl-res cdd-got-func cdd-got-init
        c-last-identifier-range cdd-exhausted cdd-after-block)
 
     ;; The following `while' applies `cdd-function' to a single declarator id
     ;; each time round.  It loops only when CDD-LIST is non-nil.
     (while
        (and (not cdd-exhausted)
-            (setq cdd-decl-res (c-forward-declarator cdd-limit)))
+            (setq cdd-decl-res (c-forward-declarator
+                                cdd-limit cdd-accept-anon cdd-not-top)))
+
       (setq cdd-next-pos (point)
            cdd-id-start (car cdd-decl-res)
            cdd-id-end (cadr cdd-decl-res)
-           cdd-got-func (and (eq (char-after) ?\()
-                         (or (not (c-major-mode-is 'c++-mode))
-                             (not cdd-not-top)
-                             (car (cddr (cddr cdd-decl-res))) ; Id is in
-                                       ; parens, etc.
-                             (save-excursion
-                               (forward-char)
-                               (c-forward-syntactic-ws)
-                               (looking-at "[*&]")))
-                         (not (car (cddr cdd-decl-res)))
-                         (or (not (c-major-mode-is 'c++-mode))
-                             (save-excursion
-                               (let (c-last-identifier-range)
-                                 (forward-char)
-                                 (c-forward-syntactic-ws)
-                                 (catch 'is-function
-                                   (while
-                                       (progn
-                                         (while
-                                             (cond
-                                              ((looking-at c-decl-hangon-key)
-                                               (c-forward-keyword-clause 1))
-                                              ((looking-at c-noise-macro-with-parens-name-re)
-                                               (c-forward-noise-clause))))
-                                         (if (eq (char-after) ?\))
-                                             (throw 'is-function t))
-                                         (setq cdd-got-type (c-forward-type))
-                                         (cond
-                                          ((null cdd-got-type)
-                                           (throw 'is-function nil))
-                                          ((not (eq cdd-got-type 'maybe))
-                                           (throw 'is-function t)))
-                                         (c-forward-declarator nil t)
-                                         (eq (char-after) ?,))
-                                     (forward-char)
-                                     (c-forward-syntactic-ws))
-                                   t)))))
-           cdd-got-init (and (cadr (cddr cdd-decl-res))
-                         (char-after)))
+           cdd-got-func (cadr (cddr (cddr cdd-decl-res)))
+           cdd-got-init (and (cadr (cddr cdd-decl-res)) (char-after)))
 
       ;; Jump past any initializer or function prototype to see if
       ;; there's a ',' to continue at.
-      (cond (cdd-got-func
-            ;; Skip a parenthesized initializer (C++) or a function
-            ;; prototype.
-            (if (c-go-list-forward (point) cdd-limit) ; over the parameter list.
-                (c-forward-syntactic-ws cdd-limit)
-              (setq cdd-exhausted t))) ; unbalanced parens
-
-           (cdd-got-init               ; "=" sign OR opening "(", "[", or "("
+      (cond (cdd-got-init              ; "=" sign OR opening "(", "[", or "("
             ;; Skip an initializer expression in braces, whether or not (in
             ;; C++ Mode) preceded by an "=".  Be careful that the brace list
             ;; isn't a code block or a struct (etc.) block.
@@ -9872,8 +9918,9 @@ This function might do hidden buffer changes."
            (t (c-forward-syntactic-ws cdd-limit)))
 
       (if cdd-function
-         (funcall cdd-function cdd-id-start cdd-id-end cdd-next-pos
-                  cdd-not-top cdd-got-func cdd-got-init))
+         (save-excursion
+           (funcall cdd-function cdd-id-start cdd-id-end cdd-next-pos
+                    cdd-not-top cdd-got-func cdd-got-init)))
 
       ;; If a ',' is found we set cdd-pos to the next declarator and iterate.
       (if (and cdd-list (< (point) cdd-limit) (looking-at ","))
index d2af53e837c37ef8db72d9bf58f1849262ea0126..8f930c5437704433296fb9d3faaae8ac8379f35d 100644 (file)
@@ -1092,7 +1092,7 @@ casts and declarations are fontified.  Used on level 2 and higher."
   nil)
 
 (defun c-font-lock-declarators (limit list types not-top
-                                     &optional template-class)
+                                     &optional template-class accept-anon)
   ;; Assuming the point is at the start of a declarator in a declaration,
   ;; fontify the identifier it declares.  (If TYPES is t, it does this via the
   ;; macro `c-fontify-types-and-refs'.)
@@ -1112,6 +1112,8 @@ casts and declarations are fontified.  Used on level 2 and higher."
   ;; a default (introduced by "="), it will be fontified as a type.
   ;; E.g. "<class X = Y>".
   ;;
+  ;; ACCEPT-ANON is non-nil when we accept anonymous declarators.
+  ;;
   ;; Nil is always returned.  The function leaves point at the delimiter after
   ;; the last declarator it processes.
   ;;
@@ -1124,37 +1126,35 @@ casts and declarations are fontified.  Used on level 2 and higher."
      limit list not-top
      (cond ((eq types t) 'c-decl-type-start)
           ((null types) 'c-decl-id-start))
-     (lambda (id-start _id-end end-pos _not-top is-function init-char)
+     (lambda (id-start id-end end-pos _not-top is-function init-char)
        (if (eq types t)
-          ;; Register and fontify the identifier as a type.
-          (let ((c-promote-possible-types t))
-            (goto-char id-start)
-            (c-forward-type))
-        ;; The following doesn't work properly (yet, 2018-09-22).
-        ;; (c-put-font-lock-face id-start id-end
-        ;;                    (if is-function
-        ;;                        'font-lock-function-name-face
-        ;;                      'font-lock-variable-name-face))
-        (when (and c-last-identifier-range
-                   (not (get-text-property (car c-last-identifier-range)
-                                           'face)))
-          ;; We use `c-last-identifier-range' rather than `id-start' and
-          ;; `id-end', since the latter two can be erroneous.  E.g. in
-          ;; "~Foo", `id-start' is at the tilde.  This is a bug in
-          ;; `c-forward-declarator'.
-          (c-put-font-lock-face (car c-last-identifier-range)
-                                (cdr c-last-identifier-range)
-                                (cond
-                                 ((not (memq types '(nil t))) types)
-                                 (is-function 'font-lock-function-name-face)
-                                 (t 'font-lock-variable-name-face)))))
+          (when id-start
+            ;; Register and fontify the identifier as a type.
+            (let ((c-promote-possible-types t))
+              (goto-char id-start)
+              (c-forward-type)))
+        (when id-start
+          (goto-char id-start)
+          (when c-opt-identifier-prefix-key
+            (unless (and (looking-at c-opt-identifier-prefix-key) ; For operator~
+                         (eq (match-end 1) id-end))
+              (while (and (< (point) id-end)
+                          (re-search-forward c-opt-identifier-prefix-key id-end t))
+                (c-forward-syntactic-ws limit))))
+          (when (not (get-text-property (point) 'face))
+            (c-put-font-lock-face (point) id-end
+                                  (cond
+                                   ((not (memq types '(nil t))) types)
+                                   (is-function 'font-lock-function-name-face)
+                                   (t 'font-lock-variable-name-face))))))
        (and template-class
            (eq init-char ?=)           ; C++ "<class X = Y>"?
            (progn
              (goto-char end-pos)
              (c-forward-token-2 1 nil limit) ; Over "="
              (let ((c-promote-possible-types t))
-               (c-forward-type t))))))
+               (c-forward-type t)))))
+     accept-anon)                      ; Last argument to c-do-declarators.
     nil))
 
 (defun c-get-fontification-context (match-pos not-front-decl &optional toplev)
@@ -1384,9 +1384,12 @@ casts and declarations are fontified.  Used on level 2 and higher."
                                     'c-decl-type-start
                                   'c-decl-id-start)))))
       (c-font-lock-declarators
-       (min limit (point-max)) decl-list
+       (min limit (point-max))
+       decl-list
        (not (null (cadr decl-or-cast)))
-       (not toplev) template-class))
+       (not toplev)
+       template-class
+       (memq context '(decl <>))))
 
     ;; A declaration has been successfully identified, so do all the
     ;; fontification of types and refs that've been recorded.
index 85f43d6a26b797ff99e4cbfead09ac516ac3b666..3b008fd6dc7d4da613a06c5b5b505e38f6a0cb81 100644 (file)
@@ -934,6 +934,8 @@ This value is by default merged into `c-operators'."
                             t)))
       (when ops
        (c-make-keywords-re 'appendable ops))))
+(c-lang-defvar c-opt-identifier-prefix-key
+              (c-lang-const c-opt-identifier-prefix-key))
 
 (c-lang-defconst c-after-id-concat-ops
   "Operators that can occur after a binary operator on `c-identifier-ops'
index 9dd5ddb465621edec864c26eeaab08abb0b8ede6..732b2b10549c4531f25fca7357c7d61eba76a1fc 100644 (file)
@@ -2471,38 +2471,43 @@ with // and /*, not more generic line and block comments."
       (c-backward-syntactic-ws lim))
     (when (setq pos1 (c-on-identifier))
       (goto-char pos1)
-      (let ((lim (save-excursion
-                  (and (c-beginning-of-macro)
-                       (progn (c-end-of-macro) (point))))))
-       (and (c-forward-declarator lim)
-            (if (and (eq (char-after) ?\()
-                     (c-go-list-forward nil lim))
+      (let* ((lim (save-excursion
+                   (and (c-beginning-of-macro)
+                        (progn (c-end-of-macro) (point)))))
+            (decl-res (c-forward-declarator lim)))
+        (if (or (cadr (cddr (cddr decl-res))) ; We scanned an arglist.
+                (and (eq (char-after) ?\() ; Move over a non arglist (...).
+                     (prog1 (c-go-list-forward nil lim)
+                       (c-forward-syntactic-ws lim))))
+            (if (looking-at c-symbol-char-key)
+                ;; Deal with baz (foo((bar)) type var), where `pos'
+                ;; was inside foo, but foo((bar)) is not semantically
+                ;; valid.  The result must be after var).
                 (and
-                 (progn (c-forward-syntactic-ws lim)
-                        (not (eobp)))
+                 (goto-char pos)
+                 (setq pos1 (c-on-identifier))
+                 (goto-char pos1)
                  (progn
-                   (if (looking-at c-symbol-char-key)
-                       ;; Deal with baz (foo((bar)) type var), where
-                       ;; foo((bar)) is not semantically valid.  The result
-                       ;; must be after var).
-                       (and
-                        (goto-char pos)
-                        (setq pos1 (c-on-identifier))
-                        (goto-char pos1)
-                        (progn
-                          (c-backward-syntactic-ws lim)
-                          (eq (char-before) ?\())
-                        (c-fl-decl-end (1- (point))))
-                     (c-backward-syntactic-ws lim)
-                     (point))))
-              (if (progn (c-forward-syntactic-ws lim)
-                         (not (eobp)))
-                  (c-forward-over-token)
-                (let ((lit-start (c-literal-start)))
-                  (when lit-start
-                      (goto-char lit-start))
-                  (c-backward-syntactic-ws)))
-              (and (>= (point) pos) (point))))))))
+                   (c-backward-syntactic-ws lim)
+                   (eq (char-before) ?\())
+                 (c-fl-decl-end (1- (point))))
+              (c-backward-syntactic-ws lim)
+              (point))
+          (if (progn (c-forward-syntactic-ws lim)
+                     (not (eobp)))
+              (progn
+                (c-forward-over-token)
+                ;; Cope with having POS withing a syntactically invalid
+                ;; (...), by moving backward out of the parens and trying
+                ;; again.
+                (when (and (eq (char-before) ?\))
+                           (c-go-list-backward (point) lim))
+                  (c-fl-decl-end (point))))
+            (let ((lit-start (c-literal-start)))
+              (when lit-start
+                (goto-char lit-start))
+              (c-backward-syntactic-ws)))
+          (and (>= (point) pos) (point)))))))
 
 (defun c-change-expand-fl-region (_beg _end _old-len)
   ;; Expand the region (c-new-BEG c-new-END) to an after-change font-lock