Skip to content

Commit c669046

Browse files
committed
Lint binary regexes
1 parent 77ed899 commit c669046

File tree

3 files changed

+30
-6
lines changed

3 files changed

+30
-6
lines changed

src/regex.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::error::Error;
99
use syntax::ast::{LitKind, NodeId};
1010
use syntax::codemap::{Span, BytePos};
1111
use syntax::parse::token::InternedString;
12-
use utils::{is_expn_of, match_path, match_type, paths, span_lint, span_help_and_lint};
12+
use utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_help_and_lint};
1313

1414
/// **What it does:** This lint checks `Regex::new(_)` invocations for correct regex syntax.
1515
///
@@ -96,12 +96,23 @@ impl LateLintPass for RegexPass {
9696
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
9797
if_let_chain!{[
9898
let ExprCall(ref fun, ref args) = expr.node,
99-
let ExprPath(_, ref path) = fun.node,
100-
match_path(path, &paths::REGEX_NEW) && args.len() == 1
99+
args.len() == 1
101100
], {
101+
let def_id = cx.tcx.def_map.borrow()[&fun.id].def_id();
102+
103+
let utf8 = if match_def_path(cx, def_id, &paths::REGEX_NEW) {
104+
true
105+
} else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) {
106+
false
107+
} else {
108+
return;
109+
};
110+
111+
let builder = regex_syntax::ExprBuilder::new().unicode(utf8);
112+
102113
if let ExprLit(ref lit) = args[0].node {
103114
if let LitKind::Str(ref r, _) = lit.node {
104-
match regex_syntax::Expr::parse(r) {
115+
match builder.parse(r) {
105116
Ok(r) => {
106117
if let Some(repl) = is_trivial_regex(&r) {
107118
span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span,
@@ -119,7 +130,7 @@ impl LateLintPass for RegexPass {
119130
}
120131
}
121132
} else if let Some(r) = const_str(cx, &*args[0]) {
122-
match regex_syntax::Expr::parse(&r) {
133+
match builder.parse(&r) {
123134
Ok(r) => {
124135
if let Some(repl) = is_trivial_regex(&r) {
125136
span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span,

src/utils/paths.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ 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_NEW: [&'static str; 3] = ["regex", "Regex", "new"];
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_NEW: [&'static str; 4] = ["regex", "re_unicode", "Regex", "new"];
5052
pub const RESULT: [&'static str; 3] = ["core", "result", "Result"];
5153
pub const STRING: [&'static str; 3] = ["collections", "string", "String"];
5254
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];

tests/compile-fail/regex.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
extern crate regex;
88

99
use regex::Regex;
10+
use regex::bytes::Regex as BRegex;
1011

1112
const OPENING_PAREN : &'static str = "(";
1213
const NOT_A_REAL_REGEX : &'static str = "foobar";
@@ -22,6 +23,11 @@ fn syntax_error() {
2223
let some_regex = Regex::new(OPENING_PAREN);
2324
//~^ERROR: regex syntax error on position 0: unclosed
2425

26+
let binary_pipe_in_wrong_position = BRegex::new("|");
27+
//~^ERROR: regex syntax error: empty alternate
28+
let some_binary_regex = BRegex::new(OPENING_PAREN);
29+
//~^ERROR: regex syntax error on position 0: unclosed
30+
2531
let closing_paren = ")";
2632
let not_linted = Regex::new(closing_paren);
2733
}
@@ -64,12 +70,17 @@ fn trivial_regex() {
6470
//~^ERROR: trivial regex
6571
//~|HELP consider using `str::is_empty`
6672

73+
let binary_trivial_empty = BRegex::new("^$");
74+
//~^ERROR: trivial regex
75+
//~|HELP consider using `str::is_empty`
76+
6777
// non-trivial regexes
6878
let non_trivial_dot = Regex::new("a.b");
6979
let non_trivial_eq = Regex::new("^foo|bar$");
7080
let non_trivial_starts_with = Regex::new("^foo|bar");
7181
let non_trivial_ends_with = Regex::new("^foo|bar");
7282
let non_trivial_ends_with = Regex::new("foo|bar");
83+
let non_trivial_binary = BRegex::new("foo|bar");
7384
}
7485

7586
fn main() {

0 commit comments

Comments
 (0)