aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Mackenzie2012-01-18 13:19:31 +0000
committerAlan Mackenzie2012-01-18 13:19:31 +0000
commit9657183b6f79dceb468bf70ce0980788dc3f0da7 (patch)
tree2707051d21c41e925d568246ee024ac94df7f0f2
parente8afb1265f8067d360f03c514603223cde92ffeb (diff)
downloademacs-9657183b6f79dceb468bf70ce0980788dc3f0da7.tar.gz
emacs-9657183b6f79dceb468bf70ce0980788dc3f0da7.zip
Eliminate sluggishness and hangs in fontification of "semicolon deserts".
cc-engine.el (c-state-nonlit-pos-interval): change value 10000 -> 3000. (c-state-safe-place): Reformulate so it doesn't stack up an infinite number of wrong entries in c-state-nonlit-pos-cache. (c-determine-limit-get-base, c-determine-limit): New functions to determine backward search limits disregarding literals. (c-find-decl-spots): Amend commenting. (c-cheap-inside-bracelist-p): New function which detects "={". cc-fonts.el (c-make-font-lock-BO-decl-search-function): Give a limit to a backward search. (c-font-lock-declarations): Fix an occurrence of point being undefined. Check additionally for point being in a bracelist or near a macro invocation without a semicolon so as to avoid a fruitless time consuming search for a declarator. Give a more precise search limit for declarators using the new c-determine-limit.
-rw-r--r--lisp/progmodes/cc-engine.el143
-rw-r--r--lisp/progmodes/cc-fonts.el48
2 files changed, 168 insertions, 23 deletions
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 2e0294341da..25344fe96a7 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -2074,7 +2074,7 @@ comment at the start of cc-engine.el for more info."
2074;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2074;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2075;; We maintain a simple cache of positions which aren't in a literal, so as to 2075;; We maintain a simple cache of positions which aren't in a literal, so as to
2076;; speed up testing for non-literality. 2076;; speed up testing for non-literality.
2077(defconst c-state-nonlit-pos-interval 10000) 2077(defconst c-state-nonlit-pos-interval 3000)
2078;; The approximate interval between entries in `c-state-nonlit-pos-cache'. 2078;; The approximate interval between entries in `c-state-nonlit-pos-cache'.
2079 2079
2080(defvar c-state-nonlit-pos-cache nil) 2080(defvar c-state-nonlit-pos-cache nil)
@@ -2129,7 +2129,7 @@ comment at the start of cc-engine.el for more info."
2129 (widen) 2129 (widen)
2130 (save-excursion 2130 (save-excursion
2131 (let ((c c-state-nonlit-pos-cache) 2131 (let ((c c-state-nonlit-pos-cache)
2132 pos npos lit) 2132 pos npos lit macro-beg)
2133 ;; Trim the cache to take account of buffer changes. 2133 ;; Trim the cache to take account of buffer changes.
2134 (while (and c (> (car c) c-state-nonlit-pos-cache-limit)) 2134 (while (and c (> (car c) c-state-nonlit-pos-cache-limit))
2135 (setq c (cdr c))) 2135 (setq c (cdr c)))
@@ -2139,16 +2139,32 @@ comment at the start of cc-engine.el for more info."
2139 (setq c (cdr c))) 2139 (setq c (cdr c)))
2140 (setq pos (or (car c) (point-min))) 2140 (setq pos (or (car c) (point-min)))
2141 2141
2142 (while (<= (setq npos (+ pos c-state-nonlit-pos-interval)) 2142 (while
2143 here) 2143 ;; Add an element to `c-state-nonlit-pos-cache' each iteration.
2144 (setq lit (car (cddr (c-state-pp-to-literal pos npos)))) 2144 (and
2145 (setq pos (or (cdr lit) npos)) ; end of literal containing npos. 2145 (<= (setq npos (+ pos c-state-nonlit-pos-interval)) here)
2146 (progn
2147 (setq lit (car (cddr (c-state-pp-to-literal pos npos))))
2148 (cond
2149 ((null lit)
2150 (setq pos npos)
2151 t)
2152 ((<= (cdr lit) here)
2153 (setq pos (cdr lit))
2154 t)
2155 (t
2156 (setq pos (car lit))
2157 nil))))
2158
2146 (goto-char pos) 2159 (goto-char pos)
2147 (when (and (c-beginning-of-macro) (/= (point) pos)) 2160 (when (and (c-beginning-of-macro) (/= (point) pos))
2148 (c-syntactic-end-of-macro) 2161 (setq macro-beg (point))
2149 (or (eobp) (forward-char)) 2162 (c-syntactic-end-of-macro)
2150 (setq pos (point))) 2163 (or (eobp) (forward-char))
2151 (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache))) 2164 (setq pos (if (<= (point) here)
2165 (point)
2166 macro-beg)))
2167 (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache)))
2152 2168
2153 (if (> pos c-state-nonlit-pos-cache-limit) 2169 (if (> pos c-state-nonlit-pos-cache-limit)
2154 (setq c-state-nonlit-pos-cache-limit pos)) 2170 (setq c-state-nonlit-pos-cache-limit pos))
@@ -4351,6 +4367,78 @@ comment at the start of cc-engine.el for more info."
4351 (t 'c))) ; Assuming the range is valid. 4367 (t 'c))) ; Assuming the range is valid.
4352 range)) 4368 range))
4353 4369
4370(defsubst c-determine-limit-get-base (start try-size)
4371 ;; Get a "safe place" approximately TRY-SIZE characters before START.
4372 ;; This doesn't preserve point.
4373 (let* ((pos (max (- start try-size) (point-min)))
4374 (base (c-state-safe-place pos))
4375 (s (parse-partial-sexp base pos)))
4376 (if (or (nth 4 s) (nth 3 s)) ; comment or string
4377 (nth 8 s)
4378 (point))))
4379
4380(defun c-determine-limit (how-far-back &optional start try-size)
4381 ;; Return a buffer position HOW-FAR-BACK non-literal characters from START
4382 ;; (default point). This is done by going back further in the buffer then
4383 ;; searching forward for literals. The position found won't be in a
4384 ;; literal. We start searching for the sought position TRY-SIZE (default
4385 ;; twice HOW-FAR-BACK) bytes back from START. This function must be fast.
4386 ;; :-)
4387 (save-excursion
4388 (let* ((start (or start (point)))
4389 (try-size (or try-size (* 2 how-far-back)))
4390 (base (c-determine-limit-get-base start try-size))
4391 (pos base)
4392
4393 (s (parse-partial-sexp pos pos)) ; null state.
4394 stack elt size
4395 (count 0))
4396 (while (< pos start)
4397 ;; Move forward one literal each time round this loop.
4398 ;; Move forward to the start of a comment or string.
4399 (setq s (parse-partial-sexp
4400 pos
4401 start
4402 nil ; target-depth
4403 nil ; stop-before
4404 s ; state
4405 'syntax-table)) ; stop-comment
4406
4407 ;; Gather details of the non-literal-bit - starting pos and size.
4408 (setq size (- (if (or (nth 4 s) (nth 3 s))
4409 (nth 8 s)
4410 (point))
4411 pos))
4412 (if (> size 0)
4413 (setq stack (cons (cons pos size) stack)))
4414
4415 ;; Move forward to the end of the comment/string.
4416 (if (or (nth 4 s) (nth 3 s))
4417 (setq s (parse-partial-sexp
4418 (point)
4419 start
4420 nil ; target-depth
4421 nil ; stop-before
4422 s ; state
4423 'syntax-table))) ; stop-comment
4424 (setq pos (point)))
4425
4426 ;; Now try and find enough non-literal characters recorded on the stack.
4427 ;; Go back one recorded literal each time round this loop.
4428 (while (and (< count how-far-back)
4429 stack)
4430 (setq elt (car stack)
4431 stack (cdr stack))
4432 (setq count (+ count (cdr elt))))
4433
4434 ;; Have we found enough yet?
4435 (cond
4436 ((>= count how-far-back)
4437 (+ (car elt) (- count how-far-back)))
4438 ((eq base (point-min))
4439 (point-min))
4440 (t
4441 (c-determine-limit (- how-far-back count) base try-size))))))
4354 4442
4355;; `c-find-decl-spots' and accompanying stuff. 4443;; `c-find-decl-spots' and accompanying stuff.
4356 4444
@@ -4487,13 +4575,14 @@ comment at the start of cc-engine.el for more info."
4487 ;; Call CFD-FUN for each possible spot for a declaration, cast or 4575 ;; Call CFD-FUN for each possible spot for a declaration, cast or
4488 ;; label from the point to CFD-LIMIT. 4576 ;; label from the point to CFD-LIMIT.
4489 ;; 4577 ;;
4490 ;; CFD-FUN is called with point at the start of the spot. It's 4578 ;; CFD-FUN is called with point at the start of the spot. It's passed two
4491 ;; passed two arguments: The first is the end position of the token 4579 ;; arguments: The first is the end position of the token preceding the spot,
4492 ;; preceding the spot, or 0 for the implicit match at bob. The 4580 ;; or 0 for the implicit match at bob. The second is a flag that is t when
4493 ;; second is a flag that is t when the match is inside a macro. If 4581 ;; the match is inside a macro. Point should be moved forward by at least
4494 ;; CFD-FUN adds `c-decl-end' properties somewhere below the current 4582 ;; one token.
4495 ;; spot, it should return non-nil to ensure that the next search 4583 ;;
4496 ;; will find them. 4584 ;; If CFD-FUN adds `c-decl-end' properties somewhere below the current spot,
4585 ;; it should return non-nil to ensure that the next search will find them.
4497 ;; 4586 ;;
4498 ;; Such a spot is: 4587 ;; Such a spot is:
4499 ;; o The first token after bob. 4588 ;; o The first token after bob.
@@ -4867,7 +4956,8 @@ comment at the start of cc-engine.el for more info."
4867 (goto-char cfd-continue-pos) 4956 (goto-char cfd-continue-pos)
4868 (if (= cfd-continue-pos cfd-limit) 4957 (if (= cfd-continue-pos cfd-limit)
4869 (setq cfd-match-pos cfd-limit) 4958 (setq cfd-match-pos cfd-limit)
4870 (c-find-decl-prefix-search))))) 4959 (c-find-decl-prefix-search))))) ; Moves point, sets cfd-continue-pos,
4960 ; cfd-match-pos, etc.
4871 4961
4872 4962
4873;; A cache for found types. 4963;; A cache for found types.
@@ -8047,6 +8137,23 @@ comment at the start of cc-engine.el for more info."
8047 next-open-brace (c-pull-open-brace paren-state))) 8137 next-open-brace (c-pull-open-brace paren-state)))
8048 open-brace)) 8138 open-brace))
8049 8139
8140(defun c-cheap-inside-bracelist-p (paren-state)
8141 ;; Return the position of the L-brace if point is inside a brace list
8142 ;; initialization of an array, etc. This is an approximate function,
8143 ;; designed for speed over accuracy. It will not find every bracelist, but
8144 ;; a non-nil result is reliable. We simply search for "= {" (naturally with
8145 ;; syntactic whitespace allowed). PAREN-STATE is the normal thing that it
8146 ;; is everywhere else.
8147 (let (b-pos)
8148 (save-excursion
8149 (while
8150 (and (setq b-pos (c-pull-open-brace paren-state))
8151 (progn (goto-char b-pos)
8152 (c-backward-sws)
8153 (c-backward-token-2)
8154 (not (looking-at "=")))))
8155 b-pos)))
8156
8050(defun c-inside-bracelist-p (containing-sexp paren-state) 8157(defun c-inside-bracelist-p (containing-sexp paren-state)
8051 ;; return the buffer position of the beginning of the brace list 8158 ;; return the buffer position of the beginning of the brace list
8052 ;; statement if we're inside a brace list, otherwise return nil. 8159 ;; statement if we're inside a brace list, otherwise return nil.
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index e7d00815708..2d116e1ecdc 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -446,10 +446,12 @@
446 ;; `parse-sexp-lookup-properties' (when it exists). 446 ;; `parse-sexp-lookup-properties' (when it exists).
447 (parse-sexp-lookup-properties 447 (parse-sexp-lookup-properties
448 (cc-eval-when-compile 448 (cc-eval-when-compile
449 (boundp 'parse-sexp-lookup-properties)))) 449 (boundp 'parse-sexp-lookup-properties)))
450 (BOD-limit
451 (c-determine-limit 1000)))
450 (goto-char 452 (goto-char
451 (let ((here (point))) 453 (let ((here (point)))
452 (if (eq (car (c-beginning-of-decl-1)) 'same) 454 (if (eq (car (c-beginning-of-decl-1 BOD-limit)) 'same)
453 (point) 455 (point)
454 here))) 456 here)))
455 ,(c-make-font-lock-search-form regexp highlights)) 457 ,(c-make-font-lock-search-form regexp highlights))
@@ -1240,6 +1242,7 @@ casts and declarations are fontified. Used on level 2 and higher."
1240 ;; it finds any. That's necessary so that we later will 1242 ;; it finds any. That's necessary so that we later will
1241 ;; stop inside them to fontify types there. 1243 ;; stop inside them to fontify types there.
1242 (c-parse-and-markup-<>-arglists t) 1244 (c-parse-and-markup-<>-arglists t)
1245 lbrace ; position of some {.
1243 ;; The font-lock package in Emacs is known to clobber 1246 ;; The font-lock package in Emacs is known to clobber
1244 ;; `parse-sexp-lookup-properties' (when it exists). 1247 ;; `parse-sexp-lookup-properties' (when it exists).
1245 (parse-sexp-lookup-properties 1248 (parse-sexp-lookup-properties
@@ -1351,7 +1354,6 @@ casts and declarations are fontified. Used on level 2 and higher."
1351 (or (looking-at c-typedef-key) 1354 (or (looking-at c-typedef-key)
1352 (goto-char start-pos))) 1355 (goto-char start-pos)))
1353 1356
1354 ;; Now analyze the construct.
1355 ;; In QT, "more" is an irritating keyword that expands to nothing. 1357 ;; In QT, "more" is an irritating keyword that expands to nothing.
1356 ;; We skip over it to prevent recognition of "more slots: <symbol>" 1358 ;; We skip over it to prevent recognition of "more slots: <symbol>"
1357 ;; as a bitfield declaration. 1359 ;; as a bitfield declaration.
@@ -1360,6 +1362,8 @@ casts and declarations are fontified. Used on level 2 and higher."
1360 (concat "\\(more\\)\\([^" c-symbol-chars "]\\|$\\)"))) 1362 (concat "\\(more\\)\\([^" c-symbol-chars "]\\|$\\)")))
1361 (goto-char (match-end 1)) 1363 (goto-char (match-end 1))
1362 (c-forward-syntactic-ws)) 1364 (c-forward-syntactic-ws))
1365
1366 ;; Now analyze the construct.
1363 (setq decl-or-cast (c-forward-decl-or-cast-1 1367 (setq decl-or-cast (c-forward-decl-or-cast-1
1364 match-pos context last-cast-end)) 1368 match-pos context last-cast-end))
1365 1369
@@ -1428,6 +1432,39 @@ casts and declarations are fontified. Used on level 2 and higher."
1428 (c-fontify-recorded-types-and-refs) 1432 (c-fontify-recorded-types-and-refs)
1429 nil) 1433 nil)
1430 1434
1435 ;; Restore point, since at this point in the code it has been
1436 ;; left undefined by c-forward-decl-or-cast-1 above.
1437 ((progn (goto-char start-pos) nil))
1438
1439 ;; If point is inside a bracelist, there's no point checking it
1440 ;; being at a declarator.
1441 ((let ((paren-state (c-parse-state)))
1442 (setq lbrace (c-cheap-inside-bracelist-p paren-state)))
1443 ;; Move past this bracelist to prevent an endless loop.
1444 (goto-char lbrace)
1445 (unless (c-safe (progn (forward-list) t))
1446 (goto-char start-pos)
1447 (c-forward-token-2))
1448 nil)
1449
1450 ;; If point is just after a ")" which is followed by an
1451 ;; identifier which isn't a label, or at the matching "(", we're
1452 ;; at either a macro invocation, a cast, or a
1453 ;; for/while/etc. statement. The cast case is handled above.
1454 ;; None of these cases can contain a declarator.
1455 ((or (and (eq (char-before match-pos) ?\))
1456 (c-on-identifier)
1457 (save-excursion (not (c-forward-label))))
1458 (and (eq (char-after) ?\()
1459 (save-excursion
1460 (and
1461 (progn (c-backward-token-2) (c-on-identifier))
1462 (save-excursion (not (c-forward-label)))
1463 (progn (c-backward-token-2)
1464 (eq (char-after) ?\())))))
1465 (c-forward-token-2) ; Must prevent looping.
1466 nil)
1467
1431 ((and (not c-enums-contain-decls) 1468 ((and (not c-enums-contain-decls)
1432 ;; An optimization quickly to eliminate scans of long enum 1469 ;; An optimization quickly to eliminate scans of long enum
1433 ;; declarations in the next cond arm. 1470 ;; declarations in the next cond arm.
@@ -1441,13 +1478,14 @@ casts and declarations are fontified. Used on level 2 and higher."
1441 (progn 1478 (progn
1442 (c-backward-token-2) 1479 (c-backward-token-2)
1443 (looking-at c-brace-list-key))))))) 1480 (looking-at c-brace-list-key)))))))
1444 t) 1481 (c-forward-token-2)
1482 nil)
1445 1483
1446 (t 1484 (t
1447 ;; Are we at a declarator? Try to go back to the declaration 1485 ;; Are we at a declarator? Try to go back to the declaration
1448 ;; to check this. If we get there, check whether a "typedef" 1486 ;; to check this. If we get there, check whether a "typedef"
1449 ;; is there, then fontify the declarators accordingly. 1487 ;; is there, then fontify the declarators accordingly.
1450 (let ((decl-search-lim (max (- (point) 50000) (point-min))) 1488 (let ((decl-search-lim (c-determine-limit 1000))
1451 paren-state bod-res encl-pos is-typedef 1489 paren-state bod-res encl-pos is-typedef
1452 c-recognize-knr-p) ; Strictly speaking, bogus, but it 1490 c-recognize-knr-p) ; Strictly speaking, bogus, but it
1453 ; speeds up lisp.h tremendously. 1491 ; speeds up lisp.h tremendously.