[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] Changes to emacs/lisp/progmodes/cwarn.el [lexbind]
From: |
Miles Bader |
Subject: |
[Emacs-diffs] Changes to emacs/lisp/progmodes/cwarn.el [lexbind] |
Date: |
Tue, 14 Oct 2003 19:30:26 -0400 |
Index: emacs/lisp/progmodes/cwarn.el
diff -c /dev/null emacs/lisp/progmodes/cwarn.el:1.7.2.1
*** /dev/null Tue Oct 14 19:30:26 2003
--- emacs/lisp/progmodes/cwarn.el Tue Oct 14 19:30:16 2003
***************
*** 0 ****
--- 1,384 ----
+ ;;; cwarn.el --- highlight suspicious C and C++ constructions
+
+ ;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ ;; Author: Anders Lindgren <address@hidden>
+ ;; Keywords: c, languages, faces
+ ;; X-Url: http://www.andersl.com/emacs
+ ;; Version: 1.3.1 1999-12-13
+
+ ;; This file is part of GNU Emacs.
+
+ ;; GNU Emacs is free software; you can redistribute it and/or modify
+ ;; it under the terms of the GNU General Public License as published by
+ ;; the Free Software Foundation; either version 2, or (at your option)
+ ;; any later version.
+
+ ;; GNU Emacs is distributed in the hope that it will be useful,
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ;; GNU General Public License for more details.
+
+ ;; You should have received a copy of the GNU General Public License
+ ;; along with GNU Emacs; see the file COPYING. If not, write to the
+ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ ;; Boston, MA 02111-1307, USA.
+
+ ;;; Commentary:
+
+ ;;{{{ Documentation
+
+ ;; Description:
+ ;;
+ ;; CWarn is a package that highlights suspicious C and C++ constructions.
+ ;;
+ ;; For example, take a look at the following piece of C code:
+ ;;
+ ;; if (x = 0);
+ ;; foo();
+ ;;
+ ;; The code contains two, possibly fatal, bugs. The first is that the
+ ;; assignment operator "=" is used as part of the test; the user
+ ;; probably meant to use the comparison operator "==".
+ ;;
+ ;; The second problem is that an extra semicolon is placed after
+ ;; closing parenthesis of the test expression. This makes the body of
+ ;; the if statement to be an empty statement, not the call to the
+ ;; function "foo", as the user probably intended.
+ ;;
+ ;; This package is capable of highlighting the following C and C++
+ ;; constructions:
+ ;;
+ ;; * Assignments inside expressions, including variations like "+=".
+ ;; * Semicolon following immediately after `if', `for', and `while'
+ ;; (except, of course, after a `do .. while' statement).
+ ;; * C++ functions with reference parameters.
+ ;;
+ ;; Note that none of the constructions highlighted (especially not C++
+ ;; reference parameters) are considered errors by the language
+ ;; definitions.
+
+ ;; Usage:
+ ;;
+ ;; CWarn is implemented as two minor modes: `cwarn-mode' and
+ ;; `global-cwarn-mode'. The former can be applied to individual buffers
+ ;; and the latter to all buffers.
+ ;;
+ ;; Activate this package by Customize, or by placing the following line
+ ;; into the appropriate init file:
+ ;;
+ ;; (global-cwarn-mode 1)
+ ;;
+ ;; Also, `font-lock-mode' or `global-font-lock-mode' must be enabled.
+
+ ;; Afterthought:
+ ;;
+ ;; After using this package for several weeks it feels as though I
+ ;; find stupid typo-style bugs while editing rather than at compile-
+ ;; or run-time, if I ever find them.
+ ;;
+ ;; On the other hand, I find myself using assignments inside
+ ;; expressions much more often than I used to do. The reason is that
+ ;; there is no risk of interpreting an assignment operator as a
+ ;; comparison ("hey, the assignment operator is red, duh!").
+
+ ;; Reporting bugs:
+ ;;
+ ;; Out of the last ten bugs you found, how many did you report?
+ ;;
+ ;; When reporting a bug, please:
+ ;;
+ ;; * Send a mail the maintainer of the package, or to the author
+ ;; if no maintainer exists.
+ ;; * Include the name of the package in the title of the mail, to
+ ;; simplify for the recipient.
+ ;; * State exactly what you did, what happened, and what you expected
+ ;; to see when you found the bug.
+ ;; * If the bug cause an error, set the variable `debug-on-error' to t,
+ ;; repeat the operations that triggered the error and include
+ ;; the backtrace in the letter.
+ ;; * If possible, include an example that activates the bug.
+ ;; * Should you speculate about the cause of the problem, please
+ ;; state explicitly that you are guessing.
+
+ ;;}}}
+
+ ;;; Code:
+
+ ;;{{{ Dependencies
+
+ (eval-when-compile (require 'cl))
+
+ (require 'custom)
+ (require 'font-lock)
+ (require 'cc-mode)
+
+ ;;}}}
+ ;;{{{ Variables
+
+ (defgroup cwarn nil
+ "Highlight suspicious C and C++ constructions."
+ :version "21.1"
+ :link '(url-link "http://www.andersl.com/emacs";)
+ :group 'faces)
+
+ (defvar cwarn-mode nil
+ "*Non-nil when Cwarn mode is active.
+
+ Never set this variable directly, use the command `cwarn-mode'
+ instead.")
+
+ (defcustom cwarn-configuration
+ '((c-mode (not reference))
+ (c++-mode t))
+ "*List of items each describing which features are enable for a mode.
+ Each item is on the form (mode featurelist), where featurelist can be
+ on one of three forms:
+
+ * A list of enabled features.
+ * A list starting with the atom `not' followed by the features
+ which are not enabled.
+ * The atom t, that represent that all features are enabled.
+
+ See variable `cwarn-font-lock-feature-keywords-alist' for available
+ features."
+ :type '(repeat sexp)
+ :group 'cwarn)
+
+ (defcustom cwarn-font-lock-feature-keywords-alist
+ '((assign . cwarn-font-lock-assignment-keywords)
+ (semicolon . cwarn-font-lock-semicolon-keywords)
+ (reference . cwarn-font-lock-reference-keywords))
+ "An alist mapping a CWarn feature to font-lock keywords.
+ The keywords could either a font-lock keyword list or a symbol.
+ If it is a symbol it is assumed to be a variable containing a font-lock
+ keyword list."
+ :type '(alist :key-type (choice (const assign)
+ (const semicolon)
+ (const reference))
+ :value-type (sexp :tag "Value"))
+ :group 'cwarn)
+
+ (defcustom cwarn-verbose t
+ "*When nil, CWarn mode will not generate any messages.
+
+ Currently, messages are generated when the mode is activated and
+ deactivated."
+ :group 'cwarn
+ :type 'boolean)
+
+ (defcustom cwarn-mode-text " CWarn"
+ "*String to display in the mode line when CWarn mode is active.
+
+ \(When the string is not empty, make sure that it has a leading space.)"
+ :tag "CWarn mode text" ; To separate it from `global-...'
+ :group 'cwarn
+ :type 'string)
+
+ (defcustom cwarn-load-hook nil
+ "*Functions to run when CWarn mode is first loaded."
+ :tag "Load Hook"
+ :group 'cwarn
+ :type 'hook)
+
+ ;;}}}
+ ;;{{{ The modes
+
+ ;;;###autoload
+ (define-minor-mode cwarn-mode
+ "Minor mode that highlights suspicious C and C++ constructions.
+
+ Note, in addition to enabling this minor mode, the major mode must
+ be included in the variable `cwarn-configuration'. By default C and
+ C++ modes are included.
+
+ With ARG, turn CWarn mode on if and only if arg is positive."
+ nil cwarn-mode-text nil
+ (cwarn-font-lock-keywords cwarn-mode)
+ (if font-lock-mode (font-lock-fontify-buffer)))
+
+ ;;;###autoload
+ (defun turn-on-cwarn-mode ()
+ "Turn on CWarn mode.
+
+ This function is designed to be added to hooks, for example:
+ (add-hook 'c-mode-hook 'turn-on-cwarn-mode)"
+ (cwarn-mode 1))
+
+ ;;}}}
+ ;;{{{ Help functions
+
+ (defun cwarn-is-enabled (mode &optional feature)
+ "Non-nil if CWarn FEATURE is enabled for MODE.
+ feature is an atom representing one construction to highlight.
+
+ Check if any feature is enabled for MODE if no feature is specified.
+
+ The valid features are described by the variable
+ `cwarn-font-lock-feature-keywords-alist'."
+ (let ((mode-configuraion (assq mode cwarn-configuration)))
+ (and mode-configuraion
+ (or (null feature)
+ (let ((list-or-t (nth 1 mode-configuraion)))
+ (or (eq list-or-t t)
+ (if (eq (car-safe list-or-t) 'not)
+ (not (memq feature (cdr list-or-t)))
+ (memq feature list-or-t))))))))
+
+ (defun cwarn-inside-macro ()
+ "True if point is inside a C macro definition."
+ (save-excursion
+ (beginning-of-line)
+ (while (eq (char-before (1- (point))) ?\\)
+ (forward-line -1))
+ (back-to-indentation)
+ (eq (char-after) ?#)))
+
+ (defun cwarn-font-lock-keywords (addp)
+ "Install/Remove keywords into current buffer.
+ If ADDP is non-nil, install else remove."
+ (dolist (pair cwarn-font-lock-feature-keywords-alist)
+ (let ((feature (car pair))
+ (keywords (cdr pair)))
+ (if (not (listp keywords))
+ (setq keywords (symbol-value keywords)))
+ (if (cwarn-is-enabled major-mode feature)
+ (funcall (if addp 'font-lock-add-keywords 'font-lock-remove-keywords)
+ nil keywords)))))
+
+ ;;}}}
+ ;;{{{ Backward compatibility
+
+ ;; This piece of code will be part of CC mode as of Emacs 20.4.
+ (if (not (fboundp 'c-at-toplevel-p))
+ (defun c-at-toplevel-p ()
+ "Return a determination as to whether point is at the `top-level'.
+ Being at the top-level means that point is either outside any
+ enclosing block (such function definition), or inside a class
+ definition, but outside any method blocks.
+
+ If point is not at the top-level (e.g. it is inside a method
+ definition), then nil is returned. Otherwise, if point is at a
+ top-level not enclosed within a class definition, t is returned.
+ Otherwise, a 2-vector is returned where the zeroth element is the
+ buffer position of the start of the class declaration, and the first
+ element is the buffer position of the enclosing class' opening
+ brace."
+ (let ((state (c-parse-state)))
+ (or (not (c-most-enclosing-brace state))
+ (c-search-uplist-for-classkey state))))
+ )
+
+ ;;}}}
+ ;;{{{ Font-lock keywords and match functions
+
+ ;; This section contains font-lock keywords. A font lock keyword can
+ ;; either contain a regular expression or a match function. All
+ ;; keywords defined here use match functions since the C and C++
+ ;; constructions highlighted by CWarn are too complex to be matched by
+ ;; regular expressions.
+ ;;
+ ;; A match function should act like a normal forward search. They
+ ;; should return non-nil if they found a candidate and the match data
+ ;; should correspond to the highlight part of the font-lock keyword.
+ ;; The functions should not generate errors, in that case font-lock
+ ;; will fail to highlight the buffer. A match function takes one
+ ;; argument, LIMIT, that represent the end of area to be searched.
+ ;;
+ ;; The variable `cwarn-font-lock-feature-keywords-alist' contains a
+ ;; mapping from CWarn features to the font-lock keywords defined
+ ;; below.
+
+ (defmacro cwarn-font-lock-match (re &rest body)
+ "Match RE but only if BODY holds."
+ `(let ((res nil))
+ (while
+ (progn
+ (setq res (re-search-forward ,re limit t))
+ (and res
+ (save-excursion
+ (when (match-beginning 1) (goto-char (match-beginning 1)))
+ (condition-case nil ; In case something barfs.
+ (not (save-match-data
+ ,@body))
+ (error t))))))
+ res))
+
+ ;;{{{ Assignment in expressions
+
+ (defconst cwarn-font-lock-assignment-keywords
+ '((cwarn-font-lock-match-assignment-in-expression
+ (1 font-lock-warning-face))))
+
+ (defun cwarn-font-lock-match-assignment-in-expression (limit)
+ "Match assignments inside expressions."
+ (cwarn-font-lock-match
+ "[^!<>=]\\(\\([-+*/%&^|]\\|<<\\|>>\\)?=\\)[^=]"
+ (backward-up-list 1)
+ (and (memq (following-char) '(?\( ?\[))
+ (not (progn
+ (skip-chars-backward " ")
+ (skip-chars-backward "a-zA-Z0-9_")
+ (or
+ ;; Default parameter of function.
+ (c-at-toplevel-p)
+ (looking-at "for\\>")))))))
+
+ ;;}}}
+ ;;{{{ Semicolon
+
+ (defconst cwarn-font-lock-semicolon-keywords
+ '((cwarn-font-lock-match-dangerous-semicolon (0 font-lock-warning-face))))
+
+ (defun cwarn-font-lock-match-dangerous-semicolon (limit)
+ "Match semicolons directly after `for', `while', and `if'.
+ The semicolon after a `do { ... } while (x);' construction is not matched."
+ (cwarn-font-lock-match
+ ";"
+ (backward-sexp 2) ; Expression and keyword.
+ (or (looking-at "\\(for\\|if\\)\\>")
+ (and (looking-at "while\\>")
+ (condition-case nil
+ (progn
+ (backward-sexp 2) ; Body and "do".
+ (not (looking-at "do\\>")))
+ (error t))))))
+
+ ;;}}}
+ ;;{{{ Reference
+
+ (defconst cwarn-font-lock-reference-keywords
+ '((cwarn-font-lock-match-reference (1 font-lock-warning-face))))
+
+ (defun cwarn-font-lock-match-reference (limit)
+ "Font-lock matcher for C++ reference parameters."
+ (cwarn-font-lock-match
+ "[^&]\\(&\\)[^&=]"
+ (backward-up-list 1)
+ (and (eq (following-char) ?\()
+ (not (cwarn-inside-macro))
+ (c-at-toplevel-p))))
+
+ ;;}}}
+
+ ;;}}}
+ ;;{{{ The end
+
+ (defun turn-on-cwarn-mode-if-enabled ()
+ "Turn on CWarn mode in the current buffer if applicable.
+ The mode is turned if some feature is enabled for the current
+ `major-mode' in `cwarn-configuration'."
+ (if (cwarn-is-enabled major-mode) (turn-on-cwarn-mode)))
+
+ ;;;###autoload
+ (easy-mmode-define-global-mode global-cwarn-mode cwarn-mode
+ turn-on-cwarn-mode-if-enabled)
+
+ (provide 'cwarn)
+
+ (run-hooks 'cwarn-load-hook)
+
+ ;;}}}
+
+ ;;; arch-tag: 225fb5e2-0838-4eb1-88ce-3811c5e4d738
+ ;;; cwarn.el ends here
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Emacs-diffs] Changes to emacs/lisp/progmodes/cwarn.el [lexbind],
Miles Bader <=