From: Alan Mackenzie Date: Sun, 21 Jul 2019 21:08:03 +0000 (+0000) Subject: Implement C++ Mode attributes. This fixes bug #36650. X-Git-Tag: emacs-27.0.90~1822 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=5ccaee4bbc184c53b262021361bd216af17e80f5;p=emacs.git Implement C++ Mode attributes. This fixes bug #36650. * lisp/progmodes/cc-engine.el (c-looking-at-c++-attribute) (c-enclosing-c++-attribute, c-slow-enclosing-c++-attribute): New macro and functions. (c-crosses-statement-barrier-p): Add [ into skip-chars for C++ Mode, and use it to detect and skip over an attribute whilst scanning forward. (c-sws-lit-type): Use the new value 'attribute. (c-invalidate-sws-region-before): Put a save-match-data around this function. Detect and handle an enclosing attribute at either END or BEG. (c-invalidate-sws-region-after): Handle C++ attributes. (c-forward-sws, c-backward-sws): Handle C++ attributes. * lisp/progmodes/cc-mode.el (c-fl-decl-end): Detect and handle point being inside a C++ attribute. --- diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index cb88fc3e58d..e7bae0e7b68 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -689,6 +689,21 @@ comment at the start of cc-engine.el for more info." (when (> ol-end end) (overlay-put (make-overlay end ol-end) 'face face)))) + +(defmacro c-looking-at-c++-attribute () + ;; If we're in C++ Mode, and point is at the [[ introducing an attribute, + ;; return the position of the end of the attribute, otherwise return nil. + ;; The match data are NOT preserved over this macro. + `(and + (c-major-mode-is 'c++-mode) + (looking-at "\\[\\[") + (save-excursion + (and + (c-go-list-forward) + (eq (char-before) ?\]) + (eq (char-before (1- (point))) ?\]) + (point))))) + ;; `c-beginning-of-statement-1' and accompanying stuff. @@ -1414,9 +1429,15 @@ comment at the start of cc-engine.el for more info." c-opt-cpp-symbol ; usually "#" (substring c-stmt-delim-chars 1)) ; e.g. ";{}?:" c-stmt-delim-chars)) + (skip-chars + (if (c-major-mode-is 'c++-mode) + (concat (substring skip-chars 0 1) ; "^" + "[" ; to catch C++ attributes + (substring skip-chars 1)) ; e.g. "#;{}?:" + skip-chars)) (non-skip-list (append (substring skip-chars 1) nil)) ; e.g. (?# ?\; ?{ ?} ?? ?:) - lit-range lit-start vsemi-pos) + lit-range lit-start vsemi-pos attr-end) (save-restriction (widen) (save-excursion @@ -1440,6 +1461,11 @@ comment at the start of cc-engine.el for more info." ;; In a string/comment? ((setq lit-range (c-literal-limits from)) (goto-char (cdr lit-range))) + ;; Skip over a C++ attribute? + ((eq (char-after) ?\[) + (if (setq attr-end (c-looking-at-c++-attribute)) + (goto-char attr-end) + (forward-char))) ((eq (char-after) ?:) (forward-char) (if (and (eq (char-after) ?:) @@ -1827,12 +1853,63 @@ comment at the start of cc-engine.el for more info." (def-edebug-spec c-remove-is-and-in-sws t) ;; The type of literal position `end' is in a `before-change-functions' -;; function - one of `c', `c++', `pound', or nil (but NOT `string'). +;; function - one of `c', `c++', `pound', `noise', `attribute' or nil (but NOT +;; `string'). (defvar c-sws-lit-type nil) -;; A cons (START . STOP) of the bounds of the comment or CPP construct +;; A cons (START . STOP) of the bounds of the comment or CPP construct, etc., ;; enclosing END, if any, else nil. (defvar c-sws-lit-limits nil) +(defun c-enclosing-c++-attribute () + ;; If we're in C++ Mode, and point is within a correctly balanced [[ ... ]] + ;; attribute structure, return a cons of its starting and ending positions. + ;; Otherwise, return nil. We use the c-{in,is}-sws-face text properties for + ;; this determination, this macro being intended only for use in the *-sws-* + ;; functions and macros. The match data are NOT preserved over this macro. + (let (attr-end pos-is-sws) + (and + (c-major-mode-is 'c++-mode) + (> (point) (point-min)) + (setq pos-is-sws + (if (get-text-property (1- (point)) 'c-is-sws) + (1- (point)) + (1- (previous-single-property-change + (point) 'c-is-sws nil (point-min))))) + (save-excursion + (goto-char pos-is-sws) + (setq attr-end (c-looking-at-c++-attribute))) + (> attr-end (point)) + (cons pos-is-sws attr-end)))) + +(defun c-slow-enclosing-c++-attribute () + ;; Like `c-enclosing-c++-attribute', but does not depend on the c-i[ns]-sws + ;; properties being set. + (and + (c-major-mode-is 'c++-mode) + (save-excursion + (let ((paren-state (c-parse-state)) + cand) + (while + (progn + (setq cand + (catch 'found-cand + (while (cdr paren-state) + (when (and (numberp (car paren-state)) + (numberp (cadr paren-state)) + (eq (car paren-state) + (1+ (cadr paren-state))) + (eq (char-after (car paren-state)) ?\[) + (eq (char-after (cadr paren-state)) ?\[)) + (throw 'found-cand (cadr paren-state))) + (setq paren-state (cdr paren-state))))) + (and cand + (not + (and (c-go-list-forward cand) + (eq (char-before) ?\]) + (eq (char-before (1- (point))) ?\]))))) + (setq paren-state (cdr paren-state))) + (and cand (cons cand (point))))))) + (defun c-invalidate-sws-region-before (beg end) ;; Called from c-before-change. BEG and END are the bounds of the change ;; region, the standard parameters given to all before-change-functions. @@ -1841,31 +1918,41 @@ comment at the start of cc-engine.el for more info." ;; if so note its bounds in `c-sws-lit-limits' and type in `c-sws-lit-type'. (setq c-sws-lit-type nil c-sws-lit-limits nil) - (save-excursion - (goto-char end) - (let* ((limits (c-literal-limits)) - (lit-type (c-literal-type limits))) - (cond - ((memq lit-type '(c c++)) - (setq c-sws-lit-type lit-type - c-sws-lit-limits limits)) - ((c-beginning-of-macro) - (setq c-sws-lit-type 'pound - c-sws-lit-limits (cons (point) - (progn (c-end-of-macro) (point))))) - ((progn (skip-syntax-backward "w_") - (looking-at c-noise-macro-name-re)) - (setq c-sws-lit-type 'noise - c-sws-lit-limits (cons (match-beginning 1) (match-end 1)))) - (t)))) - (save-excursion - (goto-char beg) - (skip-syntax-backward "w_") - (when (looking-at c-noise-macro-name-re) - (setq c-sws-lit-type 'noise) - (if (consp c-sws-lit-limits) - (setcar c-sws-lit-limits (match-beginning 1)) - (setq c-sws-lit-limits (cons (match-beginning 1) (match-end 1))))))) + (save-match-data + (save-excursion + (goto-char end) + (let* ((limits (c-literal-limits)) + (lit-type (c-literal-type limits))) + (cond + ((memq lit-type '(c c++)) + (setq c-sws-lit-type lit-type + c-sws-lit-limits limits)) + ((c-beginning-of-macro) + (setq c-sws-lit-type 'pound + c-sws-lit-limits (cons (point) + (progn (c-end-of-macro) (point))))) + ((eq lit-type 'string)) + ((setq c-sws-lit-limits (c-enclosing-c++-attribute)) + (setq c-sws-lit-type 'attribute)) + ((progn (skip-syntax-backward "w_") + (looking-at c-noise-macro-name-re)) + (setq c-sws-lit-type 'noise + c-sws-lit-limits (cons (match-beginning 1) (match-end 1)))) + (t)))) + (save-excursion + (goto-char beg) + (let ((attr-limits (c-enclosing-c++-attribute))) + (if attr-limits + (if (consp c-sws-lit-limits) + (setcar c-sws-lit-limits (car attr-limits)) + (setq c-sws-lit-limits attr-limits)) + (skip-syntax-backward "w_") + (when (looking-at c-noise-macro-name-re) + (setq c-sws-lit-type 'noise) + (if (consp c-sws-lit-limits) + (setcar c-sws-lit-limits (match-beginning 1)) + (setq c-sws-lit-limits (cons (match-beginning 1) + (match-end 1)))))))))) (defun c-invalidate-sws-region-after-del (beg end _old-len) ;; Text has been deleted, OLD-LEN characters of it starting from position @@ -1940,7 +2027,7 @@ comment at the start of cc-engine.el for more info." (when (and (eolp) (not (eobp))) (setq end (1+ (point))))) - (when (eq c-sws-lit-type 'noise) + (when (memq c-sws-lit-type '(noise attribute)) (setq beg (car c-sws-lit-limits) end (cdr c-sws-lit-limits))) ; This last setting may be redundant. @@ -1990,6 +2077,8 @@ comment at the start of cc-engine.el for more info." (when (or (looking-at c-syntactic-ws-start) (and c-opt-cpp-prefix (looking-at c-noise-macro-name-re)) + (and (c-major-mode-is 'c++-mode) + (looking-at "\\[\\[")) (looking-at c-doc-line-join-re)) (setq rung-end-pos (min (1+ (point)) (point-max))) @@ -2126,6 +2215,10 @@ comment at the start of cc-engine.el for more info." (goto-char (match-end 1)) (not (eobp))) + ((setq next-rung-pos (c-looking-at-c++-attribute)) + (goto-char next-rung-pos) + (not (eobp))) + ((looking-at c-doc-line-join-re) ;; Skip over a line join in (e.g.) Pike autodoc. (goto-char (match-end 0)) @@ -2214,8 +2307,7 @@ comment at the start of cc-engine.el for more info." "c-forward-sws clearing thoroughly at %s for cache separation" (1- last-put-in-sws-pos)) (c-remove-is-and-in-sws (1- last-put-in-sws-pos) - last-put-in-sws-pos)))) - )))) + last-put-in-sws-pos)))))))) (defun c-backward-sws () ;; Used by `c-backward-syntactic-ws' to implement the unbounded search. @@ -2226,7 +2318,8 @@ comment at the start of cc-engine.el for more info." ;; part of the simple ws region. (rung-pos (point)) next-rung-pos last-put-in-sws-pos rung-is-marked simple-ws-beg cmt-skip-pos - (doc-line-join-here (concat c-doc-line-join-re "\\="))) + (doc-line-join-here (concat c-doc-line-join-re "\\=")) + attr-end) ;; Skip simple horizontal ws and do a quick check on the preceding ;; character to see if it's anything that can't end syntactic ws, so we can @@ -2240,6 +2333,14 @@ comment at the start of cc-engine.el for more info." (memq (char-before) c-doc-line-join-end-ch) ; For speed. (re-search-backward doc-line-join-here (c-point 'bopl) t)) + (and + (c-major-mode-is 'c++-mode) + (eq (char-before) ?\]) + (eq (char-before (1- (point))) ?\]) + (save-excursion + (and (c-go-list-backward) + (looking-at "\\[\\["))) + (setq attr-end (point))) (progn (backward-char) (or (looking-at c-syntactic-ws-end) @@ -2250,7 +2351,8 @@ comment at the start of cc-engine.el for more info." ;; Try to find a rung position in the simple ws preceding point, so that ;; we can get a cache hit even if the last bit of the simple ws has ;; changed recently. - (setq simple-ws-beg (or (match-end 1) ; Noise macro + (setq simple-ws-beg (or attr-end ; After attribute. + (match-end 1) ; Noise macro, etc. (match-end 0))) ; c-syntactic-ws-end (skip-chars-backward " \t\n\r\f\v") (if (setq rung-is-marked (text-property-any @@ -2388,6 +2490,16 @@ comment at the start of cc-engine.el for more info." (goto-char next-rung-pos) t) + ((and (c-major-mode-is 'c++-mode) + (eq (char-before) ?\]) + (eq (char-before (1- (point))) ?\]) + (save-excursion + (and (c-go-list-backward) + (setq next-rung-pos (point)) + (looking-at "\\[\\[")))) + (goto-char next-rung-pos) + t) + ((and (memq (char-before) c-doc-line-join-end-ch) ; For speed. (re-search-backward doc-line-join-here (c-point 'bopl) t))))) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 5ae7e0f09d8..a5e158933ba 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -2158,9 +2158,11 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") ;; count as being in a declarator (on pragmatic grounds). (goto-char pos) (let ((lit-start (c-literal-start)) - pos1) + enclosing-attribute pos1) (unless lit-start (c-backward-syntactic-ws) + (when (setq enclosing-attribute (c-slow-enclosing-c++-attribute)) + (goto-char (car enclosing-attribute))) ; Only happens in C++ Mode. (when (setq pos1 (c-on-identifier)) (goto-char pos1) (let ((lim (save-excursion