From mboxrd@z Thu Jan  1 00:00:00 1970
Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail
From: Alan Mackenzie <acm@muc.de>
Newsgroups: gmane.emacs.bugs
Subject: bug#36650: 27.0.50; CC Mode: Support C++ attributes
Date: Sat, 20 Jul 2019 18:02:30 +0000
Message-ID: <20190720180230.GB27030@ACM>
References: <20190715142718.71903.qmail@mail.muc.de>
 <87muhf9vjs.fsf@telefonica.net>
Mime-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226";
	logging-data="227859"; mail-complaints-to="usenet@blaine.gmane.org"
User-Agent: Mutt/1.10.1 (2018-07-13)
Cc: 36650@debbugs.gnu.org
To: =?UTF-8?Q?=C3=93scar?= Fuentes <ofv@wanadoo.es>
Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sat Jul 20 20:03:14 2019
Return-path: <bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org>
Envelope-to: geb-bug-gnu-emacs@m.gmane.org
Original-Received: from lists.gnu.org ([209.51.188.17])
	by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
	(Exim 4.89)
	(envelope-from <bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org>)
	id 1hothR-000x7u-DL
	for geb-bug-gnu-emacs@m.gmane.org; Sat, 20 Jul 2019 20:03:13 +0200
Original-Received: from localhost ([::1]:52414 helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.86_2)
	(envelope-from <bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org>)
	id 1hothP-0000Dy-Qx
	for geb-bug-gnu-emacs@m.gmane.org; Sat, 20 Jul 2019 14:03:11 -0400
Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:47310)
 by lists.gnu.org with esmtp (Exim 4.86_2)
 (envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1hothL-0000Ci-ME
 for bug-gnu-emacs@gnu.org; Sat, 20 Jul 2019 14:03:09 -0400
Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)
 (envelope-from <Debian-debbugs@debbugs.gnu.org>) id 1hothJ-0005YG-SB
 for bug-gnu-emacs@gnu.org; Sat, 20 Jul 2019 14:03:07 -0400
Original-Received: from debbugs.gnu.org ([209.51.188.43]:49072)
 by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16)
 (Exim 4.71) (envelope-from <Debian-debbugs@debbugs.gnu.org>)
 id 1hothG-0005VZ-Ul; Sat, 20 Jul 2019 14:03:03 -0400
Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2)
 (envelope-from <Debian-debbugs@debbugs.gnu.org>)
 id 1hothG-0000Mo-EV; Sat, 20 Jul 2019 14:03:02 -0400
X-Loop: help-debbugs@gnu.org
Resent-From: Alan Mackenzie <acm@muc.de>
Original-Sender: "Debbugs-submit" <debbugs-submit-bounces@debbugs.gnu.org>
Resent-CC: bug-gnu-emacs@gnu.org, bug-cc-mode@gnu.org
Resent-Date: Sat, 20 Jul 2019 18:03:01 +0000
Resent-Message-ID: <handler.36650.B36650.15636457561379@debbugs.gnu.org>
Resent-Sender: help-debbugs@gnu.org
X-GNU-PR-Message: followup 36650
X-GNU-PR-Package: emacs,cc-mode
Original-Received: via spool by 36650-submit@debbugs.gnu.org id=B36650.15636457561379
 (code B ref 36650); Sat, 20 Jul 2019 18:03:01 +0000
Original-Received: (at 36650) by debbugs.gnu.org; 20 Jul 2019 18:02:36 +0000
Original-Received: from localhost ([127.0.0.1]:57893 helo=debbugs.gnu.org)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <debbugs-submit-bounces@debbugs.gnu.org>)
 id 1hotgp-0000M9-Mk
 for submit@debbugs.gnu.org; Sat, 20 Jul 2019 14:02:36 -0400
Original-Received: from colin.muc.de ([193.149.48.1]:63633 helo=mail.muc.de)
 by debbugs.gnu.org with smtp (Exim 4.84_2)
 (envelope-from <acm@muc.de>) id 1hotgn-0000M0-0d
 for 36650@debbugs.gnu.org; Sat, 20 Jul 2019 14:02:34 -0400
Original-Received: (qmail 21688 invoked by uid 3782); 20 Jul 2019 17:10:07 -0000
Original-Received: from acm.muc.de (p2E5D5FE3.dip0.t-ipconnect.de [46.93.95.227]) by
 colin.muc.de (tmda-ofmipd) with ESMTP;
 Sat, 20 Jul 2019 19:10:05 +0200
Original-Received: (qmail 29830 invoked by uid 1000); 20 Jul 2019 18:02:30 -0000
Content-Disposition: inline
In-Reply-To: <87muhf9vjs.fsf@telefonica.net>
X-Delivery-Agent: TMDA/1.1.12 (Macallan)
X-Primary-Address: acm@muc.de
X-BeenThere: debbugs-submit@debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic]
X-Received-From: 209.51.188.43
X-BeenThere: bug-gnu-emacs@gnu.org
List-Id: "Bug reports for GNU Emacs,
 the Swiss army knife of text editors" <bug-gnu-emacs.gnu.org>
List-Unsubscribe: <https://lists.gnu.org/mailman/options/bug-gnu-emacs>,
 <mailto:bug-gnu-emacs-request@gnu.org?subject=unsubscribe>
List-Archive: <https://lists.gnu.org/archive/html/bug-gnu-emacs>
List-Post: <mailto:bug-gnu-emacs@gnu.org>
List-Help: <mailto:bug-gnu-emacs-request@gnu.org?subject=help>
List-Subscribe: <https://lists.gnu.org/mailman/listinfo/bug-gnu-emacs>,
 <mailto:bug-gnu-emacs-request@gnu.org?subject=subscribe>
Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org
Original-Sender: "bug-gnu-emacs"
 <bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org>
Xref: news.gmane.org gmane.emacs.bugs:163485
Archived-At: <http://permalink.gmane.org/gmane.emacs.bugs/163485>

Hello, Óscar.

On Mon, Jul 15, 2019 at 17:17:27 +0200, Óscar Fuentes wrote:
> Alan Mackenzie <acm@muc.de> writes:

> > Yes.  I'll have a look at this.

> Thanks.

> >> In general, considering them part of the following token for indentation
> >> purposes and fontifying with some existing or new face should be enough.

> > I will probably end up treating attributes as syntactic whitespace.
> > They have no syntactic connection with the code they are embedded in,
> > any more than macros do.

The patch below (which should apply cleanly to the master branch) is a
first attempt at handling C++ attributes.

> I don't know how syntactic whitespace works on CC Mode, so just in case
> I'll mention that this code

> int foo([[maybe_unused]] int a,
>         int b);
        
> should not be formatted as

> int foo([[maybe_unused]] int a,
>                          int b);

Understood.  Happily, the code appears to do the right thing anyway,
without needing tedious fixing.  :-)

Could you please try out this patch, and let me know how well it works.

Thanks!



diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index cb88fc3e58..7963ab0d43 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -1827,45 +1827,122 @@ c-remove-is-and-in-sws
 (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', `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)
 
+(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)))))
+
+;; (defmacro c-enclosing-c++-attribute ()
+(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.
   ;;
-  ;; Note whether END is inside a comment, CPP construct, or noise macro, and
-  ;; if so note its bounds in `c-sws-lit-limits' and type in `c-sws-lit-type'.
+  ;; Note whether END is inside a comment, CPP construct, C++ attribute, or
+  ;; noise macro, and 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 +2017,7 @@ c-invalidate-sws-region-after
       (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 +2067,8 @@ c-forward-sws
     (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 +2205,16 @@ c-forward-sws
 	      (goto-char (match-end 1))
 	      (not (eobp)))
 
+	     ((and (c-major-mode-is 'c++-mode)
+		   (looking-at "\\[\\[")
+		   (save-excursion
+		     (and (c-go-list-forward)
+			  (eq (char-before) ?\])
+			  (eq (char-before (1- (point))) ?\])
+			  (setq next-rung-pos (point))))
+		   (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))
@@ -2240,6 +2329,13 @@ c-backward-sws
 		      (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 "\\(\\)\\[\\["))))
 		     (progn
 		       (backward-char)
 		       (or (looking-at c-syntactic-ws-end)
@@ -2250,7 +2346,7 @@ c-backward-sws
       ;; 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 (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 +2484,16 @@ c-backward-sws
 	      (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 5ae7e0f09d..a5e158933b 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -2158,9 +2158,11 @@ c-fl-decl-end
   ;; 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


-- 
Alan Mackenzie (Nuremberg, Germany).