Skip to content

Commit

Permalink
Auto merge of #11111 - Alexendoo:regex-def-paths, r=giraffate
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Jul 6, 2023
2 parents 1e656d8 + f945351 commit dd8e44c
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 27 deletions.
2 changes: 1 addition & 1 deletion clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
66 changes: 46 additions & 20 deletions clippy_lints/src/regex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! {
Expand Down Expand Up @@ -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),
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions clippy_utils/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"];
Expand Down

0 comments on commit dd8e44c

Please sign in to comment.