| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 
 | ;;; cwarn.el --- highlight suspicious C and C++ constructions
;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
;; Free Software Foundation, Inc.
;; Author: Anders Lindgren <andersl@andersl.com>
;; 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 3, 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., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, 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."
  :group 'cwarn :lighter cwarn-mode-text
  (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
(define-globalized-minor-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
 |