aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Mackenzie2017-03-30 20:24:39 +0000
committerAlan Mackenzie2017-03-30 20:24:39 +0000
commitef7df187eb0b631a6909bdc02f82b3dfef0ad689 (patch)
treee37b293633b0d65f3ea2f21125021ae99bf0dc92
parent6ff870218dd4bc015cc4115ceb2febd8d807e57c (diff)
downloademacs-ef7df187eb0b631a6909bdc02f82b3dfef0ad689.tar.gz
emacs-ef7df187eb0b631a6909bdc02f82b3dfef0ad689.zip
Fix C++ fontification problems 500 bytes after typing a space, and other bugs
Also implement the "asymmetric space" rule for fontifying otherwise ambiguous declarations/expressions. * lisp/progmodes/cc-engine.el (c-before-change-check-<>-operators): Don't set c-new-BEG or c-new-END when there is no need. (c-forward-decl-or-cast-1): Add "CASE 17.5" to implement the "asymmetric space" rule. * lisp/progmodes/cc-fonts.el (c-get-fontification-context): New function, extracted from c-font-lock-declarations. Add to this function processing to make `context' 'decl for lines contained within parens when these are also declarations. (c-font-lock-declarations): Call the newly extracted function above in place of inline code. * lisp/progmodes/cc-mode.el (c-fl-decl-start): Set point before calling c-literal-start. * lisp/progmodes/cc-vars.el (c-asymmetry-fontification-flag): New user option. * doc/misc/cc-mode.texi (Misc Font Locking): New node documenting the new "asymmetric fontification" rule, including the variable c-asymmetric-fontification-flag.
-rw-r--r--doc/misc/cc-mode.texi60
-rw-r--r--lisp/progmodes/cc-engine.el32
-rw-r--r--lisp/progmodes/cc-fonts.el216
-rw-r--r--lisp/progmodes/cc-mode.el1
-rw-r--r--lisp/progmodes/cc-vars.el12
5 files changed, 225 insertions, 96 deletions
diff --git a/doc/misc/cc-mode.texi b/doc/misc/cc-mode.texi
index a29873b03b3..91e20fa7247 100644
--- a/doc/misc/cc-mode.texi
+++ b/doc/misc/cc-mode.texi
@@ -274,6 +274,7 @@ Font Locking
274* Font Locking Preliminaries:: 274* Font Locking Preliminaries::
275* Faces:: 275* Faces::
276* Doc Comments:: 276* Doc Comments::
277* Misc Font Locking::
277* AWK Mode Font Locking:: 278* AWK Mode Font Locking::
278 279
279Configuration Basics 280Configuration Basics
@@ -1821,6 +1822,7 @@ sections apply to the other languages.
1821* Font Locking Preliminaries:: 1822* Font Locking Preliminaries::
1822* Faces:: 1823* Faces::
1823* Doc Comments:: 1824* Doc Comments::
1825* Misc Font Locking::
1824* AWK Mode Font Locking:: 1826* AWK Mode Font Locking::
1825@end menu 1827@end menu
1826 1828
@@ -2023,7 +2025,7 @@ since those aren't syntactic errors in themselves.
2023 2025
2024 2026
2025@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 2027@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2026@node Doc Comments, AWK Mode Font Locking, Faces, Font Locking 2028@node Doc Comments, Misc Font Locking, Faces, Font Locking
2027@comment node-name, next, previous, up 2029@comment node-name, next, previous, up
2028@section Documentation Comments 2030@section Documentation Comments
2029@cindex documentation comments 2031@cindex documentation comments
@@ -2099,9 +2101,63 @@ initialization and the result is prepended. For an example, see
2099If you add support for another doc comment style, please consider 2101If you add support for another doc comment style, please consider
2100contributing it: send a note to @email{bug-cc-mode@@gnu.org}. 2102contributing it: send a note to @email{bug-cc-mode@@gnu.org}.
2101 2103
2104@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2105@node Misc Font Locking, AWK Mode Font Locking, Doc Comments, Font Locking
2106@comment node-name, next, previous, up
2107@section Miscellaneous Font Locking
2108@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2109
2110In some languages, particularly in C++, there are constructs which are
2111syntactically ambiguous---they could be either declarations or
2112expressions, and @ccmode{} cannot tell for sure which. Often such a
2113construct is one of the operators @samp{*} or @samp{&} surrounded by
2114two identifiers.
2115
2116Experience shows that very often when such a construct is a
2117declaration it will be written with the operator touching exactly one
2118of the identifiers, like:
2119
2120@example
2121foo *bar
2122@end example
2123or
2124@example
2125foo& bar
2126@end example
2127
2128. Whether such code is fontified depends on the setting of
2129@code{c-asymmetry-fontification-flag}.
2130
2131@defvar c-asymmetry-fontification-flag
2132@vindex asymmetry-fontification-flag (c-)
2133When @code{c-asymmetry-fontification-flag} is non-nil (which it is by
2134default), code like the above, with white space either before or after
2135the operator, but not both, is fontified as a declaration. When the
2136variable is nil, such a construct gets the default face.
2137@end defvar
2138
2139When the construct is an expression there will often be white space
2140both before and after the operator or there will be no white space
2141around it at all, like:
2142
2143@example
2144foo * bar
2145@end example
2146or
2147@example
2148foo&bar
2149@end example
2150.
2151
2152Such code is not fontified as a declaration. (Typically, the
2153identifiers don't get a non-default face.)
2154
2155For clarity's sake, we emphasize that the ``asymmetry'' rule in this
2156section only applies when CC Mode cannot disambiguate a construct in
2157any other way.
2102 2158
2103@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 2159@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2104@node AWK Mode Font Locking, , Doc Comments, Font Locking 2160@node AWK Mode Font Locking, , Misc Font Locking, Font Locking
2105@comment node-name, next, previous, up 2161@comment node-name, next, previous, up
2106@section AWK Mode Font Locking 2162@section AWK Mode Font Locking
2107@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 2163@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index bdc77dc5028..de15d1d82fc 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -6243,9 +6243,9 @@ comment at the start of cc-engine.el for more info."
6243 (eq (char-before) ?<)) 6243 (eq (char-before) ?<))
6244 (c-backward-token-2) 6244 (c-backward-token-2)
6245 (when (eq (char-after) ?<) 6245 (when (eq (char-after) ?<)
6246 (c-clear-<-pair-props-if-match-after beg))) 6246 (c-clear-<-pair-props-if-match-after beg)
6247 (setq new-beg (point))))
6247 (c-forward-syntactic-ws) 6248 (c-forward-syntactic-ws)
6248 (setq new-beg (point))
6249 6249
6250 ;; ...Then the ones with < before end and > after end. 6250 ;; ...Then the ones with < before end and > after end.
6251 (goto-char (if end-lit-limits (cdr end-lit-limits) end)) 6251 (goto-char (if end-lit-limits (cdr end-lit-limits) end))
@@ -6254,9 +6254,9 @@ comment at the start of cc-engine.el for more info."
6254 (eq (char-before) ?>)) 6254 (eq (char-before) ?>))
6255 (c-end-of-current-token) 6255 (c-end-of-current-token)
6256 (when (eq (char-before) ?>) 6256 (when (eq (char-before) ?>)
6257 (c-clear->-pair-props-if-match-before end (1- (point))))) 6257 (c-clear->-pair-props-if-match-before end (1- (point)))
6258 (setq new-end (point))))
6258 (c-backward-syntactic-ws) 6259 (c-backward-syntactic-ws)
6259 (setq new-end (point))
6260 6260
6261 ;; Extend the fontification region, if needed. 6261 ;; Extend the fontification region, if needed.
6262 (and new-beg 6262 (and new-beg
@@ -8863,7 +8863,29 @@ comment at the start of cc-engine.el for more info."
8863 ;; it as a declaration if "a" has been used as a type 8863 ;; it as a declaration if "a" has been used as a type
8864 ;; somewhere else (if it's a known type we won't get here). 8864 ;; somewhere else (if it's a known type we won't get here).
8865 (setq maybe-expression t) 8865 (setq maybe-expression t)
8866 (throw 'at-decl-or-cast t))) 8866 (throw 'at-decl-or-cast t))
8867
8868 ;; CASE 17.5
8869 (when (and c-asymmetry-fontification-flag
8870 got-prefix-before-parens
8871 at-type
8872 (or (not got-suffix)
8873 at-decl-start))
8874 (let ((space-before-id
8875 (save-excursion
8876 (goto-char name-start)
8877 (or (bolp) (memq (char-before) '(?\ ?\t)))))
8878 (space-after-type
8879 (save-excursion
8880 (goto-char type-start)
8881 (and (c-forward-type)
8882 (progn (c-backward-syntactic-ws) t)
8883 (or (eolp)
8884 (memq (char-after) '(?\ ?\t)))))))
8885 (when (not (eq (not space-before-id)
8886 (not space-after-type)))
8887 (setq maybe-expression t)
8888 (throw 'at-decl-or-cast t)))))
8867 8889
8868 ;; CASE 18 8890 ;; CASE 18
8869 (when (and (not (memq context '(nil top))) 8891 (when (and (not (memq context '(nil top)))
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index f623b9f3332..923f077b411 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -1117,6 +1117,124 @@ casts and declarations are fontified. Used on level 2 and higher."
1117 (setq pos (point)))))) ; acts to make the `while' form continue. 1117 (setq pos (point)))))) ; acts to make the `while' form continue.
1118 nil) 1118 nil)
1119 1119
1120(defun c-get-fontification-context (match-pos not-front-decl &optional toplev)
1121 ;; Return a cons (CONTEXT . RESTRICTED-<>-ARGLISTS) for MATCH-POS.
1122 ;; NOT-FRONT-DECL is non-nil when a declaration later in the buffer than
1123 ;; MATCH-POS has already been parsed. TOPLEV is non-nil when MATCH-POS is
1124 ;; known to be at "top level", i.e. outside any braces, or directly inside a
1125 ;; namespace, class, etc.
1126 ;;
1127 ;; CONTEXT is the fontification context of MATCH-POS, and is one of the
1128 ;; following:
1129 ;; 'decl In a comma-separated declaration context (typically
1130 ;; inside a function declaration arglist).
1131 ;; '<> In an angle bracket arglist.
1132 ;; 'arglist Some other type of arglist.
1133 ;; 'top Some other context and point is at the top-level (either
1134 ;; outside any braces or directly inside a class or namespace,
1135 ;; etc.)
1136 ;; nil Some other context or unknown context. Includes
1137 ;; within the parens of an if, for, ... construct.
1138 ;; 'not-decl Definitely not in a declaration.
1139 ;;
1140 ;; RESTRICTED-<>-ARGLISTS is non-nil when a scan of template/generic
1141 ;; arguments lists (i.e. lists enclosed by <...>) is more strict about what
1142 ;; characters it allows within the list.
1143 (let ((type (and (> match-pos (point-min))
1144 (c-get-char-property (1- match-pos) 'c-type))))
1145 (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?< ?{)))
1146 (cons (and toplev 'top) nil))
1147 ;; A control flow expression or a decltype
1148 ((and (eq (char-before match-pos) ?\()
1149 (save-excursion
1150 (goto-char match-pos)
1151 (backward-char)
1152 (c-backward-token-2)
1153 (or (looking-at c-block-stmt-2-key)
1154 (looking-at c-block-stmt-1-2-key)
1155 (looking-at c-typeof-key))))
1156 (cons nil t))
1157 ;; Near BOB.
1158 ((<= match-pos (point-min))
1159 (cons 'arglist t))
1160 ;; Got a cached hit in a declaration arglist.
1161 ((eq type 'c-decl-arg-start)
1162 (cons 'decl nil))
1163 ;; We're inside (probably) a brace list.
1164 ((eq type 'c-not-decl)
1165 (cons 'not-decl nil))
1166 ;; Inside a C++11 lambda function arglist.
1167 ((and (c-major-mode-is 'c++-mode)
1168 (eq (char-before match-pos) ?\()
1169 (save-excursion
1170 (goto-char match-pos)
1171 (c-backward-token-2)
1172 (and
1173 (c-safe (goto-char (scan-sexps (point) -1)))
1174 (c-looking-at-c++-lambda-capture-list))))
1175 (c-put-char-property (1- match-pos) 'c-type
1176 'c-decl-arg-start)
1177 (cons 'decl nil))
1178 ;; We're inside a brace list.
1179 ((and (eq (char-before match-pos) ?{)
1180 (save-excursion
1181 (goto-char (1- match-pos))
1182 (consp
1183 (c-looking-at-or-maybe-in-bracelist))))
1184 (c-put-char-property (1- match-pos) 'c-type
1185 'c-not-decl)
1186 (cons 'not-decl nil))
1187 ;; We're inside an "ordinary" open brace.
1188 ((eq (char-before match-pos) ?{)
1189 (cons (and toplev 'top) nil))
1190 ;; Inside an angle bracket arglist.
1191 ((or (eq type 'c-<>-arg-sep)
1192 (eq (char-before match-pos) ?<))
1193 (cons '<> nil))
1194 ;; Got a cached hit in some other type of arglist.
1195 (type
1196 (cons 'arglist t))
1197 (not-front-decl
1198 ;; The point is within the range of a previously
1199 ;; encountered type decl expression, so the arglist
1200 ;; is probably one that contains declarations.
1201 ;; However, if `c-recognize-paren-inits' is set it
1202 ;; might also be an initializer arglist.
1203 ;;
1204 ;; The result of this check is cached with a char
1205 ;; property on the match token, so that we can look
1206 ;; it up again when refontifying single lines in a
1207 ;; multiline declaration.
1208 (c-put-char-property (1- match-pos)
1209 'c-type 'c-decl-arg-start)
1210 (cons 'decl nil))
1211 ;; Got an open paren preceded by an arith operator.
1212 ((and (eq (char-before match-pos) ?\()
1213 (save-excursion
1214 (and (zerop (c-backward-token-2 2))
1215 (looking-at c-arithmetic-op-regexp))))
1216 (cons nil nil))
1217 ;; At start of a declaration inside a declaration paren.
1218 ((save-excursion
1219 (and (memq (char-before match-pos) '(?\( ?\,))
1220 (c-go-up-list-backward match-pos)
1221 (eq (char-after) ?\()
1222 (let ((type (c-get-char-property (point) 'c-type)))
1223 (or (memq type '(c-decl-arg-start c-decl-type-start))
1224 (and
1225 (progn (c-backward-syntactic-ws) t)
1226 (c-back-over-compound-identifier)
1227 (progn
1228 (c-backward-syntactic-ws)
1229 (or (bobp)
1230 (progn
1231 (setq type (c-get-char-property (1- (point))
1232 'c-type))
1233 (memq type '(c-decl-arg-start
1234 c-decl-type-start))))))))))
1235 (cons 'decl nil))
1236 (t (cons 'arglist t)))))
1237
1120(defun c-font-lock-declarations (limit) 1238(defun c-font-lock-declarations (limit)
1121 ;; Fontify all the declarations, casts and labels from the point to LIMIT. 1239 ;; Fontify all the declarations, casts and labels from the point to LIMIT.
1122 ;; Assumes that strings and comments have been fontified already. 1240 ;; Assumes that strings and comments have been fontified already.
@@ -1231,95 +1349,15 @@ casts and declarations are fontified. Used on level 2 and higher."
1231 ;; "<" for the sake of C++-style template arglists. 1349 ;; "<" for the sake of C++-style template arglists.
1232 ;; Ignore "(" when it's part of a control flow construct 1350 ;; Ignore "(" when it's part of a control flow construct
1233 ;; (e.g. "for ("). 1351 ;; (e.g. "for (").
1234 (let ((type (and (> match-pos (point-min)) 1352 (let ((got-context
1235 (c-get-char-property (1- match-pos) 'c-type)))) 1353 (c-get-fontification-context
1236 (cond ((not (memq (char-before match-pos) '(?\( ?, ?\[ ?< ?{))) 1354 match-pos
1237 (setq context (and toplev 'top) 1355 (< match-pos (if inside-macro
1238 c-restricted-<>-arglists nil)) 1356 max-type-decl-end-before-token
1239 ;; A control flow expression or a decltype 1357 max-type-decl-end))
1240 ((and (eq (char-before match-pos) ?\() 1358 toplev)))
1241 (save-excursion 1359 (setq context (car got-context)
1242 (goto-char match-pos) 1360 c-restricted-<>-arglists (cdr got-context)))
1243 (backward-char)
1244 (c-backward-token-2)
1245 (or (looking-at c-block-stmt-2-key)
1246 (looking-at c-block-stmt-1-2-key)
1247 (looking-at c-typeof-key))))
1248 (setq context nil
1249 c-restricted-<>-arglists t))
1250 ;; Near BOB.
1251 ((<= match-pos (point-min))
1252 (setq context 'arglist
1253 c-restricted-<>-arglists t))
1254 ;; Got a cached hit in a declaration arglist.
1255 ((eq type 'c-decl-arg-start)
1256 (setq context 'decl
1257 c-restricted-<>-arglists nil))
1258 ;; We're inside (probably) a brace list.
1259 ((eq type 'c-not-decl)
1260 (setq context 'not-decl
1261 c-restricted-<>-arglists nil))
1262 ;; Inside a C++11 lambda function arglist.
1263 ((and (c-major-mode-is 'c++-mode)
1264 (eq (char-before match-pos) ?\()
1265 (save-excursion
1266 (goto-char match-pos)
1267 (c-backward-token-2)
1268 (and
1269 (c-safe (goto-char (scan-sexps (point) -1)))
1270 (c-looking-at-c++-lambda-capture-list))))
1271 (setq context 'decl
1272 c-restricted-<>-arglists nil)
1273 (c-put-char-property (1- match-pos) 'c-type
1274 'c-decl-arg-start))
1275 ;; We're inside a brace list.
1276 ((and (eq (char-before match-pos) ?{)
1277 (save-excursion
1278 (goto-char (1- match-pos))
1279 (consp
1280 (c-looking-at-or-maybe-in-bracelist))))
1281 (setq context 'not-decl
1282 c-restricted-<>-arglists nil)
1283 (c-put-char-property (1- match-pos) 'c-type
1284 'c-not-decl))
1285 ;; We're inside an "ordinary" open brace.
1286 ((eq (char-before match-pos) ?{)
1287 (setq context (and toplev 'top)
1288 c-restricted-<>-arglists nil))
1289 ;; Inside an angle bracket arglist.
1290 ((or (eq type 'c-<>-arg-sep)
1291 (eq (char-before match-pos) ?<))
1292 (setq context '<>
1293 c-restricted-<>-arglists nil))
1294 ;; Got a cached hit in some other type of arglist.
1295 (type
1296 (setq context 'arglist
1297 c-restricted-<>-arglists t))
1298 ((if inside-macro
1299 (< match-pos max-type-decl-end-before-token)
1300 (< match-pos max-type-decl-end))
1301 ;; The point is within the range of a previously
1302 ;; encountered type decl expression, so the arglist
1303 ;; is probably one that contains declarations.
1304 ;; However, if `c-recognize-paren-inits' is set it
1305 ;; might also be an initializer arglist.
1306 (setq context 'decl
1307 c-restricted-<>-arglists nil)
1308 ;; The result of this check is cached with a char
1309 ;; property on the match token, so that we can look
1310 ;; it up again when refontifying single lines in a
1311 ;; multiline declaration.
1312 (c-put-char-property (1- match-pos)
1313 'c-type 'c-decl-arg-start))
1314 ;; Got an open paren preceded by an arith operator.
1315 ((and (eq (char-before match-pos) ?\()
1316 (save-excursion
1317 (and (zerop (c-backward-token-2 2))
1318 (looking-at c-arithmetic-op-regexp))))
1319 (setq context nil
1320 c-restricted-<>-arglists nil))
1321 (t (setq context 'arglist
1322 c-restricted-<>-arglists t))))
1323 1361
1324 ;; Check we haven't missed a preceding "typedef". 1362 ;; Check we haven't missed a preceding "typedef".
1325 (when (not (looking-at c-typedef-key)) 1363 (when (not (looking-at c-typedef-key))
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index 8326e6a6f29..20c63d4dbe2 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -1363,6 +1363,7 @@ Note that the style variables are always made local to the buffer."
1363 ;; This function is called indirectly from font locking stuff - either from 1363 ;; This function is called indirectly from font locking stuff - either from
1364 ;; c-after-change (to prepare for after-change font-locking) or from font 1364 ;; c-after-change (to prepare for after-change font-locking) or from font
1365 ;; lock context (etc.) fontification. 1365 ;; lock context (etc.) fontification.
1366 (goto-char pos)
1366 (let ((lit-start (c-literal-start)) 1367 (let ((lit-start (c-literal-start))
1367 (new-pos pos) 1368 (new-pos pos)
1368 capture-opener 1369 capture-opener
diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el
index 1114b21381d..ccd4fd29940 100644
--- a/lisp/progmodes/cc-vars.el
+++ b/lisp/progmodes/cc-vars.el
@@ -1634,6 +1634,18 @@ names)."))
1634 :type 'c-extra-types-widget 1634 :type 'c-extra-types-widget
1635 :group 'c) 1635 :group 'c)
1636 1636
1637(defcustom c-asymmetry-fontification-flag t
1638 "Whether to fontify certain ambiguous constructs by white space asymmetry.
1639
1640In the fontification engine, it is sometimes impossible to determine
1641whether a construct is a declaration or an expression. This happens
1642particularly in C++, due to ambiguities in the language. When such a
1643construct is like \"foo * bar\" or \"foo &bar\", and this variable is non-nil
1644(the default), the construct will be fontified as a declaration if there is
1645white space either before or after the operator, but not both."
1646 :type 'boolean
1647 :group 'c)
1648
1637(defvar c-noise-macro-with-parens-name-re "\\<\\>") 1649(defvar c-noise-macro-with-parens-name-re "\\<\\>")
1638(defvar c-noise-macro-name-re "\\<\\>") 1650(defvar c-noise-macro-name-re "\\<\\>")
1639 1651