1
- use clippy_utils:: diagnostics:: span_lint ;
1
+ use clippy_utils:: diagnostics:: span_lint_and_then ;
2
2
use clippy_utils:: fn_def_id;
3
3
4
- use rustc_data_structures:: fx:: FxHashSet ;
5
- use rustc_hir:: { def:: Res , def_id:: DefId , Crate , Expr } ;
4
+ use rustc_hir:: { def:: Res , def_id:: DefIdMap , Crate , Expr } ;
6
5
use rustc_lint:: { LateContext , LateLintPass } ;
7
6
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
8
- use rustc_span:: Symbol ;
7
+
8
+ use crate :: utils:: conf;
9
9
10
10
declare_clippy_lint ! {
11
11
/// ### What it does
12
12
/// Denies the configured methods and functions in clippy.toml
13
13
///
14
14
/// ### Why is this bad?
15
- /// Some methods are undesirable in certain contexts,
16
- /// and it's beneficial to lint for them as needed.
15
+ /// Some methods are undesirable in certain contexts, and it's beneficial to
16
+ /// lint for them as needed.
17
17
///
18
18
/// ### Example
19
19
/// An example clippy.toml configuration:
20
20
/// ```toml
21
21
/// # clippy.toml
22
- /// disallowed-methods = ["std::vec::Vec::leak", "std::time::Instant::now"]
22
+ /// disallowed-methods = [
23
+ /// # Can use a string as the path of the disallowed method.
24
+ /// "std::boxed::Box::new",
25
+ /// # Can also use an inline table with a `path` key.
26
+ /// { path = "std::time::Instant::now" },
27
+ /// # When using an inline table, can add a `reason` for why the method
28
+ /// # is disallowed.
29
+ /// { path = "std::vec::Vec::leak", reason = "no leaking memory" },
30
+ /// ]
23
31
/// ```
24
32
///
25
33
/// ```rust,ignore
26
34
/// // Example code where clippy issues a warning
27
35
/// let xs = vec![1, 2, 3, 4];
28
36
/// xs.leak(); // Vec::leak is disallowed in the config.
37
+ /// // The diagnostic contains the message "no leaking memory".
29
38
///
30
39
/// let _now = Instant::now(); // Instant::now is disallowed in the config.
40
+ ///
41
+ /// let _box = Box::new(3); // Box::new is disallowed in the config.
31
42
/// ```
32
43
///
33
44
/// Use instead:
@@ -43,18 +54,15 @@ declare_clippy_lint! {
43
54
44
55
#[ derive( Clone , Debug ) ]
45
56
pub struct DisallowedMethod {
46
- disallowed : FxHashSet < Vec < Symbol > > ,
47
- def_ids : FxHashSet < ( DefId , Vec < Symbol > ) > ,
57
+ conf_disallowed : Vec < conf :: DisallowedMethod > ,
58
+ disallowed : DefIdMap < Option < String > > ,
48
59
}
49
60
50
61
impl DisallowedMethod {
51
- pub fn new ( disallowed : & FxHashSet < String > ) -> Self {
62
+ pub fn new ( conf_disallowed : Vec < conf :: DisallowedMethod > ) -> Self {
52
63
Self {
53
- disallowed : disallowed
54
- . iter ( )
55
- . map ( |s| s. split ( "::" ) . map ( |seg| Symbol :: intern ( seg) ) . collect :: < Vec < _ > > ( ) )
56
- . collect ( ) ,
57
- def_ids : FxHashSet :: default ( ) ,
64
+ conf_disallowed,
65
+ disallowed : DefIdMap :: default ( ) ,
58
66
}
59
67
}
60
68
}
@@ -63,32 +71,36 @@ impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
63
71
64
72
impl < ' tcx > LateLintPass < ' tcx > for DisallowedMethod {
65
73
fn check_crate ( & mut self , cx : & LateContext < ' _ > , _: & Crate < ' _ > ) {
66
- for path in & self . disallowed {
67
- let segs = path. iter ( ) . map ( ToString :: to_string) . collect :: < Vec < _ > > ( ) ;
68
- if let Res :: Def ( _, id) = clippy_utils:: path_to_res ( cx, & segs. iter ( ) . map ( String :: as_str) . collect :: < Vec < _ > > ( ) )
69
- {
70
- self . def_ids . insert ( ( id, path. clone ( ) ) ) ;
74
+ for conf in & self . conf_disallowed {
75
+ let ( path, reason) = match conf {
76
+ conf:: DisallowedMethod :: Simple ( path) => ( path, None ) ,
77
+ conf:: DisallowedMethod :: WithReason { path, reason } => (
78
+ path,
79
+ reason. as_ref ( ) . map ( |reason| format ! ( "{} (from clippy.toml)" , reason) ) ,
80
+ ) ,
81
+ } ;
82
+ let segs: Vec < _ > = path. split ( "::" ) . collect ( ) ;
83
+ if let Res :: Def ( _, id) = clippy_utils:: path_to_res ( cx, & segs) {
84
+ self . disallowed . insert ( id, reason) ;
71
85
}
72
86
}
73
87
}
74
88
75
89
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
76
- if let Some ( def_id) = fn_def_id ( cx, expr) {
77
- if self . def_ids . iter ( ) . any ( |( id, _) | def_id == * id) {
78
- let func_path = cx. get_def_path ( def_id) ;
79
- let func_path_string = func_path
80
- . into_iter ( )
81
- . map ( Symbol :: to_ident_string)
82
- . collect :: < Vec < _ > > ( )
83
- . join ( "::" ) ;
84
-
85
- span_lint (
86
- cx,
87
- DISALLOWED_METHOD ,
88
- expr. span ,
89
- & format ! ( "use of a disallowed method `{}`" , func_path_string) ,
90
- ) ;
90
+ let def_id = match fn_def_id ( cx, expr) {
91
+ Some ( def_id) => def_id,
92
+ None => return ,
93
+ } ;
94
+ let reason = match self . disallowed . get ( & def_id) {
95
+ Some ( reason) => reason,
96
+ None => return ,
97
+ } ;
98
+ let func_path = cx. tcx . def_path_str ( def_id) ;
99
+ let msg = format ! ( "use of a disallowed method `{}`" , func_path) ;
100
+ span_lint_and_then ( cx, DISALLOWED_METHOD , expr. span , & msg, |diag| {
101
+ if let Some ( reason) = reason {
102
+ diag. note ( reason) ;
91
103
}
92
- }
104
+ } ) ;
93
105
}
94
106
}
0 commit comments