-use crate::utils::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_sugg;
use if_chain::if_chain;
use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
use rustc_errors::Applicability;
use rustc_span::Span;
declare_clippy_lint! {
- /// **What it does:** The lint checks for `self` in fn parameters that
+ /// ### What it does
+ /// The lint checks for `self` in fn parameters that
/// specify the `Self`-type explicitly
- /// **Why is this bad?** Increases the amount and decreases the readability of code
+ /// ### Why is this bad?
+ /// Increases the amount and decreases the readability of code
///
- /// **Known problems:** None
- ///
- /// **Example:**
+ /// ### Example
/// ```rust
/// enum ValType {
/// I32,
/// }
/// }
/// ```
+ #[clippy::version = "1.47.0"]
pub NEEDLESS_ARBITRARY_SELF_TYPE,
complexity,
"type of `self` parameter is already by default `Self`"
if let [segment] = &path.segments[..];
if segment.ident.name == kw::SelfUpper;
then {
+ // In case we have a named lifetime, we check if the name comes from expansion.
+ // If it does, at this point we know the rest of the parameter was written by the user,
+ // so let them decide what the name of the lifetime should be.
+ // See #6089 for more details.
+ let mut applicability = Applicability::MachineApplicable;
let self_param = match (binding_mode, mutbl) {
(Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
- (Mode::Ref(Some(lifetime)), Mutability::Mut) => format!("&{} mut self", &lifetime.ident.name),
+ (Mode::Ref(Some(lifetime)), Mutability::Mut) => {
+ if lifetime.ident.span.from_expansion() {
+ applicability = Applicability::HasPlaceholders;
+ "&'_ mut self".to_string()
+ } else {
+ format!("&{} mut self", &lifetime.ident.name)
+ }
+ },
(Mode::Ref(None), Mutability::Not) => "&self".to_string(),
- (Mode::Ref(Some(lifetime)), Mutability::Not) => format!("&{} self", &lifetime.ident.name),
+ (Mode::Ref(Some(lifetime)), Mutability::Not) => {
+ if lifetime.ident.span.from_expansion() {
+ applicability = Applicability::HasPlaceholders;
+ "&'_ self".to_string()
+ } else {
+ format!("&{} self", &lifetime.ident.name)
+ }
+ },
(Mode::Value, Mutability::Mut) => "mut self".to_string(),
(Mode::Value, Mutability::Not) => "self".to_string(),
};
"the type of the `self` parameter does not need to be arbitrary",
"consider to change this parameter to",
self_param,
- Applicability::MachineApplicable,
+ applicability,
)
}
}
impl EarlyLintPass for NeedlessArbitrarySelfType {
fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
- if !p.is_self() {
+ // Bail out if the parameter it's not a receiver or was not written by the user
+ if !p.is_self() || p.span.from_expansion() {
return;
}
match &p.ty.kind {
TyKind::Path(None, path) => {
if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
- check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl)
+ check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
}
},
TyKind::Rptr(lifetime, mut_ty) => {
if let TyKind::Path(None, path) = &mut_ty.ty.kind;
if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
then {
- check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl)
+ check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
}
}
},