[elpa] externals/relint 9259a5c 03/21: Check some :value parameters in defcustom :type clauses

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 9259a5c5e82f75aa4efd20746c6d0887acd64e0f
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check some :value parameters in defcustom :type clauses

For example, this catches

  :type '(string :value "some bad regexp")
---
 relint.el   | 13 +++--
 test/1.elisp| 13 +
 test/1.expected | 30 +-
 3 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/relint.el b/relint.el
index bc4a9af..d484116 100644
--- a/relint.el
+++ b/relint.el
@@ -1551,12 +1551,13 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
 
 (defun relint--check-defcustom-type (type name file pos path)
   (pcase type
-(`(const . ,rest)
- ;; Skip keywords.
- (while (and rest (symbolp (car rest)))
-   (setq rest (cddr rest)))
- (when rest
-   (relint--check-re (car rest) name file pos path)))
+(`(,(or 'const 'string 'regexp) . ,rest)
+ (while (consp rest)
+   (cond ((eq (car rest) :value)
+  (relint--check-re (cadr rest) name file pos path))
+ ((not (cdr rest))
+  (relint--check-re (car rest) name file pos path)))
+   (setq rest (cddr rest
 (`(,(or 'choice 'radio) . ,choices)
  (dolist (choice choices)
(relint--check-defcustom-type choice name file pos path)
diff --git a/test/1.elisp b/test/1.elisp
index 865d21a..c00681a 100644
--- a/test/1.elisp
+++ b/test/1.elisp
@@ -75,6 +75,19 @@
   :group 'relint-test
   :type '(repeat regexp))
 
+(defcustom bad-custom-8 nil
+  "Doc"
+  :type '(choice (regexp :tag "*" :value "[11]")
+ (string :tag "+" :value "[22]")))
+
+(defcustom bad-custom-9-regexp nil
+  "Doc"
+  :type '(string :tag "+" :value "[33]"))
+
+(defcustom bad-custom-10 nil
+  "regular expression"
+  :type '(string :tag "+" "[44]"))
+
 ;; Special case.
 (defvar compilation-error-regexp-alist-alist
   '((aa "a^a" 1 2)
diff --git a/test/1.expected b/test/1.expected
index 8d1e997..4014a72 100644
--- a/test/1.expected
+++ b/test/1.expected
@@ -138,30 +138,42 @@
 1.elisp:73:35: In bad-custom-7: Duplicated `a' inside character alternative 
(pos 2)
   "[aa]"
..^
-1.elisp:80:11: In compilation-error-regexp-alist-alist (aa): Unescaped literal 
`^' (pos 1)
+1.elisp:80:9: In bad-custom-8: Duplicated `1' inside character alternative 
(pos 2)
+  "[11]"
+   ..^
+1.elisp:80:9: In bad-custom-8: Duplicated `2' inside character alternative 
(pos 2)
+  "[22]"
+   ..^
+1.elisp:85:9: In bad-custom-9-regexp: Duplicated `3' inside character 
alternative (pos 2)
+  "[33]"
+   ..^
+1.elisp:89:9: In bad-custom-10: Duplicated `4' inside character alternative 
(pos 2)
+  "[44]"
+   ..^
+1.elisp:93:11: In compilation-error-regexp-alist-alist (aa): Unescaped literal 
`^' (pos 1)
   "a^a"
.^
-1.elisp:81:11: In compilation-error-regexp-alist-alist (bb): Unescaped literal 
`$' (pos 1)
+1.elisp:94:11: In compilation-error-regexp-alist-alist (bb): Unescaped literal 
`$' (pos 1)
   "b$b"
.^
-1.elisp:86:8: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
+1.elisp:99:8: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
   "1^"
.^
-1.elisp:87:8: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
+1.elisp:100:8: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
   "2^"
.^
-1.elisp:88:12: In define-generic-mode my-mode: Repetition of repetition (pos 2)
+1.elisp:101:12: In define-generic-mode my-mode: Repetition of repetition (pos 
2)
   "b++"
..^
-1.elisp:94:6: In call to syntax-propertize-rules: Unescaped literal `$' (pos 0)
+1.elisp:107:6: In call to syntax-propertize-rules: Unescaped literal `$' (pos 
0)
   "$1$"
^
-1.elisp:95:8: In call to syntax-propertize-rules: Unescaped literal `^' (pos 2)
+1.elisp:108:8: In call to syntax-propertize-rules: Unescaped literal `^' (pos 
2)
   "^2^"
..^
-1.elisp:100:6: In call to syntax-propertize-precompile-rules: Unescaped 
literal `$' (pos 0)
+1.elisp:113:6: In call to syntax-propertize-precompile-rules: Unescaped 
literal `$' (pos 0)
   "$3$"
^
-1.elisp:101:8: In call to syntax-propertize-precompile-rules: Unescaped 
literal `^' (pos 2)
+1.elisp:114:8: In call to syntax-propertize-precompile-rules: Unescaped 
literal `^' (pos 2)
   "^4^"
..^



[elpa] externals/relint 09ef3df 05/21: Describe the new xr wrapped subsumption warning

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 09ef3dfa9c31317bf508ab18eb0d8f1e31c0b568
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Describe the new xr wrapped subsumption warning
---
 README | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/README b/README
index 944e665..3ca9499 100644
--- a/README
+++ b/README
@@ -122,6 +122,17 @@ skip-syntax-backward.
 so the a* could be removed without changing the meaning of the
 regexp.
 
+  - First/last item in repetition subsumes last/first item (wrapped)
+
+The first and last items in a repeated sequence, being effectively
+adjacent, match a superset or subset of each other, which makes
+for an unexpected inefficiency. For example, \(?:a*c[ab]+\)* can
+be seen as a*c[ab]+a*c[ab]+... where the [ab]+a* in the middle is
+a slow way of writing [ab]+ which is made worse by the outer
+repetition. The general remedy is to move the subsumed item out of
+the repeated sequence, resulting in a*\(?:c[ab]+\)* in the example
+above.
+
   - Uncounted repetition
 
 The construct A\{,\} repeats A zero or more times which was



[elpa] externals/relint 5d3f78d 19/21: Update xr messages ("repetition" changed to "option")

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 5d3f78da32b03b8926076c10426366e07fd0f318
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Update xr messages ("repetition" changed to "option")
---
 README | 14 +++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/README b/README
index 34a7b5b..7d25c5e 100644
--- a/README
+++ b/README
@@ -71,11 +71,17 @@ skip-syntax-backward.
 in order to include a literal backslash.
   
   - Repetition of repetition
+  - Repetition of option
+  - Optional repetition
+  - Optional option
   
 A repetition construct is applied to an expression that is already
-repeated, such as a*+ (? counts as repetition here). Such
-expressions can be written with a single repetition and often
-indicate a different mistake, such as missing backslashes.
+repeated, such as a*+ or \(x?\)?. These expressions can be written
+with a single repetition and often indicate a different mistake,
+perhaps a missing backslash.
+
+When a repetition construct is ? or ??, it is termed 'option'
+instead; the principle is the same.
 
   - Reversed range 'Y-X' matches nothing
 
@@ -186,12 +192,14 @@ skip-syntax-backward.
 intended as part of a range.
 
   - Repetition of zero-width assertion
+  - Optional zero-width assertion
 
 A repetition operator was applied to a zero-width assertion, like
 ^ or \<, which is completely pointless. The error may be a missing
 escaping backslash.
 
   - Repetition of expression matching an empty string
+  - Optional expression matching an empty string
 
 A repetition operator was applied to a sub-expression that could
 match the empty string; this is not necessarily wrong, but such



[elpa] externals/relint f6d0fed 15/21: Describe the new file-specific warnings

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit f6d0fedd9bd876c741de17b7bb3db29983c338ab
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Describe the new file-specific warnings
---
 README | 16 
 1 file changed, 16 insertions(+)

diff --git a/README b/README
index f816349..34a7b5b 100644
--- a/README
+++ b/README
@@ -147,6 +147,22 @@ skip-syntax-backward.
 A pattern that only matches a non-empty string occurs right after
 an end-of-text anchor (\'). This combination can never match.
 
+  - Use \` instead of ^ in file-matching regexp
+  - Use \' instead of $ in file-matching regexp
+
+In a regexp used for matching a file name, newlines are usually
+not relevant. Line-start and line-end anchors should therefore
+probably be replaced with string-start and string-end,
+respectively. Otherwise, the regexp may fail for file names that
+do contain newlines.
+
+  - Possibly unescaped '.' in file-matching regexp
+
+In a regexp used for matching a file name, a naked dot is usually
+more likely to be a mistake (missing escaping backslash) than an
+actual intent to match any character except newline, since literal
+dots are very common in file name patterns.
+
   - Uncounted repetition
 
 The construct A\{,\} repeats A zero or more times which was



[elpa] externals/relint 96e26a5 02/21: Check keyword arguments :regexp and :regex

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 96e26a5f8f3967cf5b1e181831e94860f2be6c74
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check keyword arguments :regexp and :regex
---
 relint.el   | 8 +++-
 test/2.elisp| 4 
 test/2.expected | 6 ++
 3 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 567315c..bc4a9af 100644
--- a/relint.el
+++ b/relint.el
@@ -1965,11 +1965,17 @@ directly."
  ;; mutables since all args are evaluated once.
  (let ((index 0))
(while (consp form)
- (when (consp (car form))
+ (cond
+  ((consp (car form))
;; Check subforms with the assumption that nothing can be mutated,
;; since we don't really know what is evaluated when.
(relint--check-form-recursively-2
 (car form) nil file pos (cons index path)))
+  ((and (memq (car form) '(:regexp :regex))
+(consp (cdr form)))
+   (relint--check-re (cadr form)
+ (format "%s parameter" (car form))
+ file pos (cons (1+ index) path
  (setq form (cdr form))
  (setq index (1+ index)))
 
diff --git a/test/2.elisp b/test/2.elisp
index 1a2c4ea..a96cef0 100644
--- a/test/2.elisp
+++ b/test/2.elisp
@@ -50,3 +50,7 @@
 
 (defun f6 ()
   (f5 "[aa]" "[bb]" "[cc]" "[dd]" "[ee]"))
+
+(defun f7 ()
+  (alpha beta :regexp "[11]")
+  (gamma :regex "[22]" delta))
diff --git a/test/2.expected b/test/2.expected
index 0bde370..0dbcfc8 100644
--- a/test/2.expected
+++ b/test/2.expected
@@ -133,3 +133,9 @@
 2.elisp:52:31: In call to f5: Duplicated `d' inside character alternative (pos 
2)
   "[dd]"
..^
+2.elisp:55:26: In :regexp parameter: Duplicated `1' inside character 
alternative (pos 2)
+  "[11]"
+   ..^
+2.elisp:56:20: In :regex parameter: Duplicated `2' inside character 
alternative (pos 2)
+  "[22]"
+   ..^



[elpa] externals/relint a001a05 21/21: Increment version to 1.16

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit a001a05a1d692be22f7fac9233e8cc0102aebd30
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.16

Require xr 1.19
---
 relint.el | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index cbdd340..0651d3b 100644
--- a/relint.el
+++ b/relint.el
@@ -3,8 +3,8 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.15
-;; Package-Requires: ((xr "1.17") (emacs "26.1"))
+;; Version: 1.16
+;; Package-Requires: ((xr "1.19") (emacs "26.1"))
 ;; URL: https://github.com/mattiase/relint
 ;; Keywords: lisp, regexps
 
@@ -29,6 +29,12 @@
 
 ;;; News:
 
+;; Version 1.16:
+;; - Suppression comments now use regexp matching of messages
+;; - New filename-specific checks in calls to `directory-files' etc
+;; - Check some keyword arguments (:regexp and :regex)
+;; - Improved rx checks
+;; - `relint-directory' now displays number of files found
 ;; Version 1.15:
 ;; - Improved position accuracy in various lists of regexps
 ;; - Check for mistake in rx `any' forms



[elpa] externals/relint eb178d5 06/21: Check assignments to imenu-generic-expression

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit eb178d5f9d529ccc29785e277683faa661e73be4
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check assignments to imenu-generic-expression
---
 relint.el   | 16 +++-
 test/9.elisp|  5 +
 test/9.expected |  3 +++
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index 0c1653d..31f1887 100644
--- a/relint.el
+++ b/relint.el
@@ -1152,6 +1152,14 @@ or in the car of an element."
 (relint--check-re-string (car elem) ident file pos p)
form path))
 
+(defun relint--check-imenu-generic-expression (form name file pos path)
+  (relint--eval-list-iter
+   (lambda (elem elem-path literal)
+ (when (and (consp elem) (consp (cdr elem)) (stringp (cadr elem)))
+   (relint--check-re-string
+(cadr elem) name file pos (if literal (cons 1 elem-path) elem-path
+   form path))
+
 (defun relint--check-compilation-error-regexp-alist-alist (form name
file pos path)
   (relint--eval-list-iter
@@ -1701,6 +1709,9 @@ directly."
 ((memq name '(font-lock-defaults font-lock-keywords))
  (relint--check-font-lock-keywords expr name
file pos (cons i path)))
+((eq name 'imenu-generic-expression)
+ (relint--check-imenu-generic-expression
+  expr name file pos (cons i path)))
 (t
  ;; Invalidate the variable if it was local; otherwise, ignore.
  (let ((local (assq name relint--locals)))
@@ -1948,7 +1959,10 @@ directly."
(relint--check-re expr name file pos (cons 2 path)))
   ((memq name '(font-lock-defaults font-lock-keywords))
(relint--check-font-lock-keywords expr name
- file pos (cons 2 path)
+ file pos (cons 2 path)))
+  ((eq name 'imenu-generic-expression)
+   (relint--check-imenu-generic-expression
+expr name file pos (cons 2 path)
(`(define-generic-mode ,name ,_ ,_ ,font-lock-list ,auto-mode-list . ,_)
 (let ((origin (format "define-generic-mode %s" name)))
   (relint--check-font-lock-keywords font-lock-list origin
diff --git a/test/9.elisp b/test/9.elisp
index 322334f..4a37174 100644
--- a/test/9.elisp
+++ b/test/9.elisp
@@ -23,3 +23,8 @@
   (setq-local font-lock-defaults '(("[mm]" . tag)))
   (setq font-lock-defaults '(("[nn]" . tag)))
   (set (make-local-variable 'font-lock-defaults) '(("[oo]" . tag
+
+(defun test-9-ge ()
+  (setq-local imenu-generic-expression
+  '((nil "oh" 0)
+("*more*" "+a+" 0
diff --git a/test/9.expected b/test/9.expected
index ab3f06e..7bab898 100644
--- a/test/9.expected
+++ b/test/9.expected
@@ -43,3 +43,6 @@
 9.elisp:25:56: In font-lock-defaults (tag): Duplicated `o' inside character 
alternative (pos 2)
   "[oo]"
..^
+9.elisp:30:28: In imenu-generic-expression: Unescaped literal `+' (pos 0)
+  "+a+"
+   ^



[elpa] externals/relint cf2a2ae 14/21: Do file-specific checks on arguments to known functions

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit cf2a2ae075f132aab97a32fc4d0c8921068217bb
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Do file-specific checks on arguments to known functions

This includes directory-files, directory-files-and-attributes,
directory-files-recursively, load-history-filename-element,
and modify-coding-system-alist (with type = file).
---
 relint.el| 20 +++-
 test/12.elisp|  9 +
 test/12.expected | 15 +++
 3 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/relint.el b/relint.el
index 03a9421..1adcaee 100644
--- a/relint.el
+++ b/relint.el
@@ -1887,7 +1887,6 @@ directly."
'posix-looking-at 'posix-search-backward 'posix-search-forward
'posix-string-match
'search-forward-regexp 'search-backward-regexp
-   'load-history-filename-element
'kill-matching-buffers
'keep-lines 'flush-lines 'how-many)
   ,re-arg . ,_)
@@ -1895,9 +1894,14 @@ directly."
  (memq re-arg relint--checked-variables))
   (relint--check-re re-arg (format "call to %s" (car form))
 file pos (cons 1 path
+   (`(load-history-filename-element ,re-arg)
+(relint--check-file-name-re re-arg (format "call to %s" (car form))
+file pos (cons 1 path)))
+   (`(directory-files-recursively ,_ ,re-arg . ,_)
+(relint--check-file-name-re re-arg (format "call to %s" (car form))
+file pos (cons 2 path)))
(`(,(or 'split-string 'split-string-and-unquote
-   'string-trim-left 'string-trim-right 'string-trim
-   'directory-files-recursively)
+   'string-trim-left 'string-trim-right 'string-trim)
   ,_ ,re-arg . ,rest)
 (unless (and (symbolp re-arg)
  (memq re-arg relint--checked-variables))
@@ -1921,8 +1925,8 @@ directly."
 file pos (cons 4 path))
(`(,(or 'directory-files 'directory-files-and-attributes)
   ,_ ,_ ,re-arg . ,_)
-(relint--check-re re-arg (format "call to %s" (car form))
-  file pos (cons 3 path)))
+(relint--check-file-name-re re-arg (format "call to %s" (car form))
+file pos (cons 3 path)))
(`(,(or 'skip-chars-forward 'skip-chars-backward)
   ,skip-arg . ,_)
 (let ((str (relint--get-string skip-arg)))
@@ -2078,6 +2082,12 @@ directly."
(`(add-to-list 'auto-mode-alist ,elem . ,_)
 (relint--check-auto-mode-alist-expr
  elem (car form) file pos (cons 2 path)))
+   (`(modify-coding-system-alist ,type ,re-arg ,_)
+(funcall
+ (if (eq (relint--eval-or-nil type) 'file)
+ #'relint--check-file-name-re
+   #'relint--check-re)
+ re-arg (format "call to %s" (car form)) file pos (cons 2 path)))
(`(,name . ,args)
 (let ((alias (assq name relint--alias-defs)))
   (when alias
diff --git a/test/12.elisp b/test/12.elisp
index ea04551..04ea09c 100644
--- a/test/12.elisp
+++ b/test/12.elisp
@@ -14,3 +14,12 @@
 (setq auto-mode-alist (append '((".hh\\'" . some-mode)
 (".ii\\'" . some-mode))
   auto-mode-alist))
+
+;; File-matching regexp functions
+
+(defun f12 (d)
+  (directory-files d nil ".txt\\'")
+  (directory-files-and-attributes d nil "\\.pas$")
+  (directory-files-recursively d "^abc")
+  (modify-coding-system-alist 'file "\\.ml$" 'utf-8)
+  (modify-coding-system-alist 'process "+xx$" 'utf-8))
diff --git a/test/12.expected b/test/12.expected
index 6abea93..ecef078 100644
--- a/test/12.expected
+++ b/test/12.expected
@@ -22,3 +22,18 @@
 12.elisp:15:35: Possibly unescaped `.' in file-matching regexp (pos 0)
   ".ii\\'"
^
+12.elisp:21:27: Possibly unescaped `.' in file-matching regexp (pos 0)
+  ".txt\\'"
+   ^
+12.elisp:22:48: Use \' instead of $ in file-matching regexp (pos 5)
+  "\\.pas$"
+   ..^
+12.elisp:23:35: Use \` instead of ^ in file-matching regexp (pos 0)
+  "^abc"
+   ^
+12.elisp:24:43: Use \' instead of $ in file-matching regexp (pos 4)
+  "\\.ml$"
+   .^
+12.elisp:25:41: In call to modify-coding-system-alist: Unescaped literal `+' 
(pos 0)
+  "+xx$"
+   ^



[elpa] externals/relint a50ed0b 20/21: Don't escape printable chars in rx warnings

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit a50ed0b3c15339ae3979d3aa2ac61bf8bdf7a160
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Don't escape printable chars in rx warnings
---
 relint.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/relint.el b/relint.el
index b775b8a..cbdd340 100644
--- a/relint.el
+++ b/relint.el
@@ -1355,7 +1355,7 @@ character alternative: `[' followed by a 
regexp-generating expression."
(if (eq from to)
(char-to-string from)
  (format "%c-%c" from to))
-   t))
+   nil))
 
 (defun relint--intersecting-range (from to ranges)
   "Return a range in RANGES intersecting [FROM,TO], or nil if none.
@@ -1438,7 +1438,7 @@ than just to a surrounding or producing expression."
   file pos (if exact-path (cons i path) path)
   (format-message
"Single-character range `%s'"
-   (relint--escape-string (format "%c-%c" from to) t))
+   (relint--escape-string (format "%c-%c" from to) 
nil))
   s j))
 ((= to (1+ from))
  (relint--warn



[elpa] externals/relint 326cfe2 11/21: Check calls to directory-files(-and-attributes)

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 326cfe24cd110e4cf7686b4a154c7bdb55a727e8
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check calls to directory-files(-and-attributes)
---
 relint.el   |  4 
 test/2.elisp|  5 -
 test/2.expected | 49 +
 3 files changed, 37 insertions(+), 21 deletions(-)

diff --git a/relint.el b/relint.el
index b17d451..6c81221 100644
--- a/relint.el
+++ b/relint.el
@@ -1844,6 +1844,10 @@ directly."
  (memq trim relint--checked-variables))
   (relint--check-re trim (format "call to %s" (car form))
 file pos (cons 4 path))
+   (`(,(or 'directory-files 'directory-files-and-attributes)
+  ,_ ,_ ,re-arg . ,_)
+(relint--check-re re-arg (format "call to %s" (car form))
+  file pos (cons 3 path)))
(`(,(or 'skip-chars-forward 'skip-chars-backward)
   ,skip-arg . ,_)
 (let ((str (relint--get-string skip-arg)))
diff --git a/test/2.elisp b/test/2.elisp
index a96cef0..f069a33 100644
--- a/test/2.elisp
+++ b/test/2.elisp
@@ -26,7 +26,10 @@
   (split-string-and-unquote s "[vv]")
   (string-trim-left s "[ww]")
   (string-trim-right s "[xx]")
-  (string-trim s "[yy]" "[zz]"))
+  (string-trim s "[yy]" "[zz]")
+  (directory-files s nil "+1")
+  (directory-files-and-attributes s nil "+2")
+  (directory-files-recursively s "+3"))
 
 ;; Test argument names as means of detecting regexps.
 (defun f2 (x1 my-regexp x2 my-regex x3 my-re x4 my-pattern x5 re)
diff --git a/test/2.expected b/test/2.expected
index 0dbcfc8..347f31d 100644
--- a/test/2.expected
+++ b/test/2.expected
@@ -79,63 +79,72 @@
 2.elisp:29:28: In call to string-trim: Duplicated `z' inside character 
alternative (pos 2)
   "[zz]"
..^
-2.elisp:42:17: In call to f2: Duplicated `B' inside character alternative (pos 
2)
+2.elisp:30:27: In call to directory-files: Unescaped literal `+' (pos 0)
+  "+1"
+   ^
+2.elisp:31:42: In call to directory-files-and-attributes: Unescaped literal 
`+' (pos 0)
+  "+2"
+   ^
+2.elisp:32:35: In call to directory-files-recursively: Unescaped literal `+' 
(pos 0)
+  "+3"
+   ^
+2.elisp:45:17: In call to f2: Duplicated `B' inside character alternative (pos 
2)
   "[BB]"
..^
-2.elisp:42:31: In call to f2: Duplicated `D' inside character alternative (pos 
2)
+2.elisp:45:31: In call to f2: Duplicated `D' inside character alternative (pos 
2)
   "[DD]"
..^
-2.elisp:42:45: In call to f2: Duplicated `F' inside character alternative (pos 
2)
+2.elisp:45:45: In call to f2: Duplicated `F' inside character alternative (pos 
2)
   "[FF]"
..^
-2.elisp:42:59: In call to f2: Duplicated `H' inside character alternative (pos 
2)
+2.elisp:45:59: In call to f2: Duplicated `H' inside character alternative (pos 
2)
   "[HH]"
..^
-2.elisp:42:73: In call to f2: Duplicated `J' inside character alternative (pos 
2)
+2.elisp:45:73: In call to f2: Duplicated `J' inside character alternative (pos 
2)
   "[JJ]"
..^
-2.elisp:43:17: In call to s2: Duplicated `B' inside character alternative (pos 
2)
+2.elisp:46:17: In call to s2: Duplicated `B' inside character alternative (pos 
2)
   "[BB]"
..^
-2.elisp:43:31: In call to s2: Duplicated `D' inside character alternative (pos 
2)
+2.elisp:46:31: In call to s2: Duplicated `D' inside character alternative (pos 
2)
   "[DD]"
..^
-2.elisp:43:45: In call to s2: Duplicated `F' inside character alternative (pos 
2)
+2.elisp:46:45: In call to s2: Duplicated `F' inside character alternative (pos 
2)
   "[FF]"
..^
-2.elisp:43:59: In call to s2: Duplicated `H' inside character alternative (pos 
2)
+2.elisp:46:59: In call to s2: Duplicated `H' inside character alternative (pos 
2)
   "[HH]"
..^
-2.elisp:43:73: In call to s2: Duplicated `J' inside character alternative (pos 
2)
+2.elisp:46:73: In call to s2: Duplicated `J' inside character alternative (pos 
2)
   "[JJ]"
..^
-2.elisp:44:17: In call to m2: Duplicated `B' inside character alternative (pos 
2)
+2.elisp:47:17: In call to m2: Duplicated `B' inside character alternative (pos 
2)
   "[BB]"
..^
-2.elisp:44:31: In call to m2: Duplicated `D' inside character alternative (pos 
2)
+2.elisp:47:31: In call to m2: Duplicated `D' inside character alternative (pos 
2)
   "[DD]"
..^
-2.elisp:44:45: In call to m2: Duplicated `F' inside character alternative (pos 
2)
+2.elisp:47:45: In call to m2: Duplicated `F' inside character alternative (pos 
2)
   "[FF]"
..^
-2.elisp:44:59: In call to m2: Duplicated `H' inside character alternative (pos 
2)
+2.elisp:47:59: In call to m2: Duplicated `H' inside character alternative (pos 
2)
   "[HH]"
..^
-2.elisp:44:73: In call to m2: Duplicated `J' inside character alternative (pos 
2)
+2.elisp:47:73: In call to m2: Duplicated `J' inside character alternative (pos 
2)
   "[JJ]"
..^
-2.elisp:52:17: In call to f5: Duplicated `b' inside character alternative 

[elpa] externals/relint b694c09 07/21: Check split ASCII-raw ranges in rx correctly

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit b694c091dcb36ed4fd3a1f0d8f4a14cf9d5f9b74
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check split ASCII-raw ranges in rx correctly

Also make sure not to confuse raw bytes and U+0080-U+00FF.
---
 relint.el| 44 ++--
 test/11.elisp|  7 ++-
 test/11.expected |  6 ++
 3 files changed, 42 insertions(+), 15 deletions(-)

diff --git a/relint.el b/relint.el
index 31f1887..d5b329e 100644
--- a/relint.el
+++ b/relint.el
@@ -1383,13 +1383,15 @@ than just to a surrounding or producing expression."
(push (cons arg arg) ranges))
 
   ((stringp arg)
-   (let ((j 0)
- (len (length arg)))
+   (let* ((s (string-to-multibyte arg))
+  (j 0)
+  (len (length s)))
  (while (< j len)
-   (let ((from (aref arg j)))
+   (let ((from (aref s j)))
  (if (and (< (+ j 2) len)
-  (eq (aref arg (1+ j)) ?-))
- (let ((to (aref arg (+ j 2
+  (eq (aref s (1+ j)) ?-))
+ ;; Range.
+ (let ((to (aref s (+ j 2
(cond
 ;; When people write "+-X" or "X-+" for some
 ;; X, they rarely mean a range.
@@ -1399,22 +1401,30 @@ than just to a surrounding or producing expression."
   file pos (if exact-path (cons i path) path)
   (format-message "Suspect range `%s'"
   (relint--pretty-range from to))
-  arg j))
+  s j))
 ((= to from)
  (relint--warn
   file pos (if exact-path (cons i path) path)
   (format-message
"Single-character range `%s'"
(relint--escape-string (format "%c-%c" from to) t))
-  arg j))
+  s j))
 ((= to (1+ from))
  (relint--warn
   file pos (if exact-path (cons i path) path)
   (format-message "Two-character range `%s'"
   (relint--pretty-range from to))
-  arg j)))
-   (let ((overlap
-  (relint--intersecting-range from to ranges)))
+  s j)))
+   ;; Take care to split ASCII-raw ranges; they do not
+   ;; include anything in-between.
+   (let* ((split (and (<= from #x7f) (>= to #x3fff80)))
+  (overlap
+   (if split
+   (or (relint--intersecting-range
+from #x7f ranges)
+   (relint--intersecting-range
+#x3fff80 to ranges))
+ (relint--intersecting-range from to ranges
  (when overlap
(relint--warn
 file pos (if exact-path (cons i path) path)
@@ -1422,15 +1432,21 @@ than just to a surrounding or producing expression."
 (relint--pretty-range from to)
 (relint--pretty-range
  (car overlap) (cdr overlap)))
-arg j)))
-   (push (cons from to) ranges)
+s j))
+ (if split
+ (progn
+   (push (cons from #x7f) ranges)
+   (push (cons #x3fff80 to) ranges))
+   (push (cons from to) ranges)))
(setq j (+ j 3)))
+
+   ;; Single character.
(when (and (eq from ?-)
   (< 0 j (1- len)))
  (relint--warn
   file pos (if exact-path (cons i path) path)
   (format-message "Literal `-' not first or last")
-  arg j))
+  s j))
(let ((overlap
   (relint--intersecting-range from from ranges)))
  (when overlap
@@ -1443,7 +1459,7 @@ than just to a surrounding or producing expression."
"Character `%s' included in range `%s'"
(relint--pretty-range from from)
(relint--pretty-range (car overlap) (cdr overlap
-arg j)))
+  

[elpa] externals/relint 12a2b0f 08/21: Use regexp in suppression comments

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 12a2b0fafdba26526e2b166a322a6171fac19cc4
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Use regexp in suppression comments

This adds flexibility, in particular for coping with different quoting
styles.
---
 README   |  6 +++---
 relint.el| 10 +-
 test/6.elisp |  4 ++--
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/README b/README
index 3ca9499..7a355c4 100644
--- a/README
+++ b/README
@@ -265,10 +265,10 @@ skip-syntax-backward.
 
   To suppress such diagnostics, add a comment on the form
 
-;; relint suppression: MESSAGE
+;; relint suppression: REGEXP
 
-  on the line before the code where the error occurred. MESSAGE is a
-  substring of the message to be suppressed. Multiple suppression
+  on the line before the code where the error occurred. REGEXP
+  matches the message to be suppressed. Multiple suppression
   comment lines can precede a line of code to eliminate several
   complaints on the same line.
 
diff --git a/relint.el b/relint.el
index d5b329e..b17d451 100644
--- a/relint.el
+++ b/relint.el
@@ -209,9 +209,9 @@ or nil if no position could be determined."
   (save-excursion
 ;; On a preceding line, look for a comment on the form
 ;;
-;; relint suppression: SUBSTRING
+;; relint suppression: REGEXP
 ;;
-;; where SUBSTRING is a substring of MESSAGE. There can be
+;; where REGEXP matches MESSAGE. There can be
 ;; multiple suppression lines preceding a line of code with
 ;; several errors.
 (goto-char pos)
@@ -221,11 +221,11 @@ or nil if no position could be determined."
   (not (setq matched
  (and
   (looking-at (rx (0+ blank) (1+ ";") (0+ blank)
-  "relint suppression:" (0+ blank)
+  "relint suppression:" (1+ blank)
   (group (0+ nonl)
  (not (any "\n" blank)
-  (let ((substr (match-string 1)))
-(string-match-p (regexp-quote substr) message)
+  (let ((regexp (match-string 1)))
+(string-match-p regexp message)
   (looking-at (rx bol
   (0+ blank) (opt ";" (0+ nonl))
   eol))
diff --git a/test/6.elisp b/test/6.elisp
index ac07fc1..cbbdf4b 100644
--- a/test/6.elisp
+++ b/test/6.elisp
@@ -48,8 +48,8 @@
 
 ;; Test suppression
 (defun test-suppression ()
-  ;; relint suppression: Unescaped literal `$'
-  ;; relint suppression: Duplicated `a'
+  ;; relint suppression: Unescaped literal .\$
+  ;; relint suppression: Duplicated .a
   (looking-at "$[aa]"))
 
 ;; Test user-defined regexp-generating functions



[elpa] externals/relint ac75b62 04/21: Check rx-to-string, and the 'regexp' and 'eval' subforms

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit ac75b6211e1a9ee0e173641981310550d5193dd3
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check rx-to-string, and the 'regexp' and 'eval' subforms

This includes special treatment for backquoted forms.
---
 relint.el| 54 --
 test/11.elisp| 11 ++-
 test/11.expected | 21 +
 3 files changed, 71 insertions(+), 15 deletions(-)

diff --git a/relint.el b/relint.el
index d484116..0c1653d 100644
--- a/relint.el
+++ b/relint.el
@@ -1328,8 +1328,10 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
 (setq ranges (cdr ranges)))
   (car ranges))
 
-(defun relint--check-rx (item file pos path)
-  "Check the `rx' expression ITEM."
+(defun relint--check-rx (item file pos path exact-path)
+  "Check the `rx' expression ITEM.
+EXACT-PATH indicates whether PATH leads to ITEM exactly, rather
+than just to a surrounding or producing expression."
   (pcase item
 (`(,(or ': 'seq 'sequence 'and 'or '|
 'not 'intersection 'repeat '= '>= '**
@@ -1343,7 +1345,9 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
  ;; Form with subforms: recurse.
  (let ((i 1))
(dolist (arg args)
- (relint--check-rx arg file pos (cons i path))
+ (relint--check-rx arg file pos
+   (if exact-path (cons i path) path)
+   exact-path)
  (setq i (1+ i)
 
 (`(,(or 'any 'in 'char 'not-char) . ,args)
@@ -1360,7 +1364,7 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
(let ((overlap (relint--intersecting-range arg arg ranges)))
  (when overlap
(relint--warn
-file pos (cons i path)
+file pos (if exact-path (cons i path) path)
 (if (eq (car overlap) (cdr overlap))
 (format-message "Duplicated character `%s'"
 (relint--pretty-range arg arg))
@@ -1384,20 +1388,20 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
 ((or (eq from ?+)
  (eq to ?+))
  (relint--warn
-  file pos (cons i path)
+  file pos (if exact-path (cons i path) path)
   (format-message "Suspect range `%s'"
   (relint--pretty-range from to))
   arg j))
 ((= to from)
  (relint--warn
-  file pos (cons i path)
+  file pos (if exact-path (cons i path) path)
   (format-message
"Single-character range `%s'"
(relint--escape-string (format "%c-%c" from to) t))
   arg j))
 ((= to (1+ from))
  (relint--warn
-  file pos (cons i path)
+  file pos (if exact-path (cons i path) path)
   (format-message "Two-character range `%s'"
   (relint--pretty-range from to))
   arg j)))
@@ -1405,7 +1409,7 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
   (relint--intersecting-range from to ranges)))
  (when overlap
(relint--warn
-file pos (cons i path)
+file pos (if exact-path (cons i path) path)
 (format-message "Range `%s' overlaps previous `%s'"
 (relint--pretty-range from to)
 (relint--pretty-range
@@ -1416,14 +1420,14 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."
(when (and (eq from ?-)
   (< 0 j (1- len)))
  (relint--warn
-  file pos (cons i path)
+  file pos (if exact-path (cons i path) path)
   (format-message "Literal `-' not first or last")
   arg j))
(let ((overlap
   (relint--intersecting-range from from ranges)))
  (when overlap
(relint--warn
-file pos (cons i path)
+file pos (if exact-path (cons i path) path)
 (if (eq (car overlap) (cdr overlap))
 (format-message "Duplicated character `%s'"
 (relint--pretty-range from from))
@@ -1444,7 +1448,7 @@ RANGES is a list of (X . Y) representing the interval 
[X,Y]."

[elpa] externals/relint 4fcc322 16/21: Delay call to file-relative-name until needed

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 4fcc3220975815471242dff222d9316d58920c53
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Delay call to file-relative-name until needed

ENCODE_FILE and DECODE_FILE, present in many file and filename
manipulation primitives, are quite expensive and allocate a lot, even
when names are pure ASCII.

We don't actually need to call file-relative-name until there is a
diagnostic emitted for that file, so evaluate it lazily.

This should really be fixed in Emacs, but meanwhile this mitigation
doesn't hurt.
---
 relint.el | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/relint.el b/relint.el
index 1adcaee..e2eefcf 100644
--- a/relint.el
+++ b/relint.el
@@ -91,6 +91,7 @@
 (require 'xr)
 (require 'compile)
 (require 'cl-lib)
+(require 'thunk)
 
 (defvar relint--error-buffer)
 (defvar relint--quiet)
@@ -263,7 +264,8 @@ or nil if no position could be determined."
  (error-pos (and str-idx (relint--string-pos expr-pos str-idx
 (if (relint--suppression expr-pos message)
 (setq relint--suppression-count (1+ relint--suppression-count))
-  (funcall relint--report-function file expr-pos error-pos message
+  (funcall relint--report-function
+   (thunk-force file) expr-pos error-pos message
str str-idx severity)))
   (setq relint--error-count (1+ relint--error-count)))
 
@@ -2191,8 +2193,11 @@ Return a list of (FORM . STARTING-POSITION)."
   (with-temp-buffer
 (emacs-lisp-mode)
 (insert-file-contents file)
-(relint--scan-current-buffer (file-relative-name file base-dir
-
+;; Call file-relative-name lazily -- it is surprisingly expensive
+;; on macOS, and the result only used for diagnostics output.
+(relint--scan-current-buffer
+ (thunk-delay (file-relative-name file base-dir)
+
 (defvar relint-last-target nil
   "The last file, directory or buffer on which relint was run.")
 



[elpa] externals/relint 2eba4d7 09/21: Describe new bol/eol/eos warnings

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 2eba4d72e8592cd0891ee5652c5bdd323c72f5ea
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Describe new bol/eol/eos warnings
---
 README | 12 
 1 file changed, 12 insertions(+)

diff --git a/README b/README
index 7a355c4..777d9d0 100644
--- a/README
+++ b/README
@@ -133,6 +133,18 @@ skip-syntax-backward.
 the repeated sequence, resulting in a*\(?:c[ab]+\)* in the example
 above.
 
+  - End-of-line anchor followed by non-newline
+  - Non-newline followed by line-start anchor
+
+A pattern that does not match a newline occurs right after an
+end-of-line anchor ($) or before a line-start anchor (^).
+This combination can never match.
+
+  - End-of-text anchor followed by non-empty pattern
+
+A pattern that only matches a non-empty string occurs right after
+an end-of-text anchor (\'). This combination can never match.
+
   - Uncounted repetition
 
 The construct A\{,\} repeats A zero or more times which was



[elpa] externals/xr 35dbbeb 10/10: Increment version to 1.19

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit 35dbbebc86385e2d89668f42f4997a355e17ec04
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Increment version to 1.19
---
 xr.el | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/xr.el b/xr.el
index 560cfed..6bbf5e7 100644
--- a/xr.el
+++ b/xr.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
 
 ;; Author: Mattias Engdegård 
-;; Version: 1.18
+;; Version: 1.19
 ;; Package-Requires: ((emacs "26.1"))
 ;; URL: https://github.com/mattiase/xr
 ;; Keywords: lisp, regexps
@@ -29,6 +29,11 @@
 
 ;;; News:
 
+;; Version 1.19:
+;; - Added filename-specific checks; new PURPOSE argument to `xr-lint'
+;; - Warn about wrapped subsumption, like \(A*C[AB]*\)+
+;; - Improved scope and accuracy of all subsumption checks
+;; - Warn about anchors in conflict with other expressions, like \(A$\)B
 ;; Version 1.18:
 ;; - Fix test broken in Emacs 26
 ;; Version 1.17:



[elpa] externals/relint 1bf7f25 13/21: Check auto-mode-alist with file-specific checks

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 1bf7f25a9fff55e177734ba14b41736ce77f9862
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check auto-mode-alist with file-specific checks

This also includes additions to auto-mode-alist via add-to-list or setq.
---
 relint.el| 55 ++-
 test/12.elisp| 16 
 test/12.expected | 24 
 3 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/relint.el b/relint.el
index 89c2461..03a9421 100644
--- a/relint.el
+++ b/relint.el
@@ -1090,13 +1090,16 @@ source."
 (when re
   (relint--check-re-string re name file pos path
 
-(defun relint--check-list (form name file pos path)
+(defun relint--check-list (form name file pos path is-file-name)
   "Check a list of regexps."
-  (relint--eval-list-iter
-   (lambda (elem elem-path _literal)
- (when (stringp elem)
-   (relint--check-re-string elem name file pos elem-path)))
-   form path))
+  (let ((check (if is-file-name
+   #'relint--check-file-name-re
+ #'relint--check-re-string)))
+(relint--eval-list-iter
+ (lambda (elem elem-path _literal)
+   (when (stringp elem)
+ (funcall check elem name file pos elem-path)))
+ form path)))
 
 (defun relint--check-list-any (form name file pos path)
   "Check a list of regexps or conses whose car is a regexp."
@@ -1215,6 +1218,24 @@ or in the car of an element."
   (relint--check-re re name file pos path)
   (relint--extra-file-name-re-checks re file pos path
 
+(defun relint--check-auto-mode-alist-expr (form name file pos path)
+  "Check a single element added to `auto-mode-alist'."
+  (pcase form
+(`(quote (,(and (pred stringp) str) . ,_))
+ (relint--check-file-name-re str name file pos (cons 0 (cons 1 path
+(_
+ (let ((val (relint--eval-or-nil form)))
+   (when (and (consp val) (stringp (car val)))
+ (relint--check-file-name-re (car val) name file pos path))
+
+(defun relint--check-auto-mode-alist (form name file pos path)
+  (relint--eval-list-iter
+   (lambda (elem elem-path literal)
+ (relint--check-file-name-re
+  (car elem) name
+  file pos (if literal (cons 0 elem-path) elem-path)))
+   form path))
+
 (defun relint--check-rules-list (form name file pos path)
   "Check a variable on `align-mode-rules-list' format"
   (relint--eval-list-iter
@@ -1663,7 +1684,7 @@ than just to a surrounding or producing expression."
  (relint--check-defcustom-type (relint--eval-or-nil type)
name file pos (cons index path)))
 (`(:options ,options)
- (relint--check-list options name file pos (cons index path
+ (relint--check-list options name file pos (cons index path) nil)))
   (setq index (+ index 2))
   (setq args (cddr args)
 
@@ -1772,6 +1793,14 @@ directly."
 ((eq name 'imenu-generic-expression)
  (relint--check-imenu-generic-expression
   expr name file pos (cons i path)))
+((eq name 'auto-mode-alist)
+ (pcase expr
+   (`(cons ,item auto-mode-alist)
+(relint--check-auto-mode-alist-expr
+ item name file pos (cons 1 (cons i path
+   (`(append ,items auto-mode-alist)
+(relint--check-auto-mode-alist
+ items name file pos (cons 1 (cons i path))
 (t
  ;; Invalidate the variable if it was local; otherwise, ignore.
  (let ((local (assq name relint--locals)))
@@ -1787,6 +1816,8 @@ directly."
 (`(push ,expr ,(and (pred symbolp) name))
  ;; Treat (push EXPR NAME) as (setq NAME (cons EXPR NAME)).
  (relint--check-form-recursively-2 expr mutables file pos (cons 1 path))
+ (when (eq name 'auto-mode-alist)
+   (relint--check-auto-mode-alist-expr expr name file pos (cons 1 path)))
  (let ((local (assq name relint--locals)))
(when local
  (setcdr local
@@ -1949,7 +1980,7 @@ directly."
"-list"))
   eos)
   (symbol-name name)))
-  (relint--check-list re-arg name file pos (cons 2 path))
+  (relint--check-list re-arg name file pos (cons 2 path) nil)
   (push name relint--checked-variables))
  ((string-match-p (rx "font-lock-keywords")
   (symbol-name name))
@@ -1960,6 +1991,9 @@ directly."
   (relint--check-compilation-error-regexp-alist-alist
re-arg name file pos (cons 2 path))
   (push name relint--checked-variables))
+ ((eq name 'auto-mode-alist)
+  (relint--check-auto-mode-alist
+   re-arg name file pos (cons 2 path)))
  ((string-match-p (rx (or "-regexp" "-regex" "-re" 

[elpa] externals/relint 008fad0 17/21: Repair relint-current-buffer after thunking file parameter

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 008fad0182055fde788b1df8757db49a299291b8
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Repair relint-current-buffer after thunking file parameter
---
 relint.el | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/relint.el b/relint.el
index e2eefcf..ba10355 100644
--- a/relint.el
+++ b/relint.el
@@ -2272,7 +2272,7 @@ Diagnostics to ERROR-BUFFER. If QUIET, don't emit 
messages."
   (error "Relint: can only scan elisp code (use emacs-lisp-mode)"))
 (relint--init buffer default-directory error-buffer quiet)
 (save-excursion
-  (relint--scan-current-buffer (buffer-name
+  (relint--scan-current-buffer (thunk-delay (buffer-name)
   (relint--finish))
 
 



[elpa] externals/relint 8f49686 18/21: Move file-specific checks to xr

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 8f49686f268dc10e1074f1c344084e3f2bafc7ee
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Move file-specific checks to xr
---
 relint.el| 48 ++--
 test/12.expected | 24 
 2 files changed, 18 insertions(+), 54 deletions(-)

diff --git a/relint.el b/relint.el
index ba10355..b775b8a 100644
--- a/relint.el
+++ b/relint.el
@@ -320,6 +320,9 @@ or nil if no position could be determined."
 (defun relint--check-re-string (re name file pos path)
   (relint--check-string re #'xr-lint name file pos path))
   
+(defun relint--check-file-re-string (re name file pos path)
+  (relint--check-string re (lambda (x) (xr-lint x 'file)) name file pos path))
+  
 (defun relint--check-syntax-string (syntax name file pos path)
   (relint--check-string syntax #'relint--syntax-string-lint name file pos 
path))
 
@@ -1176,59 +1179,20 @@ or in the car of an element."
 file pos (if literal (cons 1 elem-path) elem-path
form path))
 
-(defun relint--extra-file-name-re-checks (string file pos path)
-  "Perform extra checks on STRING assuming it matches file names."
-
-  ;; It would be much easier to do these checks (and more) on the rx
-  ;; representation, but unfortunately xr doesn't return a
-  ;; location-annotated expression right now.
-  (let ((len (length string))
-(start 0))
-(while (and (< start len)
-;; Skip anything that is NOT one of . ^ $
-(string-match (rx (* (or (not (any "\\.$^["))
- (seq "\\" anything)
- (seq "[" (opt "^") (opt "]")
-  (* (not (any "]")))
-  "]"
-  string start))
-  (setq start (match-end 0))
-  (let* ((m (string-match (rx (or "^" "$" (seq "." (opt (any "*+?")
-  string start))
- (end (match-end 0)))
-(when (and m (= m start))
-  (pcase (match-string 0 string)
-("^" (relint--warn
-  file pos path
-  "Use \\` instead of ^ in file-matching regexp"
-  string start))
-("$" (relint--warn
-  file pos path
-  "Use \\' instead of $ in file-matching regexp"
-  string start))
-;; We assume that .* etc are intended.
-("." (relint--warn
-  file pos path
-  (format-message
-   "Possibly unescaped `.' in file-matching regexp")
-  string start)))
-  (setq start end))
-
 (defun relint--check-file-name-re (form name file pos path)
   (let ((re (relint--get-string form)))
 (when re
-  (relint--check-re re name file pos path)
-  (relint--extra-file-name-re-checks re file pos path
+  (relint--check-file-re-string re name file pos path
 
 (defun relint--check-auto-mode-alist-expr (form name file pos path)
   "Check a single element added to `auto-mode-alist'."
   (pcase form
 (`(quote (,(and (pred stringp) str) . ,_))
- (relint--check-file-name-re str name file pos (cons 0 (cons 1 path
+ (relint--check-file-re-string str name file pos (cons 0 (cons 1 path
 (_
  (let ((val (relint--eval-or-nil form)))
(when (and (consp val) (stringp (car val)))
- (relint--check-file-name-re (car val) name file pos path))
+ (relint--check-file-re-string (car val) name file pos path))
 
 (defun relint--check-auto-mode-alist (form name file pos path)
   (relint--eval-list-iter
diff --git a/test/12.expected b/test/12.expected
index ecef078..e0ab05b 100644
--- a/test/12.expected
+++ b/test/12.expected
@@ -1,37 +1,37 @@
-12.elisp:9:6: Possibly unescaped `.' in file-matching regexp (pos 0)
+12.elisp:9:6: In define-generic-mode my-mode: Possibly unescaped `.' in 
file-matching regexp (pos 0)
   ".aa\\'"
^
-12.elisp:9:20: Use \' instead of $ in file-matching regexp (pos 4)
+12.elisp:9:20: In define-generic-mode my-mode: Use \' instead of $ in 
file-matching regexp (pos 4)
   "\\.bb$"
.^
-12.elisp:9:24: Use \` instead of ^ in file-matching regexp (pos 0)
+12.elisp:9:24: In define-generic-mode my-mode: Use \` instead of ^ in 
file-matching regexp (pos 0)
   "^cc.*dd"
^
-12.elisp:11:39: Use \' instead of $ in file-matching regexp (pos 4)
+12.elisp:11:39: In add-to-list: Use \' instead of $ in file-matching regexp 
(pos 4)
   "\\.ee$"
.^
-12.elisp:12:10: Possibly unescaped `.' in file-matching regexp (pos 0)
+12.elisp:12:10: In auto-mode-alist: Possibly unescaped `.' in file-matching 
regexp (pos 0)
   ".ff\\'"
^
-12.elisp:13:32: Possibly unescaped `.' in file-matching regexp (pos 0)
+12.elisp:13:32: In auto-mode-alist: Possibly unescaped `.' in file-matching 
regexp (pos 0)
   ".gg\\'"
^

[elpa] externals/relint cdd65ae 10/21: Add section about how relint works

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit cdd65ae90343eec0774a86741d8104a524b1aad8
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add section about how relint works
---
 README | 36 +++-
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/README b/README
index 777d9d0..f816349 100644
--- a/README
+++ b/README
@@ -36,6 +36,7 @@ skip-syntax-backward.
 
 which returns a list of diagnostics.
 
+
 * Installation
 
   From GNU ELPA (https://elpa.gnu.org/packages/relint.html):
@@ -45,6 +46,7 @@ skip-syntax-backward.
   Relint requires the package xr (https://elpa.gnu.org/packages/xr.html);
   it will be installed automatically.
 
+
 * What the diagnostics mean
 
   - Unescaped literal 'X'
@@ -268,6 +270,7 @@ skip-syntax-backward.
 A string argument to skip-syntax-forward or skip-syntax-backward
 is empty or "^", neither of which makes sense.
 
+
 * Suppressing diagnostics
 
   While relint has been designed to avoid false positives, there may
@@ -284,11 +287,34 @@ skip-syntax-backward.
   comment lines can precede a line of code to eliminate several
   complaints on the same line.
 
+
+* How it works
+
+  Relint uses a combination of ad-hoc rules to locate regexps:
+
+  - Arguments to standard functions taking regexps as arguments,
+such as re-search-forward, or to user-defined functions
+whose arguments have regexp-sounding names (like 'regexp')
+
+  - Values of variables believed to be a regexp from their name
+(ending in '-regexp', for instance), from their doc string,
+or from their type (for defcustom forms)
+
+  - Assignment to certain standard variables, such as page-delimiter
+
+  It will then try to evaluate expressions statically as far as
+  possible, to arrive at strings which can be analysed. The regexp
+  analysis is done by the xr library.
+
+  This means that if relint complains about something that isn't
+  actually a regexp, some names in your code may be misleading.
+
+
 * Bugs
 
-  The recognition of regexps is done by ad-hoc rules; the simplistic
-  method employed means that many errors will go undetected.
+  The simplistic method employed means that many errors will go
+  undetected, but false warnings are usually rare.
 
-  Still, if you believe that a flawed regexp could have been
-  discovered but wasn't, please report it as a bug. Reports of false
-  positives and crashes are of course equally welcome.
+  If you believe that an error could have been discovered but wasn't,
+  or that an unwarranted complaint could be avoided, please report it
+  as a bug.



[elpa] externals/relint 636e172 12/21: Add filename-specific checks (unused so far)

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit 636e1725f985c6cf30de04cf1396a413dd89a598
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add filename-specific checks (unused so far)

This includes checks for ^ and $ (use \` and \' instead),
and for . (should probably be \.)
---
 relint.el | 44 
 1 file changed, 44 insertions(+)

diff --git a/relint.el b/relint.el
index 6c81221..89c2461 100644
--- a/relint.el
+++ b/relint.el
@@ -1171,6 +1171,50 @@ or in the car of an element."
 file pos (if literal (cons 1 elem-path) elem-path
form path))
 
+(defun relint--extra-file-name-re-checks (string file pos path)
+  "Perform extra checks on STRING assuming it matches file names."
+
+  ;; It would be much easier to do these checks (and more) on the rx
+  ;; representation, but unfortunately xr doesn't return a
+  ;; location-annotated expression right now.
+  (let ((len (length string))
+(start 0))
+(while (and (< start len)
+;; Skip anything that is NOT one of . ^ $
+(string-match (rx (* (or (not (any "\\.$^["))
+ (seq "\\" anything)
+ (seq "[" (opt "^") (opt "]")
+  (* (not (any "]")))
+  "]"
+  string start))
+  (setq start (match-end 0))
+  (let* ((m (string-match (rx (or "^" "$" (seq "." (opt (any "*+?")
+  string start))
+ (end (match-end 0)))
+(when (and m (= m start))
+  (pcase (match-string 0 string)
+("^" (relint--warn
+  file pos path
+  "Use \\` instead of ^ in file-matching regexp"
+  string start))
+("$" (relint--warn
+  file pos path
+  "Use \\' instead of $ in file-matching regexp"
+  string start))
+;; We assume that .* etc are intended.
+("." (relint--warn
+  file pos path
+  (format-message
+   "Possibly unescaped `.' in file-matching regexp")
+  string start)))
+  (setq start end))
+
+(defun relint--check-file-name-re (form name file pos path)
+  (let ((re (relint--get-string form)))
+(when re
+  (relint--check-re re name file pos path)
+  (relint--extra-file-name-re-checks re file pos path
+
 (defun relint--check-rules-list (form name file pos path)
   "Check a variable on `align-mode-rules-list' format"
   (relint--eval-list-iter



[elpa] externals/relint updated (83e677d -> a001a05)

2020-05-03 Thread Mattias Engdeg�rd
mattiase pushed a change to branch externals/relint.

  from  83e677d   Increment version to 1.15
   new  ba7b747   Display the number of files found in relint-directory
   new  96e26a5   Check keyword arguments :regexp and :regex
   new  9259a5c   Check some :value parameters in defcustom :type clauses
   new  ac75b62   Check rx-to-string, and the 'regexp' and 'eval' subforms
   new  09ef3df   Describe the new xr wrapped subsumption warning
   new  eb178d5   Check assignments to imenu-generic-expression
   new  b694c09   Check split ASCII-raw ranges in rx correctly
   new  12a2b0f   Use regexp in suppression comments
   new  2eba4d7   Describe new bol/eol/eos warnings
   new  cdd65ae   Add section about how relint works
   new  326cfe2   Check calls to directory-files(-and-attributes)
   new  636e172   Add filename-specific checks (unused so far)
   new  1bf7f25   Check auto-mode-alist with file-specific checks
   new  cf2a2ae   Do file-specific checks on arguments to known functions
   new  f6d0fed   Describe the new file-specific warnings
   new  4fcc322   Delay call to file-relative-name until needed
   new  008fad0   Repair relint-current-buffer after thunking file parameter
   new  8f49686   Move file-specific checks to xr
   new  5d3f78d   Update xr messages ("repetition" changed to "option")
   new  a50ed0b   Don't escape printable chars in rx warnings
   new  a001a05   Increment version to 1.16


Summary of changes:
 README   |  95 +---
 relint.el| 264 +--
 test/1.elisp |  13 +++
 test/1.expected  |  30 +--
 test/11.elisp|  16 +++-
 test/11.expected |  27 ++
 test/12.elisp|  25 ++
 test/12.expected |  39 
 test/2.elisp |   9 +-
 test/2.expected  |  51 +++
 test/6.elisp |   4 +-
 test/9.elisp |   5 ++
 test/9.expected  |   3 +
 13 files changed, 475 insertions(+), 106 deletions(-)
 create mode 100644 test/12.elisp
 create mode 100644 test/12.expected



[elpa] externals/relint ba7b747 01/21: Display the number of files found in relint-directory

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/relint
commit ba7b7474ae08968d5a0341b9ce79757848ef759c
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Display the number of files found in relint-directory
---
 relint.el | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/relint.el b/relint.el
index a53e2c0..567315c 100644
--- a/relint.el
+++ b/relint.el
@@ -2125,9 +2125,12 @@ Diagnostics to ERROR-BUFFER. If QUIET, don't emit 
messages."
   "Scan all *.el files in DIR for regexp-related errors."
   (interactive "DRelint directory: ")
   (message "Finding .el files in %s..." dir)
-  (let ((files (relint--tree-files dir)))
-(message "Scanning files...")
-(relint--scan-files files dir dir (relint--get-error-buffer
+  (let* ((files (relint--tree-files dir))
+ (n (length files)))
+(if (not files)
+(message "No .el files found.")
+  (message "Scanning %d file%s..." n (if (= n 1) "" "s"))
+  (relint--scan-files files dir dir (relint--get-error-buffer)
 
 ;;;###autoload
 (defun relint-current-buffer ()



[elpa] externals/xr d752aab 09/10: Use "option" instead of "repetition" in diagnostics for ? and ??

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit d752aabeae1c5f29fff810f43a3f96f34366603f
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Use "option" instead of "repetition" in diagnostics for ? and ??
---
 xr-test.el | 17 
 xr.el  | 94 +-
 2 files changed, 69 insertions(+), 42 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 175df15..95927ca 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -362,16 +362,21 @@
'((0 . "Escaped non-special character `}'")
  (4 . "Escaped non-special character `a'")
  (8 . "Escaped non-special character `%'"
-(should (equal (xr-lint "a?+b+?\\(?:c?\\)*d\\{3\\}+e*?\\{2,5\\}")
-   '((2  . "Repetition of repetition")
+(should (equal (xr-lint "a?+b+?\\(?:c*\\)*d\\{3\\}+e*?\\{2,5\\}")
+   '((2  . "Repetition of option")
  (14 . "Repetition of repetition")
  (25 . "Repetition of repetition"
 (should (equal (xr-lint "\\(a*\\)*\\(b+\\)*\\(c*\\)?\\(d+\\)?")
'((6 .  "Repetition of repetition")
  (13 . "Repetition of repetition")
- (20 . "Repetition of repetition"
+ (20 . "Optional repetition"
+(should (equal (xr-lint "\\(a?\\)+\\(b?\\)?")
+   '((6 . "Repetition of option")
+ (13 . "Optional option"
 (should (equal (xr-lint "\\(e*\\)\\{3\\}")
'((6 . "Repetition of repetition"
+(should (equal (xr-lint "\\(a?\\)\\{4,7\\}")
+   '((6 . "Repetition of option"
 (should (equal (xr-lint "[]-Qa-fz-t]")
'((1 . "Reversed range `]-Q' matches nothing")
  (7 . "Reversed range `z-t' matches nothing"
@@ -406,7 +411,7 @@
 "Literal `-' not first or last in character alternative"
 (should (equal (xr-lint "\\'*\\

[elpa] externals/xr d0b09e1 08/10: Add filename-specific checks

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit d0b09e1b49bc47641580604c34369d4fb0875a38
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add filename-specific checks

These were moved from relint since they arguably belong here.
xr-lint now takes an optional PURPOSE argument.
---
 xr-test.el |  9 +
 xr.el  | 54 +-
 2 files changed, 46 insertions(+), 17 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index c0c428d..175df15 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -651,6 +651,15 @@
nil))
 ))
 
+(ert-deftest xr-lint-file ()
+  (let ((text-quoting-style 'grave))
+(should (equal (xr-lint "a.b\\.c.*d.?e.+f." 'file)
+   '((1 . "Possibly unescaped `.' in file-matching regexp")
+ (15 . "Possibly unescaped `.' in file-matching regexp"
+(should (equal (xr-lint "^abc$" 'file)
+   '((0 . "Use \\` instead of ^ in file-matching regexp")
+ (4 . "Use \\' instead of $ in file-matching regexp"))
+
 (ert-deftest xr-skip-set ()
   (should (equal (xr-skip-set "0-9a-fA-F+*")
  '(any "0-9a-fA-F" "+*")))
diff --git a/xr.el b/xr.el
index a10be63..f50c4f2 100644
--- a/xr.el
+++ b/xr.el
@@ -521,7 +521,7 @@ like (* (* X) ... (* X))."
  "First item in repetition subsumes last item (wrapped)"
"Last item in repetition subsumes first item (wrapped)"
 
-(defun xr--parse-seq (warnings)
+(defun xr--parse-seq (warnings purpose)
   (let ((sequence nil)) ; reversed
 (while (not (looking-at (rx (or "\\|" "\\)" eos
   (let ((item-start (point)))
@@ -530,8 +530,12 @@ like (* (* X) ... (* X))."
  ((looking-at (rx "^"))
   (forward-char 1)
   (if (null sequence)
-  (push 'bol sequence)
-(xr--report warnings (match-beginning 0)
+  (progn
+(when (eq purpose 'file)
+  (xr--report warnings item-start
+  "Use \\` instead of ^ in file-matching regexp"))
+(push 'bol sequence))
+(xr--report warnings item-start
 (format-message "Unescaped literal `^'"))
 (push "^" sequence)))
 
@@ -539,8 +543,13 @@ like (* (* X) ... (* X))."
  ((looking-at (rx "$"))
   (forward-char 1)
   (if (looking-at (rx (or "\\|" "\\)" eos)))
-  (push 'eol sequence)
-(xr--report warnings (match-beginning 0)
+  (progn
+(when (eq purpose 'file)
+  (xr--report warnings item-start
+  "Use \\' instead of $ in file-matching regexp"))
+
+(push 'eol sequence))
+(xr--report warnings item-start
 (format-message "Unescaped literal `$'"))
 (push "$" sequence)))
 
@@ -682,7 +691,7 @@ like (* (* X) ... (* X))."
 (when (and question (not colon))
   (error "Invalid \\(? syntax"))
 (goto-char (match-end 0))
-(let* ((group (xr--parse-alt warnings))
+(let* ((group (xr--parse-alt warnings purpose))
;; simplify - group has an implicit seq
(operand (if (and (listp group) (eq (car group) 'seq))
 (cdr group)
@@ -706,14 +715,23 @@ like (* (* X) ... (* X))."
   (push (list 'backref (string-to-number (match-string 1)))
 sequence))
 
+ ;; not-newline
+ ((looking-at (rx "."))
+  (goto-char (match-end 0))
+  ;; Assume that .* etc is intended.
+  (when (and (eq purpose 'file)
+ (not (looking-at (rx (any "?*+")
+(xr--report warnings (match-beginning 0)
+"Possibly unescaped `.' in file-matching regexp"))
+  (push 'nonl sequence))
+
  ;; various simple substitutions
- ((looking-at (rx (or "." "\\w" "\\W" "\\`" "\\'" "\\="
+ ((looking-at (rx (or "\\w" "\\W" "\\`" "\\'" "\\="
   "\\b" "\\B" "\\<" "\\>")))
   (goto-char (match-end 0))
   (let ((sym (cdr (assoc
(match-string 0)
-   '(("." . nonl)
- ("\\w" . wordchar) ("\\W" . not-wordchar)
+   '(("\\w" . wordchar) ("\\W" . not-wordchar)
  ("\\`" . bos) ("\\'" . eos)
  ("\\=" . point)
  ("\\b" . word-boundary) ("\\B" . 
not-word-boundary)
@@ -1356,13 +1374,13 @@ A-SETS and B-SETS are arguments to `any'."
 
(_ (equal a b))
 
-(defun xr--parse-alt (warnings)
+(defun xr--parse-alt (warnings purpose)
   (let ((alternatives nil)) ; reversed
-(push (xr--parse-seq warnings) alternatives)
+(push 

[elpa] externals/xr f3b61ef 05/10: Fix false negative in empty string repetition check

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit f3b61ef7450afd7726e509509f5b3042af23a051
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Fix false negative in empty string repetition check

We forgot to check for non-greedy inner repetitions.
---
 xr-test.el | 14 ++
 xr.el  |  4 ++--
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 88e68f7..2724e0d 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -404,16 +404,22 @@
  (xr-lint "[-A-Z][A-Z-][A-Z-a][^-A-Z][]-a][A-Z---.]")
  '((16 .
 "Literal `-' not first or last in character alternative"
-(should (equal
- (xr-lint "\\(?:a*b?\\)*\\(c\\|d\\|\\)+\\(^\\|e\\)*\\(?:\\)*")
- '((10 . "Repetition of expression matching an empty string")
-   (21 . "Repetition of expression matching an empty string"
 (should (equal (xr-lint "\\'*\\

[elpa] externals/xr 7160235 02/10: Refactor repetition subsumption check to avoid code duplication

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit 7160235fe06fdbd8814d9384f4239c9a6e8ad809
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Refactor repetition subsumption check to avoid code duplication
---
 xr-test.el |  2 +-
 xr.el  | 52 +---
 2 files changed, 10 insertions(+), 44 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 2001a39..a46cf60 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -602,7 +602,7 @@
  '((13 . "First item in repetition subsumes last item 
(wrapped)"
 (should (equal
  (xr-lint "\\(?3:a*xa*\\)\\{7\\}")
- '((14 . "First item in repetition subsumes last item 
(wrapped)"
+ '((14 . "Last item in repetition subsumes first item 
(wrapped)"
 ))
 
 (ert-deftest xr-skip-set ()
diff --git a/xr.el b/xr.el
index 985f4d8..3e09ac0 100644
--- a/xr.el
+++ b/xr.el
@@ -490,11 +490,11 @@ like (* (* X) ... (* X))."
   (when (cddr operands)
 (let* ((first (car operands))
(last (car (last operands)))
-   (subsumption (xr--adjacent-subsumption first last)))
+   (subsumption (xr--adjacent-subsumption last first)))
   (when subsumption
 (xr--report
  warnings pos
- (if (eq subsumption 'a-subsumes-b)
+ (if (eq subsumption 'b-subsumes-a)
  "First item in repetition subsumes last item (wrapped)"
"Last item in repetition subsumes first item (wrapped)"
 
@@ -743,48 +743,14 @@ like (* (* X) ... (* X))."
  (t (error "Backslash at end of regexp")))
 
 (when (and warnings (cdr sequence))
-  ;; Check for subsuming repetitions in sequence: (Rx X) (Ry Y)
-  ;; where Rx and Ry are repetition operators, and X and Y are 
operands.
-  ;; We conclude that (Rx X) subsumes (Ry Y), in the sense that the
-  ;; sequence is equivalent to just (Rx X), if:
-  ;;   X matches a superset of Y
-  ;;   and Rx can match infinitely many times
-  ;;   and Ry can match zero times
-  ;;   and Ry is non-greedy if Rx is non-greedy.
-  ;; Example: [ab]+a?
   (let* ((item (car sequence))
- (expr (and (consp item)
-(memq (car item)
-  '(zero-or-more one-or-more opt *? +? ??))
-(xr--make-seq (cdr item)
-(when expr
-  (let* ((prev-item (cadr sequence))
- (prev-expr
-  (and (consp prev-item)
-   (memq (car prev-item)
- '(zero-or-more one-or-more opt *? +? ??))
-   (xr--make-seq (cdr prev-item)
-(when prev-expr
-  (let ((op (car item))
-(prev-op (car prev-item)))
-;; Test the same condition twice, but mirrored.
-(cond
- ((and (memq op '(zero-or-more opt *? ??))
-   (memq prev-op '(zero-or-more one-or-more *? +?))
-   (not (and (memq prev-op '(*? +?))
- (memq op '(zero-or-more opt
-   (xr--superset-p prev-expr expr))
-  (xr--report
-   warnings item-start
-   "Repetition subsumed by preceding repetition"))
- ((and (memq prev-op '(zero-or-more opt *? ??))
-   (memq op '(zero-or-more one-or-more *? +?))
-   (not (and (memq op '(*? +?))
- (memq prev-op '(zero-or-more opt
-   (xr--superset-p expr prev-expr))
-  (xr--report
-   warnings item-start
-   "Repetition subsumes preceding repetition")))
+ (prev-item (cadr sequence))
+ (subsumption (xr--adjacent-subsumption prev-item item)))
+(when subsumption
+  (xr--report warnings item-start
+  (if (eq subsumption 'a-subsumes-b)
+  "Repetition subsumed by preceding repetition"
+"Repetition subsumes preceding repetition")))
 
 (let ((item-seq (xr--rev-join-seq sequence)))
   (cond ((null item-seq)



[elpa] externals/xr c98bb7b 03/10: Handle whitespace and word syntax subsumption in one place

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit c98bb7bcf319bca7c42038c51a92ed78f5e439d7
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Handle whitespace and word syntax subsumption in one place

Use the more elaborate code already in place for charsets.
---
 xr.el | 33 +
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/xr.el b/xr.el
index 3e09ac0..fa89862 100644
--- a/xr.el
+++ b/xr.el
@@ -1042,22 +1042,23 @@ A-SETS and B-SETS are arguments to `any'."
 
 (defun xr--syntax-superset-of-rx-p (syntax negated rx)
   "Whether SYNTAX, possibly NEGATED, is a superset of RX."
-  ;; Syntax tables vary, but we make a (quite conservative) guess.
-  (let* ((always-set
-   ;; Characters we think always will be in the syntax set.
-   '((whitespace " \t")
- (word "A-Za-z0-9")
- (open-parenthesis "([")
- (close-parenthesis "])")))
- (never-set
-   ;; Characters we think never will be in the syntax set.
-   '((whitespace "!-~")
- (punctuation "A-Za-z0-9")
- (open-parenthesis "\x00- A-Za-z0-9")
- (close-parenthesis "\x00- A-Za-z0-9")))
- (set (assq syntax (if negated never-set always-set
-(and set
- (xr--char-superset-of-rx-p (cdr set) nil rx
+  (cond
+   ((eq syntax 'whitespace) (xr--char-superset-of-rx-p '(space) negated rx))
+   ((eq syntax 'word)   (xr--char-superset-of-rx-p '(word) negated rx))
+   (t
+;; Syntax tables vary, but we make a fairly conservative guess.
+(let* ((always-set
+;; Characters we think always will be in the syntax set.
+'((open-parenthesis "([")
+  (close-parenthesis "])")))
+   (never-set
+;; Characters we think never will be in the syntax set.
+'((punctuation "A-Za-z0-9")   ; NOT the same as [:punct:]!
+  (open-parenthesis "\000-\037A-Za-z0-9" " \177")
+  (close-parenthesis "\000-\037A-Za-z0-9" " \177")))
+   (set (assq syntax (if negated never-set always-set
+  (and set
+   (xr--char-superset-of-rx-p (cdr set) nil rx))
 
 (defun xr--expand-strings (rx)
   "Expand strings to characters or seqs of characters.



[elpa] externals/xr c6e12b7 04/10: Handle \w and \W in subsumption checks

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit c6e12b71234c1009395d8b0c013db77d63834269
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Handle \w and \W in subsumption checks
---
 xr-test.el | 8 
 xr.el  | 6 +-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/xr-test.el b/xr-test.el
index a46cf60..88e68f7 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -509,6 +509,14 @@
 (should (equal (xr-lint "\\Ca\\|ü")
'((5 . "Branch matches subset of a previous branch"
 
+(should (equal (xr-lint "\\w\\|[^z-a]")
+   '((4 . "Branch matches superset of a previous branch"
+(should (equal (xr-lint "\\W\\|[^z-a]")
+   '((4 . "Branch matches superset of a previous branch"
+(should (equal (xr-lint "\\w\\|a")
+   '((4 . "Branch matches subset of a previous branch"
+(should (equal (xr-lint "\\W\\|\f")
+   '((4 . "Branch matches subset of a previous branch"
   ))
 
 (ert-deftest xr-lint-subsumed-repetition ()
diff --git a/xr.el b/xr.el
index fa89862..03b5f0a 100644
--- a/xr.el
+++ b/xr.el
@@ -1033,7 +1033,8 @@ A-SETS and B-SETS are arguments to `any'."
   (or (memq rx '(nonl anything
  ascii alnum alpha blank cntrl digit graph
  lower multibyte nonascii print punct space
- unibyte upper word xdigit))
+ unibyte upper word xdigit
+ wordchar not-wordchar))
   (characterp rx)
   (and (consp rx)
(or (memq (car rx) '(any category syntax))
@@ -1160,6 +1161,9 @@ A-SETS and B-SETS are arguments to `any'."
(`(not (syntax ,syn))
 (or (equal a b) (xr--syntax-superset-of-rx-p syn t b)))
 
+   ('wordchar (or (equal a b) (xr--syntax-superset-of-rx-p 'word nil b)))
+   ('not-wordchar (or (equal a b) (xr--syntax-superset-of-rx-p 'word t b)))
+
((or `(category ,_) `(not (category ,_)))
 (or (equal a b)
 (and (characterp b)



[elpa] externals/xr 21eab3c 06/10: Check for bol, eol and eos in conflict with other expressions

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit 21eab3c0f6593754b03f5d2a2a7c4f44c6744a75
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Check for bol, eol and eos in conflict with other expressions
---
 xr-test.el |  12 +++
 xr.el  | 118 +++--
 2 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index 2724e0d..b426d30 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -619,6 +619,18 @@
  '((14 . "Last item in repetition subsumes first item 
(wrapped)"
 ))
 
+(ert-deftest xr-lint-bad-anchor ()
+  (let ((text-quoting-style 'grave))
+(should (equal (xr-lint "a\\(?:^b$\\)c")
+   '((1 . "Non-newline followed by line-start anchor")
+ (10 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint ".\\(?:^$\\).")
+   '((1 . "Non-newline followed by line-start anchor")
+ (9 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "\\'b")
+   '((2 . "End-of-text anchor followed by non-empty 
pattern"
+))
+
 (ert-deftest xr-skip-set ()
   (should (equal (xr-skip-set "0-9a-fA-F+*")
  '(any "0-9a-fA-F" "+*")))
diff --git a/xr.el b/xr.el
index eccbf3f..6467624 100644
--- a/xr.el
+++ b/xr.el
@@ -439,6 +439,29 @@ UPPER may be nil, meaning infinity."
  (cl-every #'xr--matches-empty-p body))
 ("" t)))
 
+(defun xr--matches-nonempty-only-p (rx)
+  "Whether RX matches non-empty strings only."
+  (pcase rx
+((pred stringp) (> (length rx) 0))
+(`(,(or 'seq 'one-or-more '+? 'group) . ,body)
+ (cl-some #'xr--matches-nonempty-only-p body))
+(`(or . ,body)
+ (cl-every #'xr--matches-nonempty-only-p body))
+(`(group-n ,_ . ,body)
+ (cl-some #'xr--matches-nonempty-only-p body))
+(`(repeat ,from ,_ . ,body)
+ (and (> from 0)
+  (cl-some #'xr--matches-nonempty-only-p body)))
+(`(,(or '= '>=) ,n . ,body)
+ (and (> n 0)
+  (cl-some #'xr--matches-nonempty-only-p body)))
+(`(,(or 'any 'not 'intersection) . ,_) t)
+((or 'ascii 'alnum 'alpha 'blank 'cntrl 'digit 'graph
+ 'lower 'multibyte 'nonascii 'print 'punct 'space
+ 'unibyte 'upper 'word 'xdigit
+ 'nonl 'anything)
+ t)))
+
 (defun xr--adjacent-subsumption (a b)
   "Check if A subsumes B, or vice versa, or not, assuming they are adjacent.
 Return `a-subsumes-b', `b-subsumes-a' or nil."
@@ -742,7 +765,8 @@ like (* (* X) ... (* X))."
 
  (t (error "Backslash at end of regexp")))
 
-(when (and warnings (cdr sequence))
+(when (and warnings (cdr sequence)
+   (not (looking-at (rx (or (any "?*+") "\\{")
   (let* ((item (car sequence))
  (prev-item (cadr sequence))
  (subsumption (xr--adjacent-subsumption prev-item item)))
@@ -750,7 +774,27 @@ like (* (* X) ... (* X))."
   (xr--report warnings item-start
   (if (eq subsumption 'a-subsumes-b)
   "Repetition subsumed by preceding repetition"
-"Repetition subsumes preceding repetition")))
+"Repetition subsumes preceding repetition")))
+
+;; Check for anchors conflicting with previous/next character.
+(cond
+ ((and (xr--may-end-in-eol-p prev-item)
+   (not (xr--may-start-in-nl-p item)))
+  (xr--report warnings item-start
+  "End-of-line anchor followed by non-newline"))
+ ((and (xr--may-start-in-bol-p item)
+   (not (xr--may-end-in-nl-p prev-item)))
+  (xr--report warnings item-start
+  "Non-newline followed by line-start anchor"))
+ ((and (xr--may-end-in-eos-p prev-item)
+   (xr--matches-nonempty-only-p item))
+  (xr--report warnings item-start
+  "End-of-text anchor followed by non-empty pattern"))
+ ;; FIXME: We don't complain about non-empty followed by
+ ;; bos because it may be the start of unmatchable.
+ ;; We should really do these checks in a later pass,
+ ;; and maintain location information.
+ )
 
 (let ((item-seq (xr--rev-join-seq sequence)))
   (cond ((null item-seq)
@@ -760,6 +804,76 @@ like (* (* X) ... (* X))."
 (t 
  (cons 'seq item-seq))
 
+(defun xr--may-start-in-bol-p (item)
+  (pcase item
+('bol t)
+(`(,(or 'seq 'opt 'zero-or-more 'one-or-more ?? '*? '+? 'group) ,first . 
,_)
+ (xr--may-start-in-bol-p first))
+(`(group-n ,_ ,first . ,_)
+ (xr--may-start-in-bol-p first))
+(`(or . ,items) (cl-some #'xr--may-start-in-bol-p items
+
+(defun xr--may-end-in-eol-p (item)
+  (pcase item
+('eol t)
+(`(,(or 'seq 'opt 

[elpa] externals/xr updated (434b300 -> 35dbbeb)

2020-05-03 Thread Mattias Engdeg�rd
mattiase pushed a change to branch externals/xr.

  from  434b300   Increment version to 1.18
   new  e5b51bf   Add wrapped subsumption in repeated forms
   new  7160235   Refactor repetition subsumption check to avoid code 
duplication
   new  c98bb7b   Handle whitespace and word syntax subsumption in one place
   new  c6e12b7   Handle \w and \W in subsumption checks
   new  f3b61ef   Fix false negative in empty string repetition check
   new  21eab3c   Check for bol, eol and eos in conflict with other 
expressions
   new  c7e7557   Broaden anchor check to check more paths
   new  d0b09e1   Add filename-specific checks
   new  d752aab   Use "option" instead of "repetition" in diagnostics for ? 
and ??
   new  35dbbeb   Increment version to 1.19


Summary of changes:
 xr-test.el |  91 ++-
 xr.el  | 502 +++--
 2 files changed, 469 insertions(+), 124 deletions(-)



[elpa] externals/xr c7e7557 07/10: Broaden anchor check to check more paths

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit c7e7557db435cd6553c81592394de0358225f079
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Broaden anchor check to check more paths

Check both AB, A?B and AB? (but not A?B?) where A and B are an anchor
and conflicting expression, in some order.
---
 xr-test.el |  26 +++-
 xr.el  | 209 +
 2 files changed, 163 insertions(+), 72 deletions(-)

diff --git a/xr-test.el b/xr-test.el
index b426d30..c0c428d 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -621,14 +621,34 @@
 
 (ert-deftest xr-lint-bad-anchor ()
   (let ((text-quoting-style 'grave))
-(should (equal (xr-lint "a\\(?:^b$\\)c")
-   '((1 . "Non-newline followed by line-start anchor")
- (10 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "a\\(?:^\\)")
+   '((1 . "Non-newline followed by line-start anchor"
+(should (equal (xr-lint "a?\\(?:^\\)")
+   '((2 . "Non-newline followed by line-start anchor"
+(should (equal (xr-lint "a\\(?:^\\|b\\)")
+   '((1 . "Non-newline followed by line-start anchor"
+(should (equal (xr-lint "a?\\(?:^\\|b\\)")
+   nil))
+(should (equal (xr-lint "\\(?:$\\)a")
+   '((7 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "\\(?:$\\)\\(\n\\|a\\)")
+   '((7 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "\\(?:$\\|b\\)a")
+   '((10 . "End-of-line anchor followed by non-newline"
+(should (equal (xr-lint "\\(?:$\\|b\\)\\(\n\\|a\\)")
+   nil))
 (should (equal (xr-lint ".\\(?:^$\\).")
'((1 . "Non-newline followed by line-start anchor")
  (9 . "End-of-line anchor followed by non-newline"
 (should (equal (xr-lint "\\'b")
'((2 . "End-of-text anchor followed by non-empty 
pattern"
+(should (equal (xr-lint "\\'b?")
+   '((3 . "End-of-text anchor followed by non-empty 
pattern"
+(should (equal (xr-lint "\\(?:a\\|\\'\\)b")
+   '((11 .
+  "End-of-text anchor followed by non-empty pattern"
+(should (equal (xr-lint "\\(?:a\\|\\'\\)b?")
+   nil))
 ))
 
 (ert-deftest xr-skip-set ()
diff --git a/xr.el b/xr.el
index 6467624..a10be63 100644
--- a/xr.el
+++ b/xr.el
@@ -777,24 +777,41 @@ like (* (* X) ... (* X))."
 "Repetition subsumes preceding repetition")))
 
 ;; Check for anchors conflicting with previous/next character.
-(cond
- ((and (xr--may-end-in-eol-p prev-item)
-   (not (xr--may-start-in-nl-p item)))
-  (xr--report warnings item-start
-  "End-of-line anchor followed by non-newline"))
- ((and (xr--may-start-in-bol-p item)
-   (not (xr--may-end-in-nl-p prev-item)))
-  (xr--report warnings item-start
-  "Non-newline followed by line-start anchor"))
- ((and (xr--may-end-in-eos-p prev-item)
-   (xr--matches-nonempty-only-p item))
-  (xr--report warnings item-start
-  "End-of-text anchor followed by non-empty pattern"))
- ;; FIXME: We don't complain about non-empty followed by
- ;; bos because it may be the start of unmatchable.
- ;; We should really do these checks in a later pass,
- ;; and maintain location information.
- )
+;; To avoid false positives, we require that at least one
+;; of the items is present in all paths.
+(let ((prev-eol (xr--ends-with-sym 'eol prev-item)))
+  (when prev-eol
+(let ((this-nonl (xr--starts-with-nonl item)))
+  (when (and this-nonl
+ (or (eq prev-eol 'always)
+ (eq this-nonl 'always)))
+(xr--report
+ warnings item-start
+ "End-of-line anchor followed by non-newline")
+(let ((this-bol (xr--starts-with-sym 'bol item)))
+  (when this-bol
+(let ((prev-nonl (xr--ends-with-nonl prev-item)))
+  (when (and prev-nonl
+ (or (eq prev-nonl 'always)
+ (eq this-bol 'always)))
+(xr--report
+ warnings item-start
+ "Non-newline followed by line-start anchor")
+(let ((prev-eos (xr--ends-with-sym 'eos prev-item)))
+  (when prev-eos
+(let ((this-nonempty (xr--matches-nonempty item)))
+  (when (and this-nonempty
+   

[elpa] externals/xr e5b51bf 01/10: Add wrapped subsumption in repeated forms

2020-05-03 Thread Mattias Engdeg�rd
branch: externals/xr
commit e5b51bf5608720dddac10495950258a9cd07a178
Author: Mattias Engdegård 
Commit: Mattias Engdegård 

Add wrapped subsumption in repeated forms

This check finds regexps like "\\(?:a*c[ab]*\\)+", where
the first and last item in a repeated sequence are considered
adjacent.
---
 xr-test.el | 13 
 xr.el  | 71 +-
 2 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/xr-test.el b/xr-test.el
index 432b8af..2001a39 100644
--- a/xr-test.el
+++ b/xr-test.el
@@ -592,6 +592,19 @@
  (46 . "Repetition subsumed by preceding repetition"
 ))
 
+(ert-deftest xr-lint-wrapped-subsumption ()
+  (let ((text-quoting-style 'grave))
+(should (equal
+ (xr-lint "\\(?:a*x[ab]+\\)*")
+ '((14 . "Last item in repetition subsumes first item 
(wrapped)"
+(should (equal
+ (xr-lint "\\([ab]*xya?\\)+")
+ '((13 . "First item in repetition subsumes last item 
(wrapped)"
+(should (equal
+ (xr-lint "\\(?3:a*xa*\\)\\{7\\}")
+ '((14 . "First item in repetition subsumes last item 
(wrapped)"
+))
+
 (ert-deftest xr-skip-set ()
   (should (equal (xr-skip-set "0-9a-fA-F+*")
  '(any "0-9a-fA-F" "+*")))
diff --git a/xr.el b/xr.el
index 5e7a11f..985f4d8 100644
--- a/xr.el
+++ b/xr.el
@@ -439,6 +439,65 @@ UPPER may be nil, meaning infinity."
  (cl-every #'xr--matches-empty-p body))
 ("" t)))
 
+(defun xr--adjacent-subsumption (a b)
+  "Check if A subsumes B, or vice versa, or not, assuming they are adjacent.
+Return `a-subsumes-b', `b-subsumes-a' or nil."
+  ;; Check for subsuming repetitions in sequence: (Ra A) (Rb B)
+  ;; where Ra and Rb are repetition operators, and A and B are operands.
+  ;; We conclude that (Ra A) subsumes (Rb B), in the sense that the
+  ;; sequence is equivalent to just (Ra A), if:
+  ;;   A matches a superset of B
+  ;;   and Ra can match infinitely many times
+  ;;   and Rb can match zero times
+  ;;   and Rb is non-greedy if Ra is non-greedy.
+  ;; Example: [cd]+c?
+  (let ((a-expr (and (consp a)
+ (memq (car a)
+   '(zero-or-more one-or-more opt *? +? ??))
+ (xr--make-seq (cdr a)
+(when a-expr
+  (let ((b-expr (and (consp b)
+ (memq (car b)
+   '(zero-or-more one-or-more opt *? +? ??))
+ (xr--make-seq (cdr b)
+(when b-expr
+  (let ((a-op (car a))
+(b-op (car b)))
+;; Test the same condition twice, but mirrored.
+(cond
+ ((and (memq b-op '(zero-or-more opt *? ??))
+   (memq a-op '(zero-or-more one-or-more *? +?))
+   (not (and (memq a-op '(*? +?))
+ (memq b-op '(zero-or-more opt
+   (xr--superset-p a-expr b-expr))
+  'a-subsumes-b)
+ ((and (memq a-op '(zero-or-more opt *? ??))
+   (memq b-op '(zero-or-more one-or-more *? +?))
+   (not (and (memq b-op '(*? +?))
+ (memq a-op '(zero-or-more opt
+   (xr--superset-p b-expr a-expr))
+  'b-subsumes-a
+  
+(defun xr--check-wrap-around-repetition (operand pos warnings)
+  "Whether OPERAND has a wrap-around repetition subsumption case,
+like (* (* X) ... (* X))."
+  (when (and (consp operand)
+ (memq (car operand) '(seq group group-n)))
+(let* ((operands
+(if (eq (car operand) 'group-n)
+(cddr operand)
+  (cdr operand
+  (when (cddr operands)
+(let* ((first (car operands))
+   (last (car (last operands)))
+   (subsumption (xr--adjacent-subsumption first last)))
+  (when subsumption
+(xr--report
+ warnings pos
+ (if (eq subsumption 'a-subsumes-b)
+ "First item in repetition subsumes last item (wrapped)"
+   "Last item in repetition subsumes first item (wrapped)"
+
 (defun xr--parse-seq (warnings)
   (let ((sequence nil)) ; reversed
 (while (not (looking-at (rx (or "\\|" "\\)" eos
@@ -502,7 +561,11 @@ UPPER may be nil, meaning infinity."
  (not (equal operand "")))
 (xr--report
  warnings (match-beginning 0)
- "Repetition of expression matching an empty string"
+ "Repetition of expression matching an empty string")))
+  ;; (* (* X) ... (* X)) etc: wrap-around subsumption
+  (when (member operator '("*" "+" "*?" "+?"))
+(xr--check-wrap-around-repetition
+ operand (match-beginning 0) warnings)))