Skip to content

Commit 1941251

Browse files
committed
Support RegexSet::new
1 parent dcd80e5 commit 1941251

File tree

4 files changed

+100
-61
lines changed

4 files changed

+100
-61
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# Change Log
22
All notable changes to this project will be documented in this file.
33

4+
## 0.0.70 — TBD
5+
* [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new`,
6+
`Regex::with_size_limit` and byte regexes
7+
48
## 0.0.69 — 2016-05-20
59
* Rustup to *rustc 1.10.0-nightly (476fe6eef 2016-05-21)*
6-
* `used_underscore_binding` has been made `Allow` temporarily
10+
* [`used_underscore_binding`] has been made `Allow` temporarily
711

812
## 0.0.68 — 2016-05-17
913
* Rustup to *rustc 1.10.0-nightly (cd6a40017 2016-05-16)*

src/regex.rs

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -99,60 +99,19 @@ impl LateLintPass for RegexPass {
9999
args.len() >= 1,
100100
let Some(def) = cx.tcx.def_map.borrow().get(&fun.id)
101101
], {
102-
let (utf8_path, bytes_path, re_idx) = match args.len() {
103-
1 => (paths::REGEX_NEW, paths::REGEX_BYTES_NEW, 0),
104-
2 => (paths::REGEX_WSL, paths::REGEX_BYTES_WSL, 1),
105-
_ => return,
106-
};
107-
108102
let def_id = def.def_id();
109-
let utf8 = if match_def_path(cx, def_id, utf8_path) {
110-
true
111-
} else if match_def_path(cx, def_id, bytes_path) {
112-
false
113-
} else {
114-
return;
115-
};
116-
117-
let builder = regex_syntax::ExprBuilder::new().unicode(utf8);
118-
119-
if let ExprLit(ref lit) = args[re_idx].node {
120-
if let LitKind::Str(ref r, _) = lit.node {
121-
match builder.parse(r) {
122-
Ok(r) => {
123-
if let Some(repl) = is_trivial_regex(&r) {
124-
span_help_and_lint(cx, TRIVIAL_REGEX, args[re_idx].span,
125-
"trivial regex",
126-
&format!("consider using {}", repl));
127-
}
128-
}
129-
Err(e) => {
130-
span_lint(cx,
131-
INVALID_REGEX,
132-
str_span(args[re_idx].span, &r, e.position()),
133-
&format!("regex syntax error: {}",
134-
e.description()));
135-
}
136-
}
137-
}
138-
} else if let Some(r) = const_str(cx, &*args[re_idx]) {
139-
match builder.parse(&r) {
140-
Ok(r) => {
141-
if let Some(repl) = is_trivial_regex(&r) {
142-
span_help_and_lint(cx, TRIVIAL_REGEX, args[re_idx].span,
143-
"trivial regex",
144-
&format!("consider using {}", repl));
145-
}
146-
}
147-
Err(e) => {
148-
span_lint(cx,
149-
INVALID_REGEX,
150-
args[re_idx].span,
151-
&format!("regex syntax error on position {}: {}",
152-
e.position(),
153-
e.description()));
154-
}
155-
}
103+
if args.len() == 1 && match_def_path(cx, def_id, &paths::REGEX_NEW) {
104+
check_regex(cx, &args[0], true);
105+
} else if args.len() == 1 && match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) {
106+
check_regex(cx, &args[0], false);
107+
} else if args.len() == 2 && match_def_path(cx, def_id, &paths::REGEX_WSL) {
108+
check_regex(cx, &args[1], true);
109+
} else if args.len() == 2 && match_def_path(cx, def_id, &paths::REGEX_BYTES_WSL) {
110+
check_regex(cx, &args[1], false);
111+
} else if args.len() == 1 && match_def_path(cx, def_id, &paths::REGEX_SET_NEW) {
112+
check_set(cx, &args[0], true);
113+
} else if args.len() == 1 && match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) {
114+
check_set(cx, &args[0], false);
156115
}
157116
}}
158117
}
@@ -210,3 +169,57 @@ fn is_trivial_regex(s: &regex_syntax::Expr) -> Option<&'static str> {
210169
_ => None,
211170
}
212171
}
172+
173+
fn check_set(cx: &LateContext, expr: &Expr, utf8: bool) {
174+
if_let_chain! {[
175+
let ExprAddrOf(_, ref expr) = expr.node,
176+
let ExprVec(ref exprs) = expr.node,
177+
], {
178+
for expr in exprs {
179+
check_regex(cx, expr, utf8);
180+
}
181+
}}
182+
}
183+
184+
fn check_regex(cx: &LateContext, expr: &Expr, utf8: bool) {
185+
let builder = regex_syntax::ExprBuilder::new().unicode(utf8);
186+
187+
if let ExprLit(ref lit) = expr.node {
188+
if let LitKind::Str(ref r, _) = lit.node {
189+
match builder.parse(r) {
190+
Ok(r) => {
191+
if let Some(repl) = is_trivial_regex(&r) {
192+
span_help_and_lint(cx, TRIVIAL_REGEX, expr.span,
193+
"trivial regex",
194+
&format!("consider using {}", repl));
195+
}
196+
}
197+
Err(e) => {
198+
span_lint(cx,
199+
INVALID_REGEX,
200+
str_span(expr.span, r, e.position()),
201+
&format!("regex syntax error: {}",
202+
e.description()));
203+
}
204+
}
205+
}
206+
} else if let Some(r) = const_str(cx, expr) {
207+
match builder.parse(&r) {
208+
Ok(r) => {
209+
if let Some(repl) = is_trivial_regex(&r) {
210+
span_help_and_lint(cx, TRIVIAL_REGEX, expr.span,
211+
"trivial regex",
212+
&format!("consider using {}", repl));
213+
}
214+
}
215+
Err(e) => {
216+
span_lint(cx,
217+
INVALID_REGEX,
218+
expr.span,
219+
&format!("regex syntax error on position {}: {}",
220+
e.position(),
221+
e.description()));
222+
}
223+
}
224+
}
225+
}

src/utils/paths.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ pub const RANGE_TO_INCLUSIVE: [&'static str; 3] = ["core", "ops", "RangeToInclus
4646
pub const RANGE_TO_INCLUSIVE_STD: [&'static str; 3] = ["std", "ops", "RangeToInclusive"];
4747
pub const RANGE_TO_STD: [&'static str; 3] = ["std", "ops", "RangeTo"];
4848
pub const REGEX: [&'static str; 3] = ["regex", "re_unicode", "Regex"];
49-
pub const REGEX_BYTES: &'static [&'static str] = &["regex", "re_bytes", "Regex"];
50-
pub const REGEX_BYTES_NEW: &'static [&'static str] = &["regex", "re_bytes", "Regex", "new"];
51-
pub const REGEX_BYTES_WSL: &'static [&'static str] = &["regex", "re_bytes", "Regex", "with_size_limit"];
52-
pub const REGEX_NEW: &'static [&'static str] = &["regex", "re_unicode", "Regex", "new"];
53-
pub const REGEX_WSL: &'static [&'static str] = &["regex", "re_unicode", "Regex", "with_size_limit"];
49+
pub const REGEX_BYTES: [&'static str; 3] = ["regex", "re_bytes", "Regex"];
50+
pub const REGEX_BYTES_NEW: [&'static str; 4] = ["regex", "re_bytes", "Regex", "new"];
51+
pub const REGEX_BYTES_SET_NEW: [&'static str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
52+
pub const REGEX_BYTES_WSL: [&'static str; 4] = ["regex", "re_bytes", "Regex", "with_size_limit"];
53+
pub const REGEX_NEW: [&'static str; 4] = ["regex", "re_unicode", "Regex", "new"];
54+
pub const REGEX_SET_NEW: [&'static str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
55+
pub const REGEX_WSL: [&'static str; 4] = ["regex", "re_unicode", "Regex", "with_size_limit"];
5456
pub const RESULT: [&'static str; 3] = ["core", "result", "Result"];
5557
pub const STRING: [&'static str; 3] = ["collections", "string", "String"];
5658
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];

tests/compile-fail/regex.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
extern crate regex;
88

9-
use regex::Regex;
10-
use regex::bytes::Regex as BRegex;
9+
use regex::{Regex, RegexSet};
10+
use regex::bytes::{Regex as BRegex, RegexSet as BRegexSet};
1111

1212
const OPENING_PAREN : &'static str = "(";
1313
const NOT_A_REAL_REGEX : &'static str = "foobar";
@@ -40,6 +40,26 @@ fn syntax_error() {
4040
let closing_paren = ")";
4141
let not_linted = Regex::new(closing_paren);
4242
let not_linted2 = Regex::with_size_limit(42, closing_paren);
43+
44+
let set = RegexSet::new(&[
45+
r"[a-z]+@[a-z]+\.(com|org|net)",
46+
r"[a-z]+\.(com|org|net)",
47+
]);
48+
let bset = BRegexSet::new(&[
49+
r"[a-z]+@[a-z]+\.(com|org|net)",
50+
r"[a-z]+\.(com|org|net)",
51+
]);
52+
53+
let set_error = RegexSet::new(&[
54+
OPENING_PAREN,
55+
//~^ERROR: regex syntax error on position 0: unclosed
56+
r"[a-z]+\.(com|org|net)",
57+
]);
58+
let bset_error = BRegexSet::new(&[
59+
OPENING_PAREN,
60+
//~^ERROR: regex syntax error on position 0: unclosed
61+
r"[a-z]+\.(com|org|net)",
62+
]);
4363
}
4464

4565
fn trivial_regex() {

0 commit comments

Comments
 (0)