Skip to content

Commit dd8e44c

Browse files
committed
Auto merge of rust-lang#11111 - Alexendoo:regex-def-paths, r=giraffate
Fix regex lints for regex 1.9.0 regex 1.9.0 was [just released](https://blog.burntsushi.net/regex-internals/), which changes where the types are defined. Instead of updating the definitions to the ones in 1.9.0 this PR uses [`def_path_def_ids`](https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/fn.def_path_def_ids.html) on the canonical paths so that we don't have to worry about third party crate internals This means that it still works with older regex versions too, and will for any future layout changes. I tested it with 1.8.4 and 1.9.0 changelog: [`INVALID_REGEX`], [`TRIVIAL_REGEX`]: now works with regex 1.9.0
2 parents 1e656d8 + f945351 commit dd8e44c

File tree

3 files changed

+53
-27
lines changed

3 files changed

+53
-27
lines changed

clippy_lints/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
722722
store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
723723
store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
724724
store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
725-
store.register_late_pass(|_| Box::new(regex::Regex));
725+
store.register_late_pass(|_| Box::<regex::Regex>::default());
726726
let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
727727
store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
728728
store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));

clippy_lints/src/regex.rs

+46-20
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ use std::fmt::Display;
33
use clippy_utils::consts::{constant, Constant};
44
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
55
use clippy_utils::source::snippet_opt;
6-
use clippy_utils::{match_def_path, paths};
7-
use if_chain::if_chain;
6+
use clippy_utils::{def_path_def_ids, path_def_id, paths};
87
use rustc_ast::ast::{LitKind, StrStyle};
8+
use rustc_hir::def_id::DefIdMap;
99
use rustc_hir::{BorrowKind, Expr, ExprKind};
1010
use rustc_lint::{LateContext, LateLintPass};
11-
use rustc_session::{declare_lint_pass, declare_tool_lint};
11+
use rustc_session::{declare_tool_lint, impl_lint_pass};
1212
use rustc_span::source_map::{BytePos, Span};
1313

1414
declare_clippy_lint! {
@@ -55,26 +55,52 @@ declare_clippy_lint! {
5555
"trivial regular expressions"
5656
}
5757

58-
declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
58+
#[derive(Copy, Clone)]
59+
enum RegexKind {
60+
Unicode,
61+
UnicodeSet,
62+
Bytes,
63+
BytesSet,
64+
}
65+
66+
#[derive(Default)]
67+
pub struct Regex {
68+
definitions: DefIdMap<RegexKind>,
69+
}
70+
71+
impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
5972

6073
impl<'tcx> LateLintPass<'tcx> for Regex {
74+
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
75+
// We don't use `match_def_path` here because that relies on matching the exact path, which changed
76+
// between regex 1.8 and 1.9
77+
//
78+
// `def_path_def_ids` will resolve through re-exports but is relatively heavy, so we only perform
79+
// the operation once and store the results
80+
let mut resolve = |path, kind| {
81+
for id in def_path_def_ids(cx, path) {
82+
self.definitions.insert(id, kind);
83+
}
84+
};
85+
86+
resolve(&paths::REGEX_NEW, RegexKind::Unicode);
87+
resolve(&paths::REGEX_BUILDER_NEW, RegexKind::Unicode);
88+
resolve(&paths::REGEX_SET_NEW, RegexKind::UnicodeSet);
89+
resolve(&paths::REGEX_BYTES_NEW, RegexKind::Bytes);
90+
resolve(&paths::REGEX_BYTES_BUILDER_NEW, RegexKind::Bytes);
91+
resolve(&paths::REGEX_BYTES_SET_NEW, RegexKind::BytesSet);
92+
}
93+
6194
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
62-
if_chain! {
63-
if let ExprKind::Call(fun, [arg]) = expr.kind;
64-
if let ExprKind::Path(ref qpath) = fun.kind;
65-
if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
66-
then {
67-
if match_def_path(cx, def_id, &paths::REGEX_NEW) ||
68-
match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) {
69-
check_regex(cx, arg, true);
70-
} else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) ||
71-
match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) {
72-
check_regex(cx, arg, false);
73-
} else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) {
74-
check_set(cx, arg, true);
75-
} else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) {
76-
check_set(cx, arg, false);
77-
}
95+
if let ExprKind::Call(fun, [arg]) = expr.kind
96+
&& let Some(def_id) = path_def_id(cx, fun)
97+
&& let Some(regex_kind) = self.definitions.get(&def_id)
98+
{
99+
match regex_kind {
100+
RegexKind::Unicode => check_regex(cx, arg, true),
101+
RegexKind::UnicodeSet => check_set(cx, arg, true),
102+
RegexKind::Bytes => check_regex(cx, arg, false),
103+
RegexKind::BytesSet => check_set(cx, arg, false),
78104
}
79105
}
80106
}

clippy_utils/src/paths.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@ pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
9494
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
9595
pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
9696
pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
97-
pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
98-
pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
99-
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
100-
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
101-
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
102-
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
97+
pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"];
98+
pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"];
99+
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"];
100+
pub const REGEX_BYTES_SET_NEW: [&str; 4] = ["regex", "bytes", "RegexSet", "new"];
101+
pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"];
102+
pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"];
103103
pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
104104
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
105105
pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];

0 commit comments

Comments
 (0)