@@ -3,12 +3,12 @@ use std::fmt::Display;
33use clippy_utils:: consts:: { constant, Constant } ;
44use clippy_utils:: diagnostics:: { span_lint, span_lint_and_help} ;
55use 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} ;
87use rustc_ast:: ast:: { LitKind , StrStyle } ;
8+ use rustc_hir:: def_id:: DefIdMap ;
99use rustc_hir:: { BorrowKind , Expr , ExprKind } ;
1010use rustc_lint:: { LateContext , LateLintPass } ;
11- use rustc_session:: { declare_lint_pass , declare_tool_lint } ;
11+ use rustc_session:: { declare_tool_lint , impl_lint_pass } ;
1212use rustc_span:: source_map:: { BytePos , Span } ;
1313
1414declare_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
6073impl < ' 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 }
0 commit comments