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