]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / needless_arbitrary_self_type.rs
CommitLineData
cdc7bbd5 1use clippy_utils::diagnostics::span_lint_and_sugg;
f20569fa 2use if_chain::if_chain;
f2b60f7d 3use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
f20569fa
XL
4use rustc_errors::Applicability;
5use rustc_lint::{EarlyContext, EarlyLintPass};
6use rustc_session::{declare_lint_pass, declare_tool_lint};
7use rustc_span::symbol::kw;
8use rustc_span::Span;
9
10declare_clippy_lint! {
94222f64
XL
11 /// ### What it does
12 /// The lint checks for `self` in fn parameters that
f20569fa 13 /// specify the `Self`-type explicitly
94222f64
XL
14 /// ### Why is this bad?
15 /// Increases the amount and decreases the readability of code
f20569fa 16 ///
94222f64 17 /// ### Example
f20569fa
XL
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 /// ```
a2a8927a 55 #[clippy::version = "1.47.0"]
f20569fa
XL
56 pub NEEDLESS_ARBITRARY_SELF_TYPE,
57 complexity,
58 "type of `self` parameter is already by default `Self`"
59}
60
61declare_lint_pass!(NeedlessArbitrarySelfType => [NEEDLESS_ARBITRARY_SELF_TYPE]);
62
63enum Mode {
64 Ref(Option<Lifetime>),
65 Value,
66}
67
68fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mode: &Mode, mutbl: Mutability) {
69 if_chain! {
70 if let [segment] = &path.segments[..];
71 if segment.ident.name == kw::SelfUpper;
72 then {
73 // In case we have a named lifetime, we check if the name comes from expansion.
74 // If it does, at this point we know the rest of the parameter was written by the user,
75 // so let them decide what the name of the lifetime should be.
76 // See #6089 for more details.
77 let mut applicability = Applicability::MachineApplicable;
78 let self_param = match (binding_mode, mutbl) {
79 (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
80 (Mode::Ref(Some(lifetime)), Mutability::Mut) => {
a2a8927a 81 if lifetime.ident.span.from_expansion() {
f20569fa
XL
82 applicability = Applicability::HasPlaceholders;
83 "&'_ mut self".to_string()
84 } else {
85 format!("&{} mut self", &lifetime.ident.name)
86 }
87 },
88 (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
89 (Mode::Ref(Some(lifetime)), Mutability::Not) => {
a2a8927a 90 if lifetime.ident.span.from_expansion() {
f20569fa
XL
91 applicability = Applicability::HasPlaceholders;
92 "&'_ self".to_string()
93 } else {
94 format!("&{} self", &lifetime.ident.name)
95 }
96 },
97 (Mode::Value, Mutability::Mut) => "mut self".to_string(),
98 (Mode::Value, Mutability::Not) => "self".to_string(),
99 };
100
101 span_lint_and_sugg(
102 cx,
103 NEEDLESS_ARBITRARY_SELF_TYPE,
104 span,
105 "the type of the `self` parameter does not need to be arbitrary",
106 "consider to change this parameter to",
107 self_param,
108 applicability,
109 )
110 }
111 }
112}
113
114impl EarlyLintPass for NeedlessArbitrarySelfType {
115 fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
116 // Bail out if the parameter it's not a receiver or was not written by the user
a2a8927a 117 if !p.is_self() || p.span.from_expansion() {
f20569fa
XL
118 return;
119 }
120
121 match &p.ty.kind {
122 TyKind::Path(None, path) => {
f2b60f7d 123 if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), _, _) = p.pat.kind {
17df50a5 124 check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
f20569fa
XL
125 }
126 },
f25598a0 127 TyKind::Ref(lifetime, mut_ty) => {
f20569fa
XL
128 if_chain! {
129 if let TyKind::Path(None, path) = &mut_ty.ty.kind;
f2b60f7d 130 if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind;
f20569fa 131 then {
17df50a5 132 check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
f20569fa
XL
133 }
134 }
135 },
136 _ => {},
137 }
138 }
139}