emacs-diffs
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]