about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/regex.rs66
-rw-r--r--clippy_utils/src/paths.rs12
3 files changed, 53 insertions, 27 deletions
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index c43e0b753dc..00d46025caa 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -722,7 +722,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
     store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
     store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
-    store.register_late_pass(|_| Box::new(regex::Regex));
+    store.register_late_pass(|_| Box::<regex::Regex>::default());
     let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
     store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
     store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs
index 674f8bf4c0f..b795e4b15ba 100644
--- a/clippy_lints/src/regex.rs
+++ b/clippy_lints/src/regex.rs
@@ -3,12 +3,12 @@ use std::fmt::Display;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::source::snippet_opt;
-use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
+use clippy_utils::{def_path_def_ids, path_def_id, paths};
 use rustc_ast::ast::{LitKind, StrStyle};
+use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{BytePos, Span};
 
 declare_clippy_lint! {
@@ -55,26 +55,52 @@ declare_clippy_lint! {
     "trivial regular expressions"
 }
 
-declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
+#[derive(Copy, Clone)]
+enum RegexKind {
+    Unicode,
+    UnicodeSet,
+    Bytes,
+    BytesSet,
+}
+
+#[derive(Default)]
+pub struct Regex {
+    definitions: DefIdMap<RegexKind>,
+}
+
+impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
 
 impl<'tcx> LateLintPass<'tcx> for Regex {
+    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+        // We don't use `match_def_path` here because that relies on matching the exact path, which changed
+        // between regex 1.8 and 1.9
+        //
+        // `def_path_def_ids` will resolve through re-exports but is relatively heavy, so we only perform
+        // the operation once and store the results
+        let mut resolve = |path, kind| {
+            for id in def_path_def_ids(cx, path) {
+                self.definitions.insert(id, kind);
+            }
+        };
+
+        resolve(&paths::REGEX_NEW, RegexKind::Unicode);
+        resolve(&paths::REGEX_BUILDER_NEW, RegexKind::Unicode);
+        resolve(&paths::REGEX_SET_NEW, RegexKind::UnicodeSet);
+        resolve(&paths::REGEX_BYTES_NEW, RegexKind::Bytes);
+        resolve(&paths::REGEX_BYTES_BUILDER_NEW, RegexKind::Bytes);
+        resolve(&paths::REGEX_BYTES_SET_NEW, RegexKind::BytesSet);
+    }
+
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::Call(fun, [arg]) = expr.kind;
-            if let ExprKind::Path(ref qpath) = fun.kind;
-            if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
-            then {
-                if match_def_path(cx, def_id, &paths::REGEX_NEW) ||
-                   match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) {
-                    check_regex(cx, arg, true);
-                } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) ||
-                   match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) {
-                    check_regex(cx, arg, false);
-                } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) {
-                    check_set(cx, arg, true);
-                } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) {
-                    check_set(cx, arg, false);
-                }
+        if let ExprKind::Call(fun, [arg]) = expr.kind
+            && let Some(def_id) = path_def_id(cx, fun)
+            && let Some(regex_kind) = self.definitions.get(&def_id)
+        {
+            match regex_kind {
+                RegexKind::Unicode => check_regex(cx, arg, true),
+                RegexKind::UnicodeSet => check_set(cx, arg, true),
+                RegexKind::Bytes => check_regex(cx, arg, false),
+                RegexKind::BytesSet => check_set(cx, arg, false),
             }
         }
     }
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index 0e6f01287b5..f3677e6f614 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -94,12 +94,12 @@ pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
 pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
 pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
-pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
-pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
-pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
-pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
-pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
-pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
+pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"];
+pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"];
+pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"];
+pub const REGEX_BYTES_SET_NEW: [&str; 4] = ["regex", "bytes", "RegexSet", "new"];
+pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"];
+pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"];
 pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
 pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];