|
1 | | -use clippy_utils::diagnostics::span_lint_and_sugg; |
| 1 | +use clippy_utils::diagnostics::span_lint_and_then; |
2 | 2 | use clippy_utils::source::snippet_with_applicability; |
3 | | -use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; |
| 3 | +use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Param, PatKind, TyKind}; |
4 | 4 | use rustc_errors::Applicability; |
5 | 5 | use rustc_lint::{EarlyContext, EarlyLintPass}; |
6 | 6 | use rustc_session::declare_lint_pass; |
7 | | -use rustc_span::Span; |
8 | 7 | use rustc_span::symbol::kw; |
9 | 8 |
|
10 | 9 | declare_clippy_lint! { |
@@ -65,73 +64,62 @@ enum Mode { |
65 | 64 | Value, |
66 | 65 | } |
67 | 66 |
|
68 | | -fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mode: &Mode, mutbl: Mutability) { |
69 | | - if let [segment] = &path.segments[..] |
70 | | - && segment.ident.name == kw::SelfUpper |
71 | | - { |
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 lifetime.ident.span.from_expansion() { |
81 | | - applicability = Applicability::HasPlaceholders; |
82 | | - "&'_ mut self".to_string() |
83 | | - } else { |
84 | | - let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability); |
85 | | - format!("&{lt_name} mut self") |
86 | | - } |
87 | | - }, |
88 | | - (Mode::Ref(None), Mutability::Not) => "&self".to_string(), |
89 | | - (Mode::Ref(Some(lifetime)), Mutability::Not) => { |
90 | | - if lifetime.ident.span.from_expansion() { |
91 | | - applicability = Applicability::HasPlaceholders; |
92 | | - "&'_ self".to_string() |
93 | | - } else { |
94 | | - let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability); |
95 | | - format!("&{lt_name} self") |
96 | | - } |
97 | | - }, |
98 | | - (Mode::Value, Mutability::Mut) => "mut self".to_string(), |
99 | | - (Mode::Value, Mutability::Not) => "self".to_string(), |
100 | | - }; |
101 | | - |
102 | | - span_lint_and_sugg( |
103 | | - cx, |
104 | | - NEEDLESS_ARBITRARY_SELF_TYPE, |
105 | | - span, |
106 | | - "the type of the `self` parameter does not need to be arbitrary", |
107 | | - "consider to change this parameter to", |
108 | | - self_param, |
109 | | - applicability, |
110 | | - ); |
111 | | - } |
112 | | -} |
113 | | - |
114 | 67 | impl EarlyLintPass for NeedlessArbitrarySelfType { |
115 | 68 | fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) { |
116 | 69 | // Bail out if the parameter it's not a receiver or was not written by the user |
117 | 70 | if !p.is_self() || p.span.from_expansion() { |
118 | 71 | return; |
119 | 72 | } |
120 | 73 |
|
121 | | - match &p.ty.kind { |
122 | | - TyKind::Path(None, path) => { |
123 | | - if let PatKind::Ident(BindingMode(ByRef::No, mutbl), _, _) = p.pat.kind { |
124 | | - check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); |
125 | | - } |
| 74 | + let (path, binding_mode, mutbl) = match &p.ty.kind { |
| 75 | + TyKind::Path(None, path) if let PatKind::Ident(BindingMode(ByRef::No, mutbl), _, _) = p.pat.kind => { |
| 76 | + (path, Mode::Value, mutbl) |
126 | 77 | }, |
127 | | - TyKind::Ref(lifetime, mut_ty) => { |
| 78 | + TyKind::Ref(lifetime, mut_ty) |
128 | 79 | if let TyKind::Path(None, path) = &mut_ty.ty.kind |
129 | | - && let PatKind::Ident(BindingMode::NONE, _, _) = p.pat.kind |
130 | | - { |
131 | | - check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl); |
132 | | - } |
| 80 | + && let PatKind::Ident(BindingMode::NONE, _, _) = p.pat.kind => |
| 81 | + { |
| 82 | + (path, Mode::Ref(*lifetime), mut_ty.mutbl) |
133 | 83 | }, |
134 | | - _ => {}, |
| 84 | + _ => return, |
| 85 | + }; |
| 86 | + |
| 87 | + let span = p.span.to(p.ty.span); |
| 88 | + if let [segment] = &path.segments[..] |
| 89 | + && segment.ident.name == kw::SelfUpper |
| 90 | + { |
| 91 | + span_lint_and_then( |
| 92 | + cx, |
| 93 | + NEEDLESS_ARBITRARY_SELF_TYPE, |
| 94 | + span, |
| 95 | + "the type of the `self` parameter does not need to be arbitrary", |
| 96 | + |diag| { |
| 97 | + let mut applicability = Applicability::MachineApplicable; |
| 98 | + let add = match binding_mode { |
| 99 | + Mode::Value => String::new(), |
| 100 | + Mode::Ref(None) => mutbl.ref_prefix_str().to_string(), |
| 101 | + Mode::Ref(Some(lifetime)) => { |
| 102 | + // In case we have a named lifetime, we check if the name comes from expansion. |
| 103 | + // If it does, at this point we know the rest of the parameter was written by the user, |
| 104 | + // so let them decide what the name of the lifetime should be. |
| 105 | + // See #6089 for more details. |
| 106 | + let lt_name = if lifetime.ident.span.from_expansion() { |
| 107 | + applicability = Applicability::HasPlaceholders; |
| 108 | + "'_".into() |
| 109 | + } else { |
| 110 | + snippet_with_applicability(cx, lifetime.ident.span, "'_", &mut applicability) |
| 111 | + }; |
| 112 | + format!("&{lt_name} {mut_}", mut_ = mutbl.prefix_str()) |
| 113 | + }, |
| 114 | + }; |
| 115 | + |
| 116 | + let mut sugg = vec![(p.ty.span.with_lo(p.span.hi()), String::new())]; |
| 117 | + if !add.is_empty() { |
| 118 | + sugg.push((p.span.shrink_to_lo(), add)); |
| 119 | + } |
| 120 | + diag.multipart_suggestion_verbose("remove the type", sugg, applicability); |
| 121 | + }, |
| 122 | + ); |
135 | 123 | } |
136 | 124 | } |
137 | 125 | } |
0 commit comments