Merge pull request #631 from mcarton/regex
Fix false negative in TRIVIAL_REGEX
This commit is contained in:
commit
b5105f5667
98
src/regex.rs
98
src/regex.rs
@ -55,32 +55,40 @@ impl LateLintPass for RegexPass {
|
|||||||
], {
|
], {
|
||||||
if let ExprLit(ref lit) = args[0].node {
|
if let ExprLit(ref lit) = args[0].node {
|
||||||
if let LitStr(ref r, _) = lit.node {
|
if let LitStr(ref r, _) = lit.node {
|
||||||
if let Err(e) = regex_syntax::Expr::parse(r) {
|
match regex_syntax::Expr::parse(r) {
|
||||||
span_lint(cx,
|
Ok(r) => {
|
||||||
INVALID_REGEX,
|
if let Some(repl) = is_trivial_regex(&r) {
|
||||||
str_span(args[0].span, &r, e.position()),
|
span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span,
|
||||||
&format!("regex syntax error: {}",
|
&"trivial regex",
|
||||||
e.description()));
|
&format!("consider using {}", repl));
|
||||||
}
|
}
|
||||||
else if let Some(repl) = is_trivial_regex(r) {
|
}
|
||||||
span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span,
|
Err(e) => {
|
||||||
&"trivial regex",
|
span_lint(cx,
|
||||||
&format!("consider using {}", repl));
|
INVALID_REGEX,
|
||||||
|
str_span(args[0].span, &r, e.position()),
|
||||||
|
&format!("regex syntax error: {}",
|
||||||
|
e.description()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Some(r) = const_str(cx, &*args[0]) {
|
} else if let Some(r) = const_str(cx, &*args[0]) {
|
||||||
if let Err(e) = regex_syntax::Expr::parse(&r) {
|
match regex_syntax::Expr::parse(&r) {
|
||||||
span_lint(cx,
|
Ok(r) => {
|
||||||
INVALID_REGEX,
|
if let Some(repl) = is_trivial_regex(&r) {
|
||||||
args[0].span,
|
span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span,
|
||||||
&format!("regex syntax error on position {}: {}",
|
&"trivial regex",
|
||||||
e.position(),
|
&format!("consider using {}", repl));
|
||||||
e.description()));
|
}
|
||||||
}
|
}
|
||||||
else if let Some(repl) = is_trivial_regex(&r) {
|
Err(e) => {
|
||||||
span_help_and_lint(cx, TRIVIAL_REGEX, args[0].span,
|
span_lint(cx,
|
||||||
&"trivial regex",
|
INVALID_REGEX,
|
||||||
&format!("{}", repl));
|
args[0].span,
|
||||||
|
&format!("regex syntax error on position {}: {}",
|
||||||
|
e.position(),
|
||||||
|
e.description()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -103,25 +111,31 @@ fn const_str(cx: &LateContext, e: &Expr) -> Option<InternedString> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_trivial_regex(s: &str) -> Option<&'static str> {
|
fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> {
|
||||||
// some unlikely but valid corner cases
|
use regex_syntax::Expr;
|
||||||
match s {
|
|
||||||
"" | "^" | "$" => return Some("the regex is unlikely to be useful as it is"),
|
|
||||||
"^$" => return Some("consider using `str::is_empty`"),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
let (start, end, repl) = match (s.starts_with('^'), s.ends_with('$')) {
|
match *s {
|
||||||
(true, true) => (1, s.len()-1, "consider using `==` on `str`s"),
|
Expr::Empty | Expr::StartText | Expr::EndText => Some("the regex is unlikely to be useful as it is"),
|
||||||
(false, true) => (0, s.len()-1, "consider using `str::ends_with`"),
|
Expr::Literal {..} => Some("consider using `str::contains`"),
|
||||||
(true, false) => (1, s.len(), "consider using `str::starts_with`"),
|
Expr::Concat(ref exprs) => {
|
||||||
(false, false) => (0, s.len(), "consider using `str::contains`"),
|
match exprs.len() {
|
||||||
};
|
2 => match (&exprs[0], &exprs[1]) {
|
||||||
|
(&Expr::StartText, &Expr::EndText) => Some("consider using `str::is_empty`"),
|
||||||
if !s.chars().take(end).skip(start).any(regex_syntax::is_punct) {
|
(&Expr::StartText, &Expr::Literal {..}) => Some("consider using `str::starts_with`"),
|
||||||
Some(repl)
|
(&Expr::Literal {..}, &Expr::EndText) => Some("consider using `str::ends_with`"),
|
||||||
}
|
_ => None,
|
||||||
else {
|
},
|
||||||
None
|
3 => {
|
||||||
|
if let (&Expr::StartText, &Expr::Literal {..}, &Expr::EndText) = (&exprs[0], &exprs[1], &exprs[2]) {
|
||||||
|
Some("consider using `==` on `str`s")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,16 +45,25 @@ fn trivial_regex() {
|
|||||||
//~^ERROR: trivial regex
|
//~^ERROR: trivial regex
|
||||||
//~|HELP consider using `str::contains`
|
//~|HELP consider using `str::contains`
|
||||||
|
|
||||||
|
let trivial_backslash = Regex::new("a\\.b");
|
||||||
|
//~^ERROR: trivial regex
|
||||||
|
//~|HELP consider using `str::contains`
|
||||||
|
|
||||||
// unlikely corner cases
|
// unlikely corner cases
|
||||||
let trivial_empty = Regex::new("");
|
let trivial_empty = Regex::new("");
|
||||||
//~^ERROR: trivial regex
|
//~^ERROR: trivial regex
|
||||||
//~|HELP the regex is unlikely to be useful
|
//~|HELP the regex is unlikely to be useful
|
||||||
|
|
||||||
|
let trivial_empty = Regex::new("^");
|
||||||
|
//~^ERROR: trivial regex
|
||||||
|
//~|HELP the regex is unlikely to be useful
|
||||||
|
|
||||||
let trivial_empty = Regex::new("^$");
|
let trivial_empty = Regex::new("^$");
|
||||||
//~^ERROR: trivial regex
|
//~^ERROR: trivial regex
|
||||||
//~|HELP consider using `str::is_empty`
|
//~|HELP consider using `str::is_empty`
|
||||||
|
|
||||||
// non-trivial regexes
|
// non-trivial regexes
|
||||||
|
let non_trivial_dot = Regex::new("a.b");
|
||||||
let non_trivial_eq = Regex::new("^foo|bar$");
|
let non_trivial_eq = Regex::new("^foo|bar$");
|
||||||
let non_trivial_starts_with = Regex::new("^foo|bar");
|
let non_trivial_starts_with = Regex::new("^foo|bar");
|
||||||
let non_trivial_ends_with = Regex::new("^foo|bar");
|
let non_trivial_ends_with = Regex::new("^foo|bar");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user