123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- (eval-when-compile (require 'cl))
- (require 'custom)
- (require 'font-lock)
- (require 'cc-mode)
- (defgroup cwarn nil
- "Highlight suspicious C and C++ constructions."
- :version "21.1"
- :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"
- :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)
- (define-minor-mode cwarn-mode
- "Minor mode that highlights suspicious C and C++ constructions.
- Suspicious constructs are highlighted using `font-lock-warning-face'.
- 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 a prefix argument ARG, enable the mode if ARG is positive,
- and disable it otherwise. If called from Lisp, enable the mode
- if ARG is omitted or nil."
- :group 'cwarn :lighter cwarn-mode-text
- (cwarn-font-lock-keywords cwarn-mode)
- (if font-lock-mode (font-lock-fontify-buffer)))
- (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))
- (make-obsolete 'turn-on-cwarn-mode 'cwarn-mode "24.1")
- (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-configuration (assq mode cwarn-configuration)))
- (and mode-configuration
- (or (null feature)
- (let ((list-or-t (nth 1 mode-configuration)))
- (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)))))
- (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
- (not (save-match-data
- ,@body))
- (error t))))))
- res))
- (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
-
- (c-at-toplevel-p)
- (looking-at "for\\>")))))))
- (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)
- (or (looking-at "\\(for\\|if\\)\\>")
- (and (looking-at "while\\>")
- (condition-case nil
- (progn
- (backward-sexp 2)
- (not (looking-at "do\\>")))
- (error t))))))
- (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))))
- (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'."
- (when (cwarn-is-enabled major-mode) (cwarn-mode 1)))
- (define-globalized-minor-mode global-cwarn-mode
- cwarn-mode turn-on-cwarn-mode-if-enabled)
- (provide 'cwarn)
- (run-hooks 'cwarn-load-hook)
|