1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

Fix some errors in c-display-defun-name when the type is "struct {..}", etc.

Also fix some errors with c-display-defun-name when there are nested classes.

* lisp/progmodes/cc-cmds.el (c-in-function-trailer-p): Deal with a struct {..}
being merely the type of a function.
(c-where-wrt-brace-construct): Deal with a struct {..} being merely the type
of a function.  Rearrange the order of some Lisp forms.  Insert a check for
c-protection-key ("private", etc.) alongside the checking for a label.
(c-defun-name-1): New function extracted form c-defun-name, which works within
the existing restriction.  Don't regard 'at-function-end as being within the
defun any more.  Recognize "struct", etc., with the new
c-defun-type-name-decl-key rather than c-type-prefix-key.  Make the
recognition of a normal function more accurate.
(c-defun-name): Part left after extracting the above function.  It now just
widens and calls c-defun-name-1.
(c-declaration-limits-1): New function extracted from c-declaration-limits,
which works within the existing restriction.  Move LIM back one block to
account for the possibility of struct {..} as a function type.  Check we're
not inside a declaration without braces.
(c-declaration-limits): Part left after extracting the above function.  It now
just narrows to an enclosing decl block and calls c-declaration-limits-1.
(c-defun-name-and-limits): New function which identifies the name and limits
of the most nested enclosing declaration or macro.
(c-display-defun-name): Use c-defun-name-and-limits rather than two separate
functions (which didn't always agree on which function).

* lisp/progmodes/cc-engine.el (c-beginning-of-statement-1): If we have struct
{..} as the type of a function, go back over this, too.

* lisp/progmodes/cc-langs.el (c-defun-type-name-decl-kwds)
(c-defun-type-name-decl-key): New lang const/var.
This commit is contained in:
Alan Mackenzie 2018-01-28 17:53:07 +00:00
parent 36c8128e74
commit a718e1593a
3 changed files with 324 additions and 237 deletions

View file

@ -1397,6 +1397,16 @@ No indentation or other \"electric\" behavior is performed."
(not (eq (char-before) ?_))
(c-syntactic-re-search-forward "[;=([{]" eo-block t t t)
(eq (char-before) ?\{)
;; Exclude the entire "struct {...}" being the type of a
;; function being declared.
(not
(and
(c-go-up-list-forward)
(eq (char-before) ?})
(progn (c-forward-syntactic-ws)
(c-syntactic-re-search-forward
"[;=([{]" nil t t t))
(eq (char-before) ?\()))
bod)))))
(defun c-where-wrt-brace-construct ()
@ -1434,7 +1444,11 @@ No indentation or other \"electric\" behavior is performed."
((and (not least-enclosing)
(consp paren-state)
(consp (car paren-state))
(eq start (cdar paren-state)))
(eq start (cdar paren-state))
(not
(progn
(c-forward-syntactic-ws)
(looking-at c-symbol-start))))
'at-function-end)
(t
;; Find the start of the current declaration. NOTE: If we're in the
@ -1450,6 +1464,18 @@ No indentation or other \"electric\" behavior is performed."
"\\([;#]\\|\\'\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s$\\|\\s<\\|\\s>\\|\\s!\\)")))
(forward-char))
(setq kluge-start (point))
;; First approximation as to whether the current "header" we're in is
;; one followed by braces.
(setq brace-decl-p
(save-excursion
(and (c-syntactic-re-search-forward "[;{]" nil t t)
(or (eq (char-before) ?\{)
(and c-recognize-knr-p
;; Might have stopped on the
;; ';' in a K&R argdecl. In
;; that case the declaration
;; should contain a block.
(c-in-knr-argdecl))))))
(setq decl-result
(car (c-beginning-of-decl-1
;; NOTE: If we're in a K&R region, this might be the start
@ -1460,17 +1486,9 @@ No indentation or other \"electric\" behavior is performed."
(c-safe-position least-enclosing paren-state)))))
;; Has the declaration we've gone back to got braces?
(or (eq decl-result 'label)
(setq brace-decl-p
(save-excursion
(and (c-syntactic-re-search-forward "[;{]" nil t t)
(or (eq (char-before) ?\{)
(and c-recognize-knr-p
;; Might have stopped on the
;; ';' in a K&R argdecl. In
;; that case the declaration
;; should contain a block.
(c-in-knr-argdecl)))))))
(if (or (eq decl-result 'label)
(looking-at c-protection-key))
(setq brace-decl-p nil))
(cond
((or (eq decl-result 'label) ; e.g. "private:" or invalid syntax.
@ -1817,112 +1835,246 @@ the open-parenthesis that starts a defun; see `beginning-of-defun'."
(c-keep-region-active)
(= arg 0))))
(defun c-defun-name-1 ()
"Return the name of the current defun, at the current narrowing,
or NIL if there isn't one. \"Defun\" here means a function, or
other top level construct with a brace block."
(c-save-buffer-state
(beginning-of-defun-function end-of-defun-function
where pos decl name-start name-end case-fold-search)
(save-excursion
;; Move back out of any macro/comment/string we happen to be in.
(c-beginning-of-macro)
(setq pos (c-literal-start))
(if pos (goto-char pos))
(setq where (c-where-wrt-brace-construct))
;; Move to the beginning of the current defun, if any, if we're not
;; already there.
(if (memq where '(outwith-function at-function-end))
nil
(unless (eq where 'at-header)
(c-backward-to-nth-BOF-{ 1 where)
(c-beginning-of-decl-1))
(when (looking-at c-typedef-key)
(goto-char (match-end 0))
(c-forward-syntactic-ws))
;; Pick out the defun name, according to the type of defun.
(cond
;; struct, union, enum, or similar:
((save-excursion
(and
(looking-at c-defun-type-name-decl-key)
(consp (c-forward-decl-or-cast-1 (c-point 'bosws) 'top nil))
(or (not (or (eq (char-after) ?{)
(and c-recognize-knr-p
(c-in-knr-argdecl))))
(progn (c-backward-syntactic-ws)
(not (eq (char-before) ?\)))))))
(let ((key-pos (point)))
(c-forward-over-token-and-ws) ; over "struct ".
(cond
((looking-at c-symbol-key) ; "struct foo { ..."
(buffer-substring-no-properties key-pos (match-end 0)))
((eq (char-after) ?{) ; "struct { ... } foo"
(when (c-go-list-forward)
(c-forward-syntactic-ws)
(when (looking-at c-symbol-key) ; a bit bogus - there might
; be several identifiers.
(match-string-no-properties 0)))))))
((looking-at "DEFUN\\s-*(") ;"DEFUN\\_>") think of XEmacs!
;; DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory, ...) ==> Ffile_name_directory
;; DEFUN(POSIX::STREAM-LOCK, stream lockp &key BLOCK SHARED START LENGTH) ==> POSIX::STREAM-LOCK
(down-list 1)
(c-forward-syntactic-ws)
(when (eq (char-after) ?\")
(forward-sexp 1)
(c-forward-token-2)) ; over the comma and following WS.
(buffer-substring-no-properties
(point)
(progn
(c-forward-token-2)
(c-backward-syntactic-ws)
(point))))
(t
;; Normal function or initializer.
(when
(and
(consp
(setq decl
(c-forward-decl-or-cast-1 (c-point 'bosws) 'top nil)))
(setq name-start (car decl))
(progn (if (and (looking-at c-after-suffixed-type-decl-key)
(match-beginning 1))
(c-forward-keyword-clause 1))
t)
(or (eq (char-after) ?{)
(and c-recognize-knr-p
(c-in-knr-argdecl)))
(goto-char name-start)
(c-forward-name)
(eq (char-after) ?\())
(c-backward-syntactic-ws)
(when (eq (char-before) ?\=) ; struct foo bar = {0, 0} ;
(c-backward-token-2)
(c-backward-syntactic-ws))
(setq name-end (point))
(c-back-over-compound-identifier)
(and (looking-at c-symbol-start)
(buffer-substring-no-properties (point) name-end)))))))))
(defun c-defun-name ()
"Return the name of the current defun, or NIL if there isn't one.
\"Defun\" here means a function, or other top level construct
with a brace block."
(c-save-buffer-state
(beginning-of-defun-function end-of-defun-function
where pos name-end case-fold-search)
with a brace block, at the outermost level of nesting."
(c-save-buffer-state ()
(save-restriction
(widen)
(save-excursion
;; Move back out of any macro/comment/string we happen to be in.
(c-beginning-of-macro)
(setq pos (c-literal-start))
(if pos (goto-char pos))
(c-defun-name-1))))
(setq where (c-where-wrt-brace-construct))
(defun c-declaration-limits-1 (near)
;; Return a cons of the beginning and end position of the current
;; declaration or macro in the current narrowing. If there is no current
;; declaration or macro, return nil, unless NEAR is non-nil, in which case
;; the closest following one is chosen instead (if there is any). The end
;; position is at the next line, providing there is one before the
;; declaration.
;;
;; This function might do hidden buffer changes.
(save-excursion
(let ((start (point))
(paren-state (c-parse-state))
lim pos end-pos where)
(or
;; Note: Some code duplication in `c-beginning-of-defun' and
;; `c-end-of-defun'.
(catch 'exit
(unless (c-safe
(goto-char (c-least-enclosing-brace paren-state))
;; If we moved to the outermost enclosing paren
;; then we can use c-safe-position to set the
;; limit. Can't do that otherwise since the
;; earlier paren pair on paren-state might very
;; well be part of the declaration we should go
;; to.
(setq lim (c-safe-position (point) paren-state))
;; We might have a struct foo {...} as the type of the
;; function, so set LIM back one further block.
(if (eq (char-before lim) ?})
(setq lim
(or
(save-excursion
(and
(c-go-list-backward lim)
(let ((paren-state-1 (c-parse-state)))
(c-safe-position
(point) paren-state-1))))
(point-min))))
t)
;; At top level. Make sure we aren't inside a literal.
(setq pos (c-literal-start
(c-safe-position (point) paren-state)))
(if pos (goto-char pos)))
;; Move to the beginning of the current defun, if any, if we're not
;; already there.
(if (eq where 'outwith-function)
nil
(unless (eq where 'at-header)
(c-backward-to-nth-BOF-{ 1 where)
(c-beginning-of-decl-1))
(when (looking-at c-typedef-key)
(goto-char (match-end 0))
(c-forward-syntactic-ws))
(when (c-beginning-of-macro)
(throw 'exit
(cons (point)
(save-excursion
(c-end-of-macro)
(forward-line 1)
(point)))))
;; Pick out the defun name, according to the type of defun.
(cond
;; struct, union, enum, or similar:
((save-excursion
(and
(looking-at c-type-prefix-key)
(consp (c-forward-decl-or-cast-1 (c-point 'bosws) 'top nil))
(or (not (or (eq (char-after) ?{)
(and c-recognize-knr-p
(c-in-knr-argdecl))))
(progn (c-backward-syntactic-ws)
(not (eq (char-before) ?\)))))))
(let ((key-pos (point)))
(c-forward-over-token-and-ws) ; over "struct ".
(cond
((looking-at c-symbol-key) ; "struct foo { ..."
(buffer-substring-no-properties key-pos (match-end 0)))
((eq (char-after) ?{) ; "struct { ... } foo"
(when (c-go-list-forward)
(c-forward-syntactic-ws)
(when (looking-at c-symbol-key) ; a bit bogus - there might
; be several identifiers.
(match-string-no-properties 0)))))))
(setq pos (point))
(setq where (and (not (save-excursion (c-beginning-of-macro)))
(c-where-wrt-brace-construct)))
(when (and (not (eq where 'at-header))
(or (and near
(memq where
'(at-function-end outwith-function))
;; Check we're not inside a declaration without
;; braces.
(save-excursion
(memq (car (c-beginning-of-decl-1 lim))
'(previous label))))
(eq (car (c-beginning-of-decl-1 lim)) 'previous)
(= pos (point))))
;; We moved back over the previous defun. Skip to the next
;; one. Not using c-forward-syntactic-ws here since we
;; should not skip a macro. We can also be directly after
;; the block in a `c-opt-block-decls-with-vars-key'
;; declaration, but then we won't move significantly far
;; here.
(goto-char pos)
(c-forward-comments)
((looking-at "DEFUN\\s-*(") ;"DEFUN\\_>") think of XEmacs!
;; DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory, ...) ==> Ffile_name_directory
;; DEFUN(POSIX::STREAM-LOCK, stream lockp &key BLOCK SHARED START LENGTH) ==> POSIX::STREAM-LOCK
(down-list 1)
(c-forward-syntactic-ws)
(when (eq (char-after) ?\")
(forward-sexp 1)
(c-forward-token-2)) ; over the comma and following WS.
(buffer-substring-no-properties
(point)
(progn
(c-forward-token-2)
(when (looking-at ":") ; CLISP: DEFUN(PACKAGE:LISP-SYMBOL,...)
(skip-chars-forward "^,"))
(c-backward-syntactic-ws)
(point))))
(when (and near (c-beginning-of-macro))
(throw 'exit
(cons (point)
(save-excursion
(c-end-of-macro)
(forward-line 1)
(point))))))
((looking-at "DEF[a-zA-Z0-9_]* *( *\\([^, ]*\\) *,")
;; DEFCHECKER(sysconf_arg,prefix=_SC,default=, ...) ==> sysconf_arg
;; DEFFLAGSET(syslog_opt_flags,LOG_PID ...) ==> syslog_opt_flags
(match-string-no-properties 1))
(if (eobp) (throw 'exit nil))
;; Objc selectors.
((assq 'objc-method-intro (c-guess-basic-syntax))
(let ((bound (save-excursion (c-end-of-statement) (point)))
(kw-re (concat "\\(?:" c-symbol-key "\\)?:"))
(stretches))
(when (c-syntactic-re-search-forward c-symbol-key bound t t t)
(push (match-string-no-properties 0) stretches)
(while (c-syntactic-re-search-forward kw-re bound t t t)
(push (match-string-no-properties 0) stretches)))
(apply 'concat (nreverse stretches))))
;; Check if `c-beginning-of-decl-1' put us after the block in a
;; declaration that doesn't end there. We're searching back and
;; forth over the block here, which can be expensive.
(setq pos (point))
(if (and c-opt-block-decls-with-vars-key
(progn
(c-backward-syntactic-ws)
(eq (char-before) ?}))
(eq (car (c-beginning-of-decl-1))
'previous)
(save-excursion
(c-end-of-decl-1)
(and (> (point) pos)
(setq end-pos (point)))))
nil
(goto-char pos))
(t
;; Normal function or initializer.
(when
(and
(consp (c-forward-decl-or-cast-1 (c-point 'bosws) 'top nil))
(or (eq (char-after) ?{)
(and c-recognize-knr-p
(c-in-knr-argdecl)))
(if (or (and (not near) (> (point) start))
(not (eq (c-where-wrt-brace-construct) 'at-header)))
nil
;; Try to be line oriented; position the limits at the
;; closest preceding boi, and after the next newline, that
;; isn't inside a comment, but if we hit a neighboring
;; declaration then we instead use the exact declaration
;; limit in that direction.
(cons (progn
(setq pos (point))
(while (and (/= (point) (c-point 'boi))
(c-backward-single-comment)))
(if (/= (point) (c-point 'boi))
pos
(point)))
(progn
(c-backward-syntactic-ws)
(eq (char-before) ?\)))
(c-go-list-backward))
(c-backward-syntactic-ws)
(when (eq (char-before) ?\=) ; struct foo bar = {0, 0} ;
(c-backward-token-2)
(c-backward-syntactic-ws))
(setq name-end (point))
(c-back-over-compound-identifier)
(and (looking-at c-symbol-start)
(buffer-substring-no-properties (point) name-end))))))))))
(if end-pos
(goto-char end-pos)
(c-end-of-decl-1))
(setq pos (point))
(while (and (not (bolp))
(not (looking-at "\\s *$"))
(c-forward-single-comment)))
(cond ((bolp)
(point))
((looking-at "\\s *$")
(forward-line 1)
(point))
(t
pos))))))
(and (not near)
(goto-char (point-min))
(c-forward-decl-or-cast-1 -1 nil nil)
(eq (char-after) ?\{)
(cons (point-min) (point-max)))))))
(defun c-declaration-limits (near)
;; Return a cons of the beginning and end positions of the current
@ -1933,135 +2085,48 @@ with a brace block."
;; declaration.
;;
;; This function might do hidden buffer changes.
(save-excursion
(save-restriction
(let ((start (point))
(paren-state (c-parse-state))
lim pos end-pos where)
;; Narrow enclosing brace blocks out, as required by the values of
;; `c-defun-tactic', `near', and the position of point.
(when (eq c-defun-tactic 'go-outward)
(let ((bounds
(save-restriction
(if (and (not (save-excursion (c-beginning-of-macro)))
(save-restriction
(c-narrow-to-most-enclosing-decl-block)
(memq (c-where-wrt-brace-construct)
'(at-function-end outwith-function)))
(not near))
(c-narrow-to-most-enclosing-decl-block nil 2)
(c-narrow-to-most-enclosing-decl-block))
(cons (point-min) (point-max)))))
(narrow-to-region (car bounds) (cdr bounds))))
(setq paren-state (c-parse-state))
(save-restriction
;; Narrow enclosing brace blocks out, as required by the values of
;; `c-defun-tactic', `near', and the position of point.
(when (eq c-defun-tactic 'go-outward)
(let ((bounds
(save-restriction
(if (and (not (save-excursion (c-beginning-of-macro)))
(save-restriction
(c-narrow-to-most-enclosing-decl-block)
(memq (c-where-wrt-brace-construct)
'(at-function-end outwith-function)))
(not near))
(c-narrow-to-most-enclosing-decl-block nil 2)
(c-narrow-to-most-enclosing-decl-block))
(cons (point-min) (point-max)))))
(narrow-to-region (car bounds) (cdr bounds))))
(c-declaration-limits-1 near)))
(or
;; Note: Some code duplication in `c-beginning-of-defun' and
;; `c-end-of-defun'.
(catch 'exit
(unless (c-safe
(goto-char (c-least-enclosing-brace paren-state))
;; If we moved to the outermost enclosing paren
;; then we can use c-safe-position to set the
;; limit. Can't do that otherwise since the
;; earlier paren pair on paren-state might very
;; well be part of the declaration we should go
;; to.
(setq lim (c-safe-position (point) paren-state))
t)
;; At top level. Make sure we aren't inside a literal.
(setq pos (c-literal-start
(c-safe-position (point) paren-state)))
(if pos (goto-char pos)))
(when (c-beginning-of-macro)
(throw 'exit
(cons (point)
(save-excursion
(c-end-of-macro)
(forward-line 1)
(point)))))
(setq pos (point))
(setq where (and (not (save-excursion (c-beginning-of-macro)))
(c-where-wrt-brace-construct)))
(when (and (not (eq where 'at-header))
(or (and near
(memq where
'(at-function-end outwith-function)))
(eq (car (c-beginning-of-decl-1 lim)) 'previous)
(= pos (point))))
;; We moved back over the previous defun. Skip to the next
;; one. Not using c-forward-syntactic-ws here since we
;; should not skip a macro. We can also be directly after
;; the block in a `c-opt-block-decls-with-vars-key'
;; declaration, but then we won't move significantly far
;; here.
(goto-char pos)
(c-forward-comments)
(when (and near (c-beginning-of-macro))
(throw 'exit
(cons (point)
(save-excursion
(c-end-of-macro)
(forward-line 1)
(point))))))
(if (eobp) (throw 'exit nil))
;; Check if `c-beginning-of-decl-1' put us after the block in a
;; declaration that doesn't end there. We're searching back and
;; forth over the block here, which can be expensive.
(setq pos (point))
(if (and c-opt-block-decls-with-vars-key
(progn
(c-backward-syntactic-ws)
(eq (char-before) ?}))
(eq (car (c-beginning-of-decl-1))
'previous)
(save-excursion
(c-end-of-decl-1)
(and (> (point) pos)
(setq end-pos (point)))))
nil
(goto-char pos))
(if (and (not near) (> (point) start))
nil
;; Try to be line oriented; position the limits at the
;; closest preceding boi, and after the next newline, that
;; isn't inside a comment, but if we hit a neighboring
;; declaration then we instead use the exact declaration
;; limit in that direction.
(cons (progn
(setq pos (point))
(while (and (/= (point) (c-point 'boi))
(c-backward-single-comment)))
(if (/= (point) (c-point 'boi))
pos
(point)))
(progn
(if end-pos
(goto-char end-pos)
(c-end-of-decl-1))
(setq pos (point))
(while (and (not (bolp))
(not (looking-at "\\s *$"))
(c-forward-single-comment)))
(cond ((bolp)
(point))
((looking-at "\\s *$")
(forward-line 1)
(point))
(t
pos))))))
(and (not near)
(goto-char (point-min))
(c-forward-decl-or-cast-1 -1 nil nil)
(eq (char-after) ?\{)
(cons (point-min) (point-max))))))))
(defun c-defun-name-and-limits (near)
;; Return a cons of the name and limits (itself a cons) of the current
;; top-level declaration or macro, or nil of there is none.
;;
;; If `c-defun-tactic' is 'go-outward, we return the name and limits of the
;; most tightly enclosing declaration or macro. Otherwise, we return that
;; at the file level.
(save-restriction
(widen)
(if (eq c-defun-tactic 'go-outward)
(c-save-buffer-state ((paren-state (c-parse-state))
(orig-point-min (point-min))
(orig-point-max (point-max))
lim name where limits fdoc)
(setq lim (c-widen-to-enclosing-decl-scope
paren-state orig-point-min orig-point-max))
(and lim (setq lim (1- lim)))
(c-while-widening-to-decl-block (not (setq name (c-defun-name-1))))
(when name
(setq limits (c-declaration-limits-1 near))
(cons name limits)))
(c-save-buffer-state ((name (c-defun-name))
(limits (c-declaration-limits near)))
(and name limits (cons name limits))))))
(defun c-display-defun-name (&optional arg)
"Display the name of the current CC mode defun and the position in it.
@ -2069,12 +2134,13 @@ With a prefix arg, push the name onto the kill ring too."
(interactive "P")
(save-restriction
(widen)
(c-save-buffer-state ((name (c-defun-name))
(limits (c-declaration-limits t))
(c-save-buffer-state ((name-and-limits (c-defun-name-and-limits nil))
(name (car name-and-limits))
(limits (cdr name-and-limits))
(point-bol (c-point 'bol)))
(when name
(message "%s. Line %s/%s." name
(1+ (count-lines (car limits) point-bol))
(1+ (count-lines (car limits) (max point-bol (car limits))))
(count-lines (car limits) (cdr limits)))
(if arg (kill-new name))
(sit-for 3 t)))))