]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/needless_arbitrary_self_type.rs
Auto merge of #6111 - flip1995:rustup, r=flip1995
[rust.git] / clippy_lints / src / needless_arbitrary_self_type.rs
1 use crate::utils::{in_macro, span_lint_and_sugg};
2 use if_chain::if_chain;
3 use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
4 use rustc_errors::Applicability;
5 use rustc_lint::{EarlyContext, EarlyLintPass};
6 use rustc_session::{declare_lint_pass, declare_tool_lint};
7 use rustc_span::symbol::kw;
8 use rustc_span::Span;
9
10 declare_clippy_lint! {
11     /// **What it does:** The lint checks for `self` in fn parameters that
12     /// specify the `Self`-type explicitly
13     /// **Why is this bad?** Increases the amount and decreases the readability of code
14     ///
15     /// **Known problems:** None
16     ///
17     /// **Example:**
18     /// ```rust
19     /// enum ValType {
20     ///     I32,
21     ///     I64,
22     ///     F32,
23     ///     F64,
24     /// }
25     ///
26     /// impl ValType {
27     ///     pub fn bytes(self: Self) -> usize {
28     ///         match self {
29     ///             Self::I32 | Self::F32 => 4,
30     ///             Self::I64 | Self::F64 => 8,
31     ///         }
32     ///     }
33     /// }
34     /// ```
35     ///
36     /// Could be rewritten as
37     ///
38     /// ```rust
39     /// enum ValType {
40     ///     I32,
41     ///     I64,
42     ///     F32,
43     ///     F64,
44     /// }
45     ///
46     /// impl ValType {
47     ///     pub fn bytes(self) -> usize {
48     ///         match self {
49     ///             Self::I32 | Self::F32 => 4,
50     ///             Self::I64 | Self::F64 => 8,
51     ///         }
52     ///     }
53     /// }
54     /// ```
55     pub NEEDLESS_ARBITRARY_SELF_TYPE,
56     complexity,
57     "type of `self` parameter is already by default `Self`"
58 }
59
60 declare_lint_pass!(NeedlessArbitrarySelfType => [NEEDLESS_ARBITRARY_SELF_TYPE]);
61
62 enum Mode {
63     Ref(Option<Lifetime>),
64     Value,
65 }
66
67 fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mode: &Mode, mutbl: Mutability) {
68     if_chain! {
69         if let [segment] = &path.segments[..];
70         if segment.ident.name == kw::SelfUpper;
71         then {
72             // In case we have a named lifetime, we check if the name comes from expansion.
73             // If it does, at this point we know the rest of the parameter was written by the user,
74             // so let them decide what the name of the lifetime should be.
75             // See #6089 for more details.
76             let mut applicability = Applicability::MachineApplicable;
77             let self_param = match (binding_mode, mutbl) {
78                 (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
79                 (Mode::Ref(Some(lifetime)), Mutability::Mut) => {
80                     if in_macro(lifetime.ident.span) {
81                         applicability = Applicability::HasPlaceholders;
82                         "&'_ mut self".to_string()
83                     } else {
84                         format!("&{} mut self", &lifetime.ident.name)
85                     }
86                 },
87                 (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
88                 (Mode::Ref(Some(lifetime)), Mutability::Not) => {
89                     if in_macro(lifetime.ident.span) {
90                         applicability = Applicability::HasPlaceholders;
91                         "&'_ self".to_string()
92                     } else {
93                         format!("&{} self", &lifetime.ident.name)
94                     }
95                 },
96                 (Mode::Value, Mutability::Mut) => "mut self".to_string(),
97                 (Mode::Value, Mutability::Not) => "self".to_string(),
98             };
99
100             span_lint_and_sugg(
101                 cx,
102                 NEEDLESS_ARBITRARY_SELF_TYPE,
103                 span,
104                 "the type of the `self` parameter does not need to be arbitrary",
105                 "consider to change this parameter to",
106                 self_param,
107                 applicability,
108             )
109         }
110     }
111 }
112
113 impl EarlyLintPass for NeedlessArbitrarySelfType {
114     fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
115         // Bail out if the parameter it's not a receiver or was not written by the user
116         if !p.is_self() || in_macro(p.span) {
117             return;
118         }
119
120         match &p.ty.kind {
121             TyKind::Path(None, path) => {
122                 if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
123                     check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl)
124                 }
125             },
126             TyKind::Rptr(lifetime, mut_ty) => {
127                 if_chain! {
128                 if let TyKind::Path(None, path) = &mut_ty.ty.kind;
129                 if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
130                     then {
131                         check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl)
132                     }
133                 }
134             },
135             _ => {},
136         }
137     }
138 }