aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Mackenzie2016-01-22 22:31:23 +0000
committerAlan Mackenzie2016-01-22 22:31:23 +0000
commitbbbb038654eab73624a5d51faa52f2d3f5db14b5 (patch)
tree60ec0e1a51aebf7d6060e9b469a45e815e8ae235
parent6ff8b45f18619c2dc95dfb1d92a5c48b14049973 (diff)
downloademacs-bbbb038654eab73624a5d51faa52f2d3f5db14b5.tar.gz
emacs-bbbb038654eab73624a5d51faa52f2d3f5db14b5.zip
Prevent spurious recognition of K&R argument declarations. Fixes bug #2203
* cc-engine.el (c-forward-declarator): New function. (c-in-knr-argdecl): Before recognizing a K&R argument declaration, check it is contained in the preceding arg list. * cc-fonts.el (c-font-lock-declarators): Use the new function `c-forward-declarator' in place of inline code.
-rw-r--r--lisp/progmodes/cc-engine.el171
-rw-r--r--lisp/progmodes/cc-fonts.el93
2 files changed, 168 insertions, 96 deletions
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 63f01829845..8113446e4d3 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -6808,6 +6808,110 @@ comment at the start of cc-engine.el for more info."
6808 ;; This identifier is bound only in the inner let. 6808 ;; This identifier is bound only in the inner let.
6809 '(setq start id-start)))) 6809 '(setq start id-start))))
6810 6810
6811(defun c-forward-declarator (&optional limit)
6812 ;; Assuming point is at the start of a declarator, move forward over it,
6813 ;; leaving point at the next token after it (e.g. a ) or a ; or a ,).
6814 ;;
6815 ;; Return a list (ID-START ID-END BRACKETS-AFTER-ID GOT-INIT), where ID-START and
6816 ;; ID-END are the bounds of the declarator's identifier, and
6817 ;; BRACKETS-AFTER-ID is non-nil if a [...] pair is present after the id.
6818 ;; GOT-INIT is non-nil when the declarator is followed by "=" or "(".
6819 ;;
6820 ;; If no declarator is found, leave point unmoved and return nil. LIMIT is
6821 ;; an optional limit for forward searching.
6822 ;;
6823 ;; Note that the global variable `c-last-identifier-range' is written to, so
6824 ;; the caller should bind it if necessary.
6825
6826 ;; Inside the following "condition form", we move forward over the
6827 ;; declarator's identifier up as far as any opening bracket (for array
6828 ;; size) or paren (for parameters of function-type) or brace (for
6829 ;; array/struct initialization) or "=" or terminating delimiter
6830 ;; (e.g. "," or ";" or "}").
6831 (let ((here (point))
6832 id-start id-end brackets-after-id paren-depth)
6833 (or limit (setq limit (point-max)))
6834 (if (and
6835 (< (point) limit)
6836
6837 ;; The following form moves forward over the declarator's
6838 ;; identifier (and what precedes it), returning t. If there
6839 ;; wasn't one, it returns nil.
6840 (let (got-identifier)
6841 (setq paren-depth 0)
6842 ;; Skip over type decl prefix operators, one for each iteration
6843 ;; of the while. These are, e.g. "*" in "int *foo" or "(" and
6844 ;; "*" in "int (*foo) (void)" (Note similar code in
6845 ;; `c-forward-decl-or-cast-1'.)
6846 (while (and (looking-at c-type-decl-prefix-key)
6847 (if (and (c-major-mode-is 'c++-mode)
6848 (match-beginning 3))
6849 ;; If the third submatch matches in C++ then
6850 ;; we're looking at an identifier that's a
6851 ;; prefix only if it specifies a member pointer.
6852 (progn
6853 (setq id-start (point))
6854 (c-forward-name)
6855 (if (looking-at "\\(::\\)")
6856 ;; We only check for a trailing "::" and
6857 ;; let the "*" that should follow be
6858 ;; matched in the next round.
6859 t
6860 ;; It turned out to be the real identifier,
6861 ;; so flag that and stop.
6862 (setq got-identifier t)
6863 nil))
6864 t))
6865 (if (eq (char-after) ?\()
6866 (progn
6867 (setq paren-depth (1+ paren-depth))
6868 (forward-char))
6869 (goto-char (match-end 1)))
6870 (c-forward-syntactic-ws))
6871
6872 ;; If we haven't passed the identifier already, do it now.
6873 (unless got-identifier
6874 (setq id-start (point))
6875 (c-forward-name))
6876 (prog1
6877 (/= (point) here)
6878 (save-excursion
6879 (c-backward-syntactic-ws)
6880 (setq id-end (point)))))
6881
6882 ;; Skip out of the parens surrounding the identifier. If closing
6883 ;; parens are missing, this form returns nil.
6884 (or (= paren-depth 0)
6885 (c-safe (goto-char (scan-lists (point) 1 paren-depth))))
6886
6887 (<= (point) limit)
6888
6889 ;; Skip over any trailing bit, such as "__attribute__".
6890 (progn
6891 (when (looking-at c-decl-hangon-key)
6892 (c-forward-keyword-clause 1))
6893 (<= (point) limit))
6894
6895 ;; Search syntactically to the end of the declarator (";",
6896 ;; ",", a closing paren, eob etc) or to the beginning of an
6897 ;; initializer or function prototype ("=" or "\\s\(").
6898 ;; Note that square brackets are now not also treated as
6899 ;; initializers, since this broke when there were also
6900 ;; initializing brace lists.
6901 (let (found)
6902 (while
6903 (and (setq found (c-syntactic-re-search-forward
6904 "[;,]\\|\\s)\\|\\'\\|\\(=\\|\\s(\\)" limit t t))
6905 (eq (char-before) ?\[)
6906 (c-go-up-list-forward))
6907 (setq brackets-after-id t))
6908 (backward-char)
6909 found))
6910 (list id-start id-end brackets-after-id (match-beginning 1))
6911
6912 (goto-char here)
6913 nil)))
6914
6811(defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end) 6915(defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end)
6812 ;; Move forward over a declaration or a cast if at the start of one. 6916 ;; Move forward over a declaration or a cast if at the start of one.
6813 ;; The point is assumed to be at the start of some token. Nil is 6917 ;; The point is assumed to be at the start of some token. Nil is
@@ -8162,14 +8266,14 @@ comment at the start of cc-engine.el for more info."
8162 ;; Return the position of the first argument declaration if point is 8266 ;; Return the position of the first argument declaration if point is
8163 ;; inside a K&R style argument declaration list, nil otherwise. 8267 ;; inside a K&R style argument declaration list, nil otherwise.
8164 ;; `c-recognize-knr-p' is not checked. If LIM is non-nil, it's a 8268 ;; `c-recognize-knr-p' is not checked. If LIM is non-nil, it's a
8165 ;; position that bounds the backward search for the argument list. 8269 ;; position that bounds the backward search for the argument list. This
8270 ;; function doesn't move point.
8166 ;; 8271 ;;
8167 ;; Point must be within a possible K&R region, e.g. just before a top-level 8272 ;; Point must be within a possible K&R region, e.g. just before a top-level
8168 ;; "{". It must be outside of parens and brackets. The test can return 8273 ;; "{". It must be outside of parens and brackets. The test can return
8169 ;; false positives otherwise. 8274 ;; false positives otherwise.
8170 ;; 8275 ;;
8171 ;; This function might do hidden buffer changes. 8276 ;; This function might do hidden buffer changes.
8172
8173 (save-excursion 8277 (save-excursion
8174 (save-restriction 8278 (save-restriction
8175 ;; If we're in a macro, our search range is restricted to it. Narrow to 8279 ;; If we're in a macro, our search range is restricted to it. Narrow to
@@ -8178,8 +8282,12 @@ comment at the start of cc-engine.el for more info."
8178 (macro-end (save-excursion (and macro-start (c-end-of-macro) (point)))) 8282 (macro-end (save-excursion (and macro-start (c-end-of-macro) (point))))
8179 (low-lim (max (or lim (point-min)) (or macro-start (point-min)))) 8283 (low-lim (max (or lim (point-min)) (or macro-start (point-min))))
8180 before-lparen after-rparen 8284 before-lparen after-rparen
8181 (pp-count-out 20)) ; Max number of paren/brace constructs before 8285 (here (point))
8286 (pp-count-out 20) ; Max number of paren/brace constructs before
8182 ; we give up 8287 ; we give up
8288 ids ; List of identifiers in the parenthesised list.
8289 id-start after-prec-token decl-or-cast decl-res
8290 c-last-identifier-range identifier-ok)
8183 (narrow-to-region low-lim (or macro-end (point-max))) 8291 (narrow-to-region low-lim (or macro-end (point-max)))
8184 8292
8185 ;; Search backwards for the defun's argument list. We give up if we 8293 ;; Search backwards for the defun's argument list. We give up if we
@@ -8198,8 +8306,12 @@ comment at the start of cc-engine.el for more info."
8198 ;; int foo (bar, baz, yuk) 8306 ;; int foo (bar, baz, yuk)
8199 ;; int bar [] ; 8307 ;; int bar [] ;
8200 ;; int (*baz) (my_type) ; 8308 ;; int (*baz) (my_type) ;
8201 ;; int (*) (void) (*yuk) (void) ; 8309 ;; int (*(* yuk) (void)) (void) ;
8202 ;; { 8310 ;; {
8311 ;;
8312 ;; Additionally, for a knr list to be recognized:
8313 ;; o - The identifier of each deeclarator up to and including the
8314 ;; one "near" point must be contained in the arg list.
8203 8315
8204 (catch 'knr 8316 (catch 'knr
8205 (while (> pp-count-out 0) ; go back one paren/bracket pair each time. 8317 (while (> pp-count-out 0) ; go back one paren/bracket pair each time.
@@ -8245,21 +8357,58 @@ comment at the start of cc-engine.el for more info."
8245 (goto-char before-lparen) 8357 (goto-char before-lparen)
8246 (c-forward-token-2) ; to first token inside parens 8358 (c-forward-token-2) ; to first token inside parens
8247 (and 8359 (and
8248 (c-on-identifier) 8360 (setq id-start (c-on-identifier)) ; Must be at least one.
8249 (c-forward-token-2)
8250 (catch 'id-list 8361 (catch 'id-list
8251 (while (eq (char-after) ?\,) 8362 (while
8363 (progn
8364 (forward-char)
8365 (c-end-of-current-token)
8366 (push (buffer-substring-no-properties id-start
8367 (point))
8368 ids)
8369 (c-forward-syntactic-ws)
8370 (eq (char-after) ?\,))
8252 (c-forward-token-2) 8371 (c-forward-token-2)
8253 (unless (c-on-identifier) (throw 'id-list nil)) 8372 (unless (setq id-start (c-on-identifier))
8254 (c-forward-token-2)) 8373 (throw 'id-list nil)))
8255 (eq (char-after) ?\)))))) 8374 (eq (char-after) ?\)))))
8256 8375
8376 ;; Are all the identifiers in the k&r list up to the
8377 ;; current one also in the argument list?
8378 (progn
8379 (forward-char) ; over the )
8380 (setq after-prec-token after-rparen)
8381 (c-forward-syntactic-ws)
8382 (while (and
8383 (or (consp (setq decl-or-cast
8384 (c-forward-decl-or-cast-1
8385 after-prec-token
8386 nil ; Or 'arglist ???
8387 nil)))
8388 (progn
8389 (goto-char after-prec-token)
8390 (c-forward-syntactic-ws)
8391 (setq identifier-ok (eq (char-after) ?{))
8392 nil))
8393 (eq (char-after) ?\;)
8394 (setq after-prec-token (1+ (point)))
8395 (goto-char (car decl-or-cast))
8396 (setq decl-res (c-forward-declarator))
8397 (setq identifier-ok
8398 (member (buffer-substring-no-properties
8399 (car decl-res) (cadr decl-res))
8400 ids))
8401 (progn
8402 (goto-char after-prec-token)
8403 (prog1 (< (point) here)
8404 (c-forward-syntactic-ws))))
8405 (setq identifier-ok nil))
8406 identifier-ok))
8257 ;; ...Yes. We've identified the function's argument list. 8407 ;; ...Yes. We've identified the function's argument list.
8258 (throw 'knr 8408 (throw 'knr
8259 (progn (goto-char after-rparen) 8409 (progn (goto-char after-rparen)
8260 (c-forward-syntactic-ws) 8410 (c-forward-syntactic-ws)
8261 (point))) 8411 (point)))
8262
8263 ;; ...No. The current parens aren't the function's arg list. 8412 ;; ...No. The current parens aren't the function's arg list.
8264 (goto-char before-lparen)) 8413 (goto-char before-lparen))
8265 8414
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index 03e67a99515..1e101d12aac 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -1006,6 +1006,7 @@ casts and declarations are fontified. Used on level 2 and higher."
1006 ;;(message "c-font-lock-declarators from %s to %s" (point) limit) 1006 ;;(message "c-font-lock-declarators from %s to %s" (point) limit)
1007 (c-fontify-types-and-refs 1007 (c-fontify-types-and-refs
1008 ((pos (point)) next-pos id-start id-end 1008 ((pos (point)) next-pos id-start id-end
1009 decl-res
1009 paren-depth 1010 paren-depth
1010 id-face got-init 1011 id-face got-init
1011 c-last-identifier-range 1012 c-last-identifier-range
@@ -1015,93 +1016,15 @@ casts and declarations are fontified. Used on level 2 and higher."
1015 ;; The following `while' fontifies a single declarator id each time round. 1016 ;; The following `while' fontifies a single declarator id each time round.
1016 ;; It loops only when LIST is non-nil. 1017 ;; It loops only when LIST is non-nil.
1017 (while 1018 (while
1018 ;; Inside the following "condition form", we move forward over the 1019 (and pos (setq decl-res (c-forward-declarator limit)))
1019 ;; declarator's identifier up as far as any opening bracket (for array 1020 (setq next-pos (point)
1020 ;; size) or paren (for parameters of function-type) or brace (for 1021 id-start (car decl-res)
1021 ;; array/struct initialization) or "=" or terminating delimiter 1022 id-face (if (and (eq (char-after) ?\()
1022 ;; (e.g. "," or ";" or "}"). 1023 (not (car (cddr decl-res)))) ; brackets-after-id
1023 (and
1024 pos
1025 (< (point) limit)
1026
1027 ;; The following form moves forward over the declarator's
1028 ;; identifier (and what precedes it), returning t. If there
1029 ;; wasn't one, it returns nil, terminating the `while'.
1030 (let (got-identifier)
1031 (setq paren-depth 0)
1032 ;; Skip over type decl prefix operators, one for each iteration
1033 ;; of the while. These are, e.g. "*" in "int *foo" or "(" and
1034 ;; "*" in "int (*foo) (void)" (Note similar code in
1035 ;; `c-forward-decl-or-cast-1'.)
1036 (while (and (looking-at c-type-decl-prefix-key)
1037 (if (and (c-major-mode-is 'c++-mode)
1038 (match-beginning 3))
1039 ;; If the third submatch matches in C++ then
1040 ;; we're looking at an identifier that's a
1041 ;; prefix only if it specifies a member pointer.
1042 (progn
1043 (setq id-start (point))
1044 (c-forward-name)
1045 (if (looking-at "\\(::\\)")
1046 ;; We only check for a trailing "::" and
1047 ;; let the "*" that should follow be
1048 ;; matched in the next round.
1049 t
1050 ;; It turned out to be the real identifier,
1051 ;; so flag that and stop.
1052 (setq got-identifier t)
1053 nil))
1054 t))
1055 (if (eq (char-after) ?\()
1056 (progn
1057 (setq paren-depth (1+ paren-depth))
1058 (forward-char))
1059 (goto-char (match-end 1)))
1060 (c-forward-syntactic-ws))
1061
1062 ;; If we haven't passed the identifier already, do it now.
1063 (unless got-identifier
1064 (setq id-start (point))
1065 (c-forward-name))
1066 (setq id-end (point))
1067
1068 (/= id-end pos))
1069
1070 ;; Skip out of the parens surrounding the identifier. If closing
1071 ;; parens are missing, this form returns nil.
1072 (or (= paren-depth 0)
1073 (c-safe (goto-char (scan-lists (point) 1 paren-depth))))
1074
1075 (<= (point) limit)
1076
1077 ;; Skip over any trailing bit, such as "__attribute__".
1078 (progn
1079 (when (looking-at c-decl-hangon-key)
1080 (c-forward-keyword-clause 1))
1081 (<= (point) limit))
1082
1083 ;; Search syntactically to the end of the declarator (";",
1084 ;; ",", a closing paren, eob etc) or to the beginning of an
1085 ;; initializer or function prototype ("=" or "\\s(").
1086 ;; Note that square brackets are now not also treated as
1087 ;; initializers, since this broke when there were also
1088 ;; initializing brace lists.
1089 (let (found)
1090 (while
1091 (and (setq found (c-syntactic-re-search-forward
1092 "[;,]\\|\\s)\\|\\'\\|\\(=\\|\\s(\\)" limit t t))
1093 (eq (char-before) ?\[)
1094 (c-go-up-list-forward))
1095 (setq brackets-after-id t))
1096 found))
1097
1098 (setq next-pos (match-beginning 0)
1099 id-face (if (and (eq (char-after next-pos) ?\()
1100 (not brackets-after-id))
1101 'font-lock-function-name-face 1024 'font-lock-function-name-face
1102 'font-lock-variable-name-face) 1025 'font-lock-variable-name-face)
1103 got-init (and (match-beginning 1) 1026 got-init (and (cadr (cddr decl-res)) ; got-init
1104 (char-after (match-beginning 1)))) 1027 (char-after)))
1105 1028
1106 (if types 1029 (if types
1107 ;; Register and fontify the identifier as a type. 1030 ;; Register and fontify the identifier as a type.