]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/disallowed_method.rs
Rollup merge of #83092 - petrochenkov:qspan, r=estebank
[rust.git] / clippy_lints / src / disallowed_method.rs
1 use crate::utils::{fn_def_id, span_lint};
2
3 use rustc_data_structures::fx::FxHashSet;
4 use rustc_hir::Expr;
5 use rustc_lint::{LateContext, LateLintPass};
6 use rustc_session::{declare_tool_lint, impl_lint_pass};
7 use rustc_span::Symbol;
8
9 declare_clippy_lint! {
10     /// **What it does:** Denies the configured methods and functions in clippy.toml
11     ///
12     /// **Why is this bad?** Some methods are undesirable in certain contexts,
13     /// and it's beneficial to lint for them as needed.
14     ///
15     /// **Known problems:** Currently, you must write each function as a
16     /// fully-qualified path. This lint doesn't support aliases or reexported
17     /// names; be aware that many types in `std` are actually reexports.
18     ///
19     /// For example, if you want to disallow `Duration::as_secs`, your clippy.toml
20     /// configuration would look like
21     /// `disallowed-methods = ["core::time::Duration::as_secs"]` and not
22     /// `disallowed-methods = ["std::time::Duration::as_secs"]` as you might expect.
23     ///
24     /// **Example:**
25     ///
26     /// An example clippy.toml configuration:
27     /// ```toml
28     /// # clippy.toml
29     /// disallowed-methods = ["alloc::vec::Vec::leak", "std::time::Instant::now"]
30     /// ```
31     ///
32     /// ```rust,ignore
33     /// // Example code where clippy issues a warning
34     /// let xs = vec![1, 2, 3, 4];
35     /// xs.leak(); // Vec::leak is disallowed in the config.
36     ///
37     /// let _now = Instant::now(); // Instant::now is disallowed in the config.
38     /// ```
39     ///
40     /// Use instead:
41     /// ```rust,ignore
42     /// // Example code which does not raise clippy warning
43     /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config.
44     /// xs.push(123); // Vec::push is _not_ disallowed in the config.
45     /// ```
46     pub DISALLOWED_METHOD,
47     nursery,
48     "use of a disallowed method call"
49 }
50
51 #[derive(Clone, Debug)]
52 pub struct DisallowedMethod {
53     disallowed: FxHashSet<Vec<Symbol>>,
54 }
55
56 impl DisallowedMethod {
57     pub fn new(disallowed: &FxHashSet<String>) -> Self {
58         Self {
59             disallowed: disallowed
60                 .iter()
61                 .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
62                 .collect(),
63         }
64     }
65 }
66
67 impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
68
69 impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
70     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
71         if let Some(def_id) = fn_def_id(cx, expr) {
72             let func_path = cx.get_def_path(def_id);
73             if self.disallowed.contains(&func_path) {
74                 let func_path_string = func_path
75                     .into_iter()
76                     .map(Symbol::to_ident_string)
77                     .collect::<Vec<_>>()
78                     .join("::");
79
80                 span_lint(
81                     cx,
82                     DISALLOWED_METHOD,
83                     expr.span,
84                     &format!("use of a disallowed method `{}`", func_path_string),
85                 );
86             }
87         }
88     }
89 }