diff --git a/src/lib.rs b/src/lib.rs index 5f4f6e5291d..106d63aa0da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -158,7 +158,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box vec::UselessVec); reg.register_late_lint_pass(box drop_ref::DropRefPass); reg.register_late_lint_pass(box types::AbsurdExtremeComparisons); - reg.register_late_lint_pass(box regex::RegexPass); + reg.register_late_lint_pass(box regex::RegexPass::default()); reg.register_late_lint_pass(box copies::CopyAndPaste); reg.register_lint_group("clippy_pedantic", vec![ diff --git a/src/regex.rs b/src/regex.rs index 5103391e9dd..25c7260abec 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -1,11 +1,10 @@ use regex_syntax; use std::error::Error; use std::collections::HashSet; -use syntax::ast::LitKind; +use syntax::ast::{LitKind, NodeId}; use syntax::codemap::{Span, BytePos}; use syntax::parse::token::InternedString; use rustc_front::hir::*; -use rustc_front::intravisit::{Visitor, walk_block}; use rustc::middle::const_eval::{eval_const_expr_partial, ConstVal}; use rustc::middle::const_eval::EvalHint::ExprTypeChecked; use rustc::lint::*; @@ -52,8 +51,11 @@ declare_lint! { "finds use of `regex!(_)`, suggests `Regex::new(_)` instead" } -#[derive(Copy,Clone)] -pub struct RegexPass; +#[derive(Clone, Default)] +pub struct RegexPass { + spans: HashSet, + last: Option +} impl LintPass for RegexPass { fn get_lints(&self) -> LintArray { @@ -62,11 +64,34 @@ impl LintPass for RegexPass { } impl LateLintPass for RegexPass { - fn check_crate(&mut self, cx: &LateContext, krate: &Crate) { - let mut visitor = RegexVisitor { cx: cx, spans: HashSet::new() }; - krate.visit_all_items(&mut visitor); + fn check_crate(&mut self, _: &LateContext, _: &Crate) { + self.spans.clear(); } + fn check_block(&mut self, cx: &LateContext, block: &Block) { + if_let_chain!{[ + self.last.is_none(), + let Some(ref expr) = block.expr, + match_type(cx, cx.tcx.expr_ty(expr), &["regex", "re", "Regex"]), + let Some(span) = is_expn_of(cx, expr.span, "regex") + ], { + if !self.spans.contains(&span) { + span_lint(cx, + REGEX_MACRO, + span, + "`regex!(_)` found. \ + Please use `Regex::new(_)`, which is faster for now."); + self.spans.insert(span); + } + self.last = Some(block.id); + }} + } + + fn check_block_post(&mut self, _: &LateContext, block: &Block) { + if self.last.map_or(false, |id| block.id == id) { + self.last = None; + } + } fn check_expr(&mut self, cx: &LateContext, expr: &Expr) { if_let_chain!{[ @@ -160,30 +185,3 @@ fn is_trivial_regex(s: ®ex_syntax::Expr) -> Option<&'static str> { _ => None, } } - -struct RegexVisitor<'v, 't: 'v> { - cx: &'v LateContext<'v, 't>, - spans: HashSet, -} - -impl<'v, 't: 'v> Visitor<'v> for RegexVisitor<'v, 't> { - fn visit_block(&mut self, block: &'v Block) { - if_let_chain!{[ - let Some(ref expr) = block.expr, - match_type(self.cx, self.cx.tcx.expr_ty(expr), &["regex", "re", "Regex"]), - let Some(span) = is_expn_of(self.cx, expr.span, "regex") - ], { - if self.spans.contains(&span) { - return; - } - span_lint(self.cx, - REGEX_MACRO, - span, - "`regex!(_)` found. \ - Please use `Regex::new(_)`, which is faster for now."); - self.spans.insert(span); - return; - }} - walk_block(self, block); - } -}