[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/relint e8d8052 03/11: Add checking of ineffective backs
From: |
Mattias Engdegård |
Subject: |
[elpa] externals/relint e8d8052 03/11: Add checking of ineffective backslashes in string literals |
Date: |
Sat, 20 Jun 2020 05:57:40 -0400 (EDT) |
branch: externals/relint
commit e8d80524bf41980c765f045e07acf325837376f1
Author: Mattias Engdegård <mattiase@acm.org>
Commit: Mattias Engdegård <mattiase@acm.org>
Add checking of ineffective backslashes in string literals
This is an experimental feature.
Check all string literals (not just those that are regexps) for
backslashes that do not escape something sensible; this is a frequent
source of mistakes for regexps in particular, and can indicate errors
in other strings as well.
Currently, all such occurrencies in doc strings are ignored since
those are mostly false positives.
---
relint.el | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/relint.el b/relint.el
index d4c261c..73f32a5 100644
--- a/relint.el
+++ b/relint.el
@@ -2131,6 +2131,89 @@ Return a list of (FORM . STARTING-POSITION)."
(push (cons form pos) forms))))
(nreverse forms)))
+(defun relint--miscape-in-doc-string-p (pos)
+ "Whether the string literal starting at POS is a doc string."
+ (save-excursion
+ (goto-char pos)
+ ;; Go back to start of containing sexp, counting the steps.
+ (let ((steps 0))
+ (while (and (not (bobp))
+ (ignore-errors
+ (forward-sexp -1)
+ t)
+ (not (and (= steps 0)
+ (looking-at (rx ":documentation" symbol-end)))))
+ (setq steps (1+ steps)))
+ (or
+ (= steps 0) ; `:documentation' parameter
+ (and (= steps 3)
+ (looking-at (rx (or "defun" "defmacro" "defsubst" "defalias"
+ "defconst" "defvar" "defcustom"
+ "autoload"
+ "cl-defun" "cl-defmacro" "cl-defmethod"
+ "ert-deftest"
+ ;; Specific to cc-mode
+ "c-lang-defvar"
+ ;; Specific to gnus
+ "defvoo"))))
+ (and (= steps 2)
+ (looking-at (rx (or "define-major-mode" "define-minor-mode"
+ ;; Specific to cc-mode
+ "c-lang-defconst"))))
+ (and (= steps 4)
+ (looking-at (rx (or "define-derived-mode"))))))))
+
+(defconst relint--miscape-ignore-left-round-bracket nil
+ "Whether to ignore specifically `\\(' in doc strings.")
+
+(defconst relint--miscape-ignore-all-doc-strings t
+ "Whether to ignore all stray backslashes in doc strings.")
+
+(defun relint--miscape-suspicious-backslash (string-start)
+ "With point at an ineffective backslash, emit an warning unless filtered out.
+STRING-START is the start of the string literal (first double quote)."
+ (let ((c (char-after (1+ (point)))))
+ (unless (or (bolp)
+ (and (or (and relint--miscape-ignore-left-round-bracket
+ (eq c ?\())
+ relint--miscape-ignore-all-doc-strings)
+ (relint--miscape-in-doc-string-p string-start)))
+ (relint--warn (point) nil
+ (format-message
+ "Ineffective string escape `\\%s'"
+ (relint--escape-string (char-to-string c) nil))))))
+
+(defun relint--miscape-current-buffer ()
+ "Check for misplaced backslashes in the current buffer."
+ (goto-char (point-min))
+ (while (not (eobp))
+ (when (looking-at (rx (1+ (or (seq "?" (or (seq ?\\ anything)
+ (not (any ?\\))))
+ (seq "\\" anything)
+ (seq ";" (0+ nonl))
+ (not (any ?\" ?\; ?? ?\\))))))
+ (goto-char (match-end 0)))
+ (when (looking-at (rx ?\"))
+ (let ((string-start (point)))
+ (goto-char (match-end 0))
+ (while (not (looking-at (rx (or ?\" eot))))
+ (when (looking-at
+ (rx (1+ (or (seq
+ ?\\ (any "0-9" "xuUN" "abfnrtv"
+ "des" "^" " "
+ ?\\ ?\n ?\"))
+ (seq
+ (1+ ?\\ (any "CM") "-")
+ (or (not (any ?\\))
+ (seq ?\\ anything)))
+ (not (any ?\\ ?\"))))))
+ (goto-char (match-end 0)))
+ (when (eq (following-char) ?\\)
+ (relint--miscape-suspicious-backslash string-start)
+ (forward-char 2)))
+ (unless (eobp)
+ (forward-char 1))))))
+
(defun relint--scan-current-buffer ()
(let* ((relint--suppression-count 0)
(relint--complaints nil)
@@ -2149,6 +2232,7 @@ Return a list of (FORM . STARTING-POSITION)."
(relint--check-form-recursively-1 (car form) (cdr form) nil))
(dolist (form forms)
(relint--check-form-recursively-2 (car form) nil (cdr form) nil))
+ (relint--miscape-current-buffer)
(cons (nreverse relint--complaints) relint--suppression-count)))
(defvar relint-last-target nil
- [elpa] externals/relint updated (a54960a -> 0c35e02), Mattias Engdegård, 2020/06/20
- [elpa] externals/relint 6bfba5c 01/11: Always output to stderr when running noninteractively, Mattias Engdegård, 2020/06/20
- [elpa] externals/relint 1ea9b91 05/11: Add tests for ineffective backslash check, Mattias Engdegård, 2020/06/20
- [elpa] externals/relint 0d80c1f 07/11: Rename various 'miscape' identifiers, Mattias Engdegård, 2020/06/20
- [elpa] externals/relint e35fa2e 09/11: Fix doc string predicate, Mattias Engdegård, 2020/06/20
- [elpa] externals/relint e8d8052 03/11: Add checking of ineffective backslashes in string literals,
Mattias Engdegård <=
- [elpa] externals/relint 329df9c 02/11: Refactor framework, Mattias Engdegård, 2020/06/20
- [elpa] externals/relint 2de1106 04/11: Sort diagnostics by buffer position, Mattias Engdegård, 2020/06/20
- [elpa] externals/relint a1c7bf5 06/11: Describe the ineffective backslash warning in README, Mattias Engdegård, 2020/06/20
- [elpa] externals/relint 0627d4d 08/11: Simplify (and speed up) string scanning regexp, Mattias Engdegård, 2020/06/20
- [elpa] externals/relint 0c35e02 11/11: Increment version to 1.18, Mattias Engdegård, 2020/06/20
- [elpa] externals/relint 6a86509 10/11: Tuned miscape filtering, Mattias Engdegård, 2020/06/20