From 4e0b67ed27114fa2cbebca32567089fd8fa78425 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Wed, 4 Oct 2017 17:34:27 +0000 Subject: [PATCH] Fontify untyped function declarations in C Mode correctly. Also correct two bugs where deleting WS at a BOL could leave an untyped function declaration unfontified. * lisp/progmodes/cc-engine.el (c-find-decl-spots): Don't set the flag "top-level" when we're in a macro. (c-forward-decl-or-cast-1): Recognize top-level "foo(bar)" or "foo()" in C Mode as a implicitly typed function declaration. (c-just-after-func-arglist-p): Don't get confused by "defined (foo)" inside a macro. It's not a function plus arglist. * lisp/progmodes/cc-langs.el (c-cpp-expr-functions-key): New defconst and defvar. * lisp/progmodes/cc-mode.el (c-fl-decl-end): After c-forward-declarator, move over any following parenthesis expression (i.e. parameter list). (c-change-expand-fl-region): When c-new-END is at a BOL, include that line in the returned region, to cope with deletions at column 0. --- lisp/progmodes/cc-engine.el | 48 ++++++++++++++++++++++++++++--------- lisp/progmodes/cc-langs.el | 5 ++++ lisp/progmodes/cc-mode.el | 4 +++- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 9d65383e258..37928357526 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -132,7 +132,7 @@ ;; ;; 'c-not-decl ;; Put on the brace which introduces a brace list and on the commas -;; which separate the element within it. +;; which separate the elements within it. ;; ;; 'c-awk-NL-prop ;; Used in AWK mode to mark the various kinds of newlines. See @@ -5403,8 +5403,8 @@ comment at the start of cc-engine.el for more info." (min c-bs-cache-limit pos))) (defun c-update-brace-stack (stack from to) - ;; Give a brace-stack which has the value STACK at position FROM, update it - ;; to it's value at position TO, where TO is after (or equal to) FROM. + ;; Given a brace-stack which has the value STACK at position FROM, update it + ;; to its value at position TO, where TO is after (or equal to) FROM. ;; Return a cons of either TO (if it is outside a literal) and this new ;; value, or of the next position after TO outside a literal and the new ;; value. @@ -5649,11 +5649,13 @@ comment at the start of cc-engine.el for more info." ;; Call CFD-FUN for each possible spot for a declaration, cast or ;; label from the point to CFD-LIMIT. ;; - ;; CFD-FUN is called with point at the start of the spot. It's passed two + ;; CFD-FUN is called with point at the start of the spot. It's passed three ;; arguments: The first is the end position of the token preceding the spot, ;; or 0 for the implicit match at bob. The second is a flag that is t when - ;; the match is inside a macro. Point should be moved forward by at least - ;; one token. + ;; the match is inside a macro. The third is a flag that is t when the + ;; match is at "top level", i.e. outside any brace block, or directly inside + ;; a class or namespace, etc. Point should be moved forward by at least one + ;; token. ;; ;; If CFD-FUN adds `c-decl-end' properties somewhere below the current spot, ;; it should return non-nil to ensure that the next search will find them. @@ -6040,6 +6042,8 @@ comment at the start of cc-engine.el for more info." (setq cfd-macro-end 0) nil)))) ; end of when condition + (when (> cfd-macro-end 0) + (setq cfd-top-level nil)) ; In a macro is "never" at top level. (c-debug-put-decl-spot-faces cfd-match-pos (point)) (if (funcall cfd-fun cfd-match-pos (/= cfd-macro-end 0) cfd-top-level) (setq cfd-prop-match nil)) @@ -8577,7 +8581,13 @@ comment at the start of cc-engine.el for more info." (looking-at c-noise-macro-with-parens-name-re)) (c-forward-noise-clause)) - ((looking-at c-type-decl-suffix-key) + ((and (looking-at c-type-decl-suffix-key) + ;; We avoid recognizing foo(bar) or foo() at top level as a + ;; construct here in C, since we want to recognize this as a + ;; typeless function declaration. + (not (and (c-major-mode-is 'c-mode) + (eq context 'top) + (eq (char-after) ?\))))) (if (eq (char-after) ?\)) (when (> paren-depth 0) (setq paren-depth (1- paren-depth)) @@ -8620,7 +8630,12 @@ comment at the start of cc-engine.el for more info." (save-excursion (goto-char after-paren-pos) (c-forward-syntactic-ws) - (c-forward-type))))) + (or (c-forward-type) + ;; Recognize a top-level typeless + ;; function declaration in C. + (and (c-major-mode-is 'c-mode) + (eq context 'top) + (eq (char-after) ?\)))))))) (setq pos (c-up-list-forward (point))) (eq (char-before pos) ?\))) (c-fdoc-shift-type-backward) @@ -9037,9 +9052,12 @@ comment at the start of cc-engine.el for more info." ;; (in at least C++) that anything that can be parsed as a declaration ;; is a declaration. Now we're being more defensive and prefer to ;; highlight things like "foo (bar);" as a declaration only if we're - ;; inside an arglist that contains declarations. - ;; CASE 19 - (eq context 'decl)))) + ;; inside an arglist that contains declarations. Update (2017-09): We + ;; now recognize a top-level "foo(bar);" as a declaration in C. + ;; CASE 19 + (or (eq context 'decl) + (and (c-major-mode-is 'c-mode) + (eq context 'top)))))) ;; The point is now after the type decl expression. @@ -9547,6 +9565,7 @@ Note that this function might do hidden buffer changes. See the comment at the start of cc-engine.el for more info." ;; Note to maintainers: this function consumes a great mass of CPU cycles. ;; Its use should thus be minimized as far as possible. + ;; Consider instead using `c-bs-at-toplevel-p'. (let ((paren-state (c-parse-state))) (or (not (c-most-enclosing-brace paren-state)) (c-search-uplist-for-classkey paren-state)))) @@ -9576,8 +9595,15 @@ comment at the start of cc-engine.el for more info." (not (and (c-major-mode-is 'objc-mode) (c-forward-objc-directive))) + ;; Don't confuse #if .... defined(foo) for a function arglist. + (not (and (looking-at c-cpp-expr-functions-key) + (save-excursion + (save-restriction + (widen) + (c-beginning-of-macro lim))))) (setq id-start (car-safe (c-forward-decl-or-cast-1 (c-point 'bosws) 'top nil))) + (numberp id-start) (< id-start beg) ;; There should not be a '=' or ',' between beg and the diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 7a285f93d34..bcda093678a 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -952,6 +952,11 @@ expression, or nil if there aren't any in the language." '("defined")) pike '("defined" "efun" "constant")) +(c-lang-defconst c-cpp-expr-functions-key + ;; Matches a function in a cpp expression. + t (c-make-keywords-re t (c-lang-const c-cpp-expr-functions))) +(c-lang-defvar c-cpp-expr-functions-key (c-lang-const c-cpp-expr-functions-key)) + (c-lang-defconst c-assignment-operators "List of all assignment operators." t '("=" "*=" "/=" "%=" "+=" "-=" ">>=" "<<=" "&=" "^=" "|=") diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 8867453e85c..b0e5fe47a7c 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -1571,6 +1571,8 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") (and (c-beginning-of-macro) (progn (c-end-of-macro) (point)))))) (when (and (c-forward-declarator lim) + (or (not (eq (char-after) ?\()) + (c-go-list-forward nil lim)) (eq (c-forward-token-2 1 nil lim) 0)) (c-backward-syntactic-ws) (point)))))) @@ -1589,7 +1591,7 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") (or (c-fl-decl-start c-new-BEG) (c-point 'bol c-new-BEG)) c-new-END (or (c-fl-decl-end c-new-END) - (c-point 'bonl (max (1- c-new-END) (point-min))))))) + (c-point 'bonl c-new-END))))) (defun c-context-expand-fl-region (beg end) ;; Return a cons (NEW-BEG . NEW-END), where NEW-BEG is the beginning of a -- 2.39.5