diff options
| -rw-r--r-- | clippy_lints/src/use_self.rs | 320 | ||||
| -rw-r--r-- | tests/ui/use_self.fixed | 230 | ||||
| -rw-r--r-- | tests/ui/use_self.rs | 216 | ||||
| -rw-r--r-- | tests/ui/use_self.stderr | 100 | ||||
| -rw-r--r-- | tests/ui/use_self_trait.fixed | 4 | ||||
| -rw-r--r-- | tests/ui/use_self_trait.stderr | 14 |
6 files changed, 668 insertions, 216 deletions
diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 72d1ca73929..1b5070d1cff 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -1,24 +1,24 @@ +use crate::utils; +use crate::utils::snippet_opt; +use crate::utils::span_lint_and_sugg; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor}; +use rustc_hir::def::DefKind; +use rustc_hir::intravisit::{walk_expr, walk_impl_item, walk_ty, NestedVisitorMap, Visitor}; use rustc_hir::{ - def, FnDecl, FnRetTy, FnSig, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Path, PathSegment, QPath, - TyKind, + def, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, ImplItem, ImplItemKind, ItemKind, Node, Path, PathSegment, + QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; -use rustc_middle::ty::{DefIdTree, Ty}; -use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::kw; +use rustc_middle::ty::Ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{BytePos, Span}; use rustc_typeck::hir_ty_to_ty; -use crate::utils::{differing_macro_contexts, meets_msrv, span_lint_and_sugg}; - declare_clippy_lint! { /// **What it does:** Checks for unnecessary repetition of structure name when a /// replacement with `Self` is applicable. @@ -28,8 +28,7 @@ declare_clippy_lint! { /// feels inconsistent. /// /// **Known problems:** - /// - False positive when using associated types ([#2843](https://github.com/rust-lang/rust-clippy/issues/2843)) - /// - False positives in some situations when using generics ([#3410](https://github.com/rust-lang/rust-clippy/issues/3410)) + /// Unaddressed false negatives related to unresolved internal compiler errors. /// /// **Example:** /// ```rust @@ -54,23 +53,11 @@ declare_clippy_lint! { "unnecessary structure name repetition whereas `Self` is applicable" } -impl_lint_pass!(UseSelf => [USE_SELF]); +declare_lint_pass!(UseSelf => [USE_SELF]); const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element"; -fn span_use_self_lint(cx: &LateContext<'_>, path: &Path<'_>, last_segment: Option<&PathSegment<'_>>) { - let last_segment = last_segment.unwrap_or_else(|| path.segments.last().expect(SEGMENTS_MSG)); - - // Path segments only include actual path, no methods or fields. - let last_path_span = last_segment.ident.span; - - if differing_macro_contexts(path.span, last_path_span) { - return; - } - - // Only take path up to the end of last_path_span. - let span = path.span.with_hi(last_path_span.hi()); - +fn span_lint<'tcx>(cx: &LateContext<'tcx>, span: Span) { span_lint_and_sugg( cx, USE_SELF, @@ -82,107 +69,196 @@ fn span_use_self_lint(cx: &LateContext<'_>, path: &Path<'_>, last_segment: Optio ); } -// FIXME: always use this (more correct) visitor, not just in method signatures. -struct SemanticUseSelfVisitor<'a, 'tcx> { +#[allow(clippy::cast_possible_truncation)] +fn span_lint_until_last_segment<'tcx>(cx: &LateContext<'tcx>, span: Span, segment: &'tcx PathSegment<'tcx>) { + let sp = span.with_hi(segment.ident.span.lo()); + // remove the trailing :: + let span_without_last_segment = match snippet_opt(cx, sp) { + Some(snippet) => match snippet.rfind("::") { + Some(bidx) => sp.with_hi(sp.lo() + BytePos(bidx as u32)), + None => sp, + }, + None => sp, + }; + span_lint(cx, span_without_last_segment); +} + +fn span_lint_on_path_until_last_segment<'tcx>(cx: &LateContext<'tcx>, path: &'tcx Path<'tcx>) { + if path.segments.len() > 1 { + span_lint_until_last_segment(cx, path.span, path.segments.last().unwrap()); + } +} + +fn span_lint_on_qpath_resolved<'tcx>(cx: &LateContext<'tcx>, qpath: &'tcx QPath<'tcx>, until_last_segment: bool) { + if let QPath::Resolved(_, path) = qpath { + if until_last_segment { + span_lint_on_path_until_last_segment(cx, path); + } else { + span_lint(cx, path.span); + } + } +} + +struct ImplVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, self_ty: Ty<'tcx>, } -impl<'a, 'tcx> Visitor<'tcx> for SemanticUseSelfVisitor<'a, 'tcx> { +impl<'a, 'tcx> ImplVisitor<'a, 'tcx> { + fn check_trait_method_impl_decl( + &mut self, + impl_item: &ImplItem<'tcx>, + impl_decl: &'tcx FnDecl<'tcx>, + impl_trait_ref: ty::TraitRef<'tcx>, + ) { + let tcx = self.cx.tcx; + let trait_method = tcx + .associated_items(impl_trait_ref.def_id) + .find_by_name_and_kind(tcx, impl_item.ident, ty::AssocKind::Fn, impl_trait_ref.def_id) + .expect("impl method matches a trait method"); + + let trait_method_sig = tcx.fn_sig(trait_method.def_id); + let trait_method_sig = tcx.erase_late_bound_regions(&trait_method_sig); + + let output_hir_ty = if let FnRetTy::Return(ty) = &impl_decl.output { + Some(&**ty) + } else { + None + }; + + // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature. + // `trait_ty` (of type `ty::Ty`) is the semantic type for the signature in the trait. + // We use `impl_hir_ty` to see if the type was written as `Self`, + // `hir_ty_to_ty(...)` to check semantic types of paths, and + // `trait_ty` to determine which parts of the signature in the trait, mention + // the type being implemented verbatim (as opposed to `Self`). + for (impl_hir_ty, trait_ty) in impl_decl + .inputs + .iter() + .chain(output_hir_ty) + .zip(trait_method_sig.inputs_and_output) + { + // Check if the input/output type in the trait method specifies the implemented + // type verbatim, and only suggest `Self` if that isn't the case. + // This avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`, + // in an `impl Trait for u8`, when the trait always uses `Vec<u8>`. + // See also https://github.com/rust-lang/rust-clippy/issues/2894. + let self_ty = impl_trait_ref.self_ty(); + if !trait_ty.walk().any(|inner| inner == self_ty.into()) { + self.visit_ty(&impl_hir_ty); + } + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for ImplVisitor<'a, 'tcx> { type Map = Map<'tcx>; - fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'_>) { - if let TyKind::Path(QPath::Resolved(_, path)) = &hir_ty.kind { + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } + + fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { + if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind { match path.res { def::Res::SelfTy(..) => {}, _ => { - if hir_ty_to_ty(self.cx.tcx, hir_ty) == self.self_ty { - span_use_self_lint(self.cx, path, None); + match self.cx.tcx.hir().find(self.cx.tcx.hir().get_parent_node(hir_ty.hir_id)) { + Some(Node::Expr(Expr { + kind: ExprKind::Path(QPath::TypeRelative(_, _segment)), + .. + })) => { + // The following block correctly identifies applicable lint locations + // but `hir_ty_to_ty` calls cause odd ICEs. + // + // if hir_ty_to_ty(self.cx.tcx, hir_ty) == self.self_ty { + // // FIXME: this span manipulation should not be necessary + // // @flip1995 found an ast lowering issue in + // // https://github.com/rust-lang/rust/blob/master/src/librustc_ast_lowering/path.rs#L142-L162 + // span_lint_until_last_segment(self.cx, hir_ty.span, segment); + // } + }, + _ => { + if hir_ty_to_ty(self.cx.tcx, hir_ty) == self.self_ty { + span_lint(self.cx, hir_ty.span) + } + }, } }, } } - walk_ty(self, hir_ty) + walk_ty(self, hir_ty); } - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None - } -} - -fn check_trait_method_impl_decl<'tcx>( - cx: &LateContext<'tcx>, - impl_item: &ImplItem<'_>, - impl_decl: &'tcx FnDecl<'_>, - impl_trait_ref: ty::TraitRef<'tcx>, -) { - let trait_method = cx - .tcx - .associated_items(impl_trait_ref.def_id) - .find_by_name_and_kind(cx.tcx, impl_item.ident, ty::AssocKind::Fn, impl_trait_ref.def_id) - .expect("impl method matches a trait method"); - - let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id); - let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig); - - let output_hir_ty = if let FnRetTy::Return(ty) = &impl_decl.output { - Some(&**ty) - } else { - None - }; - - // `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature. - // `trait_ty` (of type `ty::Ty`) is the semantic type for the signature in the trait. - // We use `impl_hir_ty` to see if the type was written as `Self`, - // `hir_ty_to_ty(...)` to check semantic types of paths, and - // `trait_ty` to determine which parts of the signature in the trait, mention - // the type being implemented verbatim (as opposed to `Self`). - for (impl_hir_ty, trait_ty) in impl_decl - .inputs - .iter() - .chain(output_hir_ty) - .zip(trait_method_sig.inputs_and_output) - { - // Check if the input/output type in the trait method specifies the implemented - // type verbatim, and only suggest `Self` if that isn't the case. - // This avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`, - // in an `impl Trait for u8`, when the trait always uses `Vec<u8>`. - // See also https://github.com/rust-lang/rust-clippy/issues/2894. - let self_ty = impl_trait_ref.self_ty(); - if !trait_ty.walk().any(|inner| inner == self_ty.into()) { - let mut visitor = SemanticUseSelfVisitor { cx, self_ty }; - - visitor.visit_ty(&impl_hir_ty); + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + fn expr_ty_matches<'tcx>(expr: &'tcx Expr<'tcx>, self_ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { + let def_id = expr.hir_id.owner; + if cx.tcx.has_typeck_results(def_id) { + cx.tcx.typeck(def_id).expr_ty_opt(expr) == Some(self_ty) + } else { + false + } } - } -} - -const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); - -pub struct UseSelf { - msrv: Option<RustcVersion>, -} - -impl UseSelf { - #[must_use] - pub fn new(msrv: Option<RustcVersion>) -> Self { - Self { msrv } + match expr.kind { + ExprKind::Struct(QPath::Resolved(_, path), ..) => { + if expr_ty_matches(expr, self.self_ty, self.cx) { + match path.res { + def::Res::SelfTy(..) => (), + def::Res::Def(DefKind::Variant, _) => span_lint_on_path_until_last_segment(self.cx, path), + _ => { + span_lint(self.cx, path.span); + }, + } + } + }, + // tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`) + ExprKind::Call(fun, _) => { + if let Expr { + kind: ExprKind::Path(ref qpath), + .. + } = fun + { + if expr_ty_matches(expr, self.self_ty, self.cx) { + let res = utils::qpath_res(self.cx, qpath, fun.hir_id); + + if let def::Res::Def(DefKind::Ctor(ctor_of, _), ..) = res { + match ctor_of { + def::CtorOf::Variant => { + span_lint_on_qpath_resolved(self.cx, qpath, true); + }, + def::CtorOf::Struct => { + span_lint_on_qpath_resolved(self.cx, qpath, false); + }, + } + } + } + } + }, + // unit enum variants (`Enum::A`) + ExprKind::Path(ref qpath) => { + if expr_ty_matches(expr, self.self_ty, self.cx) { + span_lint_on_qpath_resolved(self.cx, qpath, true); + } + }, + _ => (), + } + walk_expr(self, expr); } } impl<'tcx> LateLintPass<'tcx> for UseSelf { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) { + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { + if in_external_macro(cx.sess(), impl_item.span) { return; } - if in_external_macro(cx.sess(), item.span) { - return; - } + let parent_id = cx.tcx.hir().get_parent_item(impl_item.hir_id); + let imp = cx.tcx.hir().expect_item(parent_id); + if_chain! { - if let ItemKind::Impl(impl_) = &item.kind; - if let TyKind::Path(QPath::Resolved(_, ref item_path)) = impl_.self_ty.kind; + if let ItemKind::Impl { self_ty: hir_self_ty, .. } = imp.kind; + if let TyKind::Path(QPath::Resolved(_, ref item_path)) = hir_self_ty.kind; then { let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args; let should_check = parameters.as_ref().map_or( @@ -191,31 +267,23 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { &&!params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) ); + // TODO: don't short-circuit upon lifetime parameters if should_check { - let visitor = &mut UseSelfVisitor { - item_path, - cx, - }; - let impl_def_id = cx.tcx.hir().local_def_id(item.hir_id); - let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id); - - if let Some(impl_trait_ref) = impl_trait_ref { - for impl_item_ref in impl_.items { - let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id); - if let ImplItemKind::Fn(FnSig{ decl: impl_decl, .. }, impl_body_id) - = &impl_item.kind { - check_trait_method_impl_decl(cx, impl_item, impl_decl, impl_trait_ref); - - let body = cx.tcx.hir().body(*impl_body_id); - visitor.visit_body(body); - } else { - visitor.visit_impl_item(impl_item); - } - } - } else { - for impl_item_ref in impl_.items { - let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id); - visitor.visit_impl_item(impl_item); + let self_ty = hir_ty_to_ty(cx.tcx, hir_self_ty); + let visitor = &mut ImplVisitor { cx, self_ty }; + + let tcx = cx.tcx; + let impl_def_id = tcx.hir().local_def_id(imp.hir_id); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + if_chain! { + if let Some(impl_trait_ref) = impl_trait_ref; + if let ImplItemKind::Fn(FnSig { decl: impl_decl, .. }, impl_body_id) = &impl_item.kind; + then { + visitor.check_trait_method_impl_decl(impl_item, impl_decl, impl_trait_ref); + let body = tcx.hir().body(*impl_body_id); + visitor.visit_body(body); + } else { + walk_impl_item(visitor, impl_item) } } } diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index bb2012441d9..916484eef93 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -15,13 +15,14 @@ mod use_self { Self {} } fn test() -> Self { - Self::new() + Foo::new() } } impl Default for Foo { fn default() -> Self { - Self::new() + // FIXME: applicable here + Foo::new() } } } @@ -87,7 +88,11 @@ mod existential { struct Foo; impl Foo { - fn bad(foos: &[Self]) -> impl Iterator<Item = &Self> { + // FIXME: + // TyKind::Def (used for `impl Trait` types) does not include type parameters yet. + // See documentation in rustc_hir::hir::TyKind. + // The hir tree walk stops at `impl Iterator` level and does not inspect &Foo. + fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> { foos.iter() } @@ -177,11 +182,22 @@ mod issue3410 { struct B; trait Trait<T> { - fn a(v: T); + fn a(v: T) -> Self; } impl Trait<Vec<A>> for Vec<B> { - fn a(_: Vec<A>) {} + fn a(_: Vec<A>) -> Self { + unimplemented!() + } + } + + impl<T> Trait<Vec<A>> for Vec<T> + where + T: Trait<B>, + { + fn a(v: Vec<A>) -> Self { + <Vec<B>>::a(v).into_iter().map(Trait::a).collect() + } } } @@ -197,8 +213,8 @@ mod rustfix { fn fun_1() {} fn fun_2() { - Self::fun_1(); - Self::A; + nested::A::fun_1(); + nested::A::A; Self {}; } @@ -219,7 +235,8 @@ mod issue3567 { impl Test for TestStruct { fn test() -> TestStruct { - Self::from_something() + // FIXME: applicable here + TestStruct::from_something() } } } @@ -233,12 +250,14 @@ mod paths_created_by_lowering { const A: usize = 0; const B: usize = 1; - async fn g() -> Self { + // FIXME: applicable here + async fn g() -> S { Self {} } fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] { - &p[Self::A..Self::B] + // FIXME: applicable here twice + &p[S::A..S::B] } } @@ -252,3 +271,194 @@ mod paths_created_by_lowering { } } } + +// reused from #1997 +mod generics { + struct Foo<T> { + value: T, + } + + impl<T> Foo<T> { + // `Self` is applicable here + fn foo(value: T) -> Self { + Self { value } + } + + // `Cannot` use `Self` as a return type as the generic types are different + fn bar(value: i32) -> Foo<i32> { + Foo { value } + } + } +} + +mod issue4140 { + pub struct Error<From, To> { + _from: From, + _too: To, + } + + pub trait From<T> { + type From; + type To; + + fn from(value: T) -> Self; + } + + pub trait TryFrom<T> + where + Self: Sized, + { + type From; + type To; + + fn try_from(value: T) -> Result<Self, Error<Self::From, Self::To>>; + } + + impl<F, T> TryFrom<F> for T + where + T: From<F>, + { + type From = Self; + type To = Self; + + fn try_from(value: F) -> Result<Self, Error<Self::From, Self::To>> { + Ok(From::from(value)) + } + } + + impl From<bool> for i64 { + type From = bool; + type To = Self; + + fn from(value: bool) -> Self { + if value { + 100 + } else { + 0 + } + } + } +} + +mod issue2843 { + trait Foo { + type Bar; + } + + impl Foo for usize { + type Bar = u8; + } + + impl<T: Foo> Foo for Option<T> { + type Bar = Option<T::Bar>; + } +} + +mod issue3859 { + pub struct Foo; + pub struct Bar([usize; 3]); + + impl Foo { + pub const BAR: usize = 3; + + pub fn foo() { + const _X: usize = Foo::BAR; + // const _Y: usize = Self::BAR; + } + } +} + +mod issue4305 { + trait Foo: 'static {} + + struct Bar; + + impl Foo for Bar {} + + impl<T: Foo> From<T> for Box<dyn Foo> { + fn from(t: T) -> Self { + // FIXME: applicable here + Box::new(t) + } + } +} + +mod lint_at_item_level { + struct Foo {} + + #[allow(clippy::use_self)] + impl Foo { + fn new() -> Foo { + Foo {} + } + } + + #[allow(clippy::use_self)] + impl Default for Foo { + fn default() -> Foo { + Foo::new() + } + } +} + +mod lint_at_impl_item_level { + struct Foo {} + + impl Foo { + #[allow(clippy::use_self)] + fn new() -> Foo { + Foo {} + } + } + + impl Default for Foo { + #[allow(clippy::use_self)] + fn default() -> Foo { + Foo::new() + } + } +} + +mod issue4734 { + #[repr(C, packed)] + pub struct X { + pub x: u32, + } + + impl From<X> for u32 { + fn from(c: X) -> Self { + unsafe { core::mem::transmute(c) } + } + } +} + +mod nested_paths { + use std::convert::Into; + mod submod { + pub struct B {} + pub struct C {} + + impl Into<C> for B { + fn into(self) -> C { + C {} + } + } + } + + struct A<T> { + t: T, + } + + impl<T> A<T> { + fn new<V: Into<T>>(v: V) -> Self { + Self { t: Into::into(v) } + } + } + + impl A<submod::C> { + fn test() -> Self { + // FIXME: applicable here + A::new::<submod::B>(submod::B {}) + } + } +} diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index ddfd2beba31..347f5e96555 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -21,6 +21,7 @@ mod use_self { impl Default for Foo { fn default() -> Foo { + // FIXME: applicable here Foo::new() } } @@ -87,7 +88,11 @@ mod existential { struct Foo; impl Foo { - fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> { + // FIXME: + // TyKind::Def (used for `impl Trait` types) does not include type parameters yet. + // See documentation in rustc_hir::hir::TyKind. + // The hir tree walk stops at `impl Iterator` level and does not inspect &Foo. + fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> { foos.iter() } @@ -177,11 +182,22 @@ mod issue3410 { struct B; trait Trait<T> { - fn a(v: T); + fn a(v: T) -> Self; } impl Trait<Vec<A>> for Vec<B> { - fn a(_: Vec<A>) {} + fn a(_: Vec<A>) -> Self { + unimplemented!() + } + } + + impl<T> Trait<Vec<A>> for Vec<T> + where + T: Trait<B>, + { + fn a(v: Vec<A>) -> Self { + <Vec<B>>::a(v).into_iter().map(Trait::a).collect() + } } } @@ -219,6 +235,7 @@ mod issue3567 { impl Test for TestStruct { fn test() -> TestStruct { + // FIXME: applicable here TestStruct::from_something() } } @@ -233,11 +250,13 @@ mod paths_created_by_lowering { const A: usize = 0; const B: usize = 1; + // FIXME: applicable here async fn g() -> S { S {} } fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] { + // FIXME: applicable here twice &p[S::A..S::B] } } @@ -252,3 +271,194 @@ mod paths_created_by_lowering { } } } + +// reused from #1997 +mod generics { + struct Foo<T> { + value: T, + } + + impl<T> Foo<T> { + // `Self` is applicable here + fn foo(value: T) -> Foo<T> { + Foo { value } + } + + // `Cannot` use `Self` as a return type as the generic types are different + fn bar(value: i32) -> Foo<i32> { + Foo { value } + } + } +} + +mod issue4140 { + pub struct Error<From, To> { + _from: From, + _too: To, + } + + pub trait From<T> { + type From; + type To; + + fn from(value: T) -> Self; + } + + pub trait TryFrom<T> + where + Self: Sized, + { + type From; + type To; + + fn try_from(value: T) -> Result<Self, Error<Self::From, Self::To>>; + } + + impl<F, T> TryFrom<F> for T + where + T: From<F>, + { + type From = T::From; + type To = T::To; + + fn try_from(value: F) -> Result<Self, Error<Self::From, Self::To>> { + Ok(From::from(value)) + } + } + + impl From<bool> for i64 { + type From = bool; + type To = Self; + + fn from(value: bool) -> Self { + if value { + 100 + } else { + 0 + } + } + } +} + +mod issue2843 { + trait Foo { + type Bar; + } + + impl Foo for usize { + type Bar = u8; + } + + impl<T: Foo> Foo for Option<T> { + type Bar = Option<T::Bar>; + } +} + +mod issue3859 { + pub struct Foo; + pub struct Bar([usize; 3]); + + impl Foo { + pub const BAR: usize = 3; + + pub fn foo() { + const _X: usize = Foo::BAR; + // const _Y: usize = Self::BAR; + } + } +} + +mod issue4305 { + trait Foo: 'static {} + + struct Bar; + + impl Foo for Bar {} + + impl<T: Foo> From<T> for Box<dyn Foo> { + fn from(t: T) -> Self { + // FIXME: applicable here + Box::new(t) + } + } +} + +mod lint_at_item_level { + struct Foo {} + + #[allow(clippy::use_self)] + impl Foo { + fn new() -> Foo { + Foo {} + } + } + + #[allow(clippy::use_self)] + impl Default for Foo { + fn default() -> Foo { + Foo::new() + } + } +} + +mod lint_at_impl_item_level { + struct Foo {} + + impl Foo { + #[allow(clippy::use_self)] + fn new() -> Foo { + Foo {} + } + } + + impl Default for Foo { + #[allow(clippy::use_self)] + fn default() -> Foo { + Foo::new() + } + } +} + +mod issue4734 { + #[repr(C, packed)] + pub struct X { + pub x: u32, + } + + impl From<X> for u32 { + fn from(c: X) -> Self { + unsafe { core::mem::transmute(c) } + } + } +} + +mod nested_paths { + use std::convert::Into; + mod submod { + pub struct B {} + pub struct C {} + + impl Into<C> for B { + fn into(self) -> C { + C {} + } + } + } + + struct A<T> { + t: T, + } + + impl<T> A<T> { + fn new<V: Into<T>>(v: V) -> Self { + Self { t: Into::into(v) } + } + } + + impl A<submod::C> { + fn test() -> Self { + // FIXME: applicable here + A::new::<submod::B>(submod::B {}) + } + } +} diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index 80e1bfc75e8..a88dd04f13d 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -19,37 +19,25 @@ LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:18:13 - | -LL | Foo::new() - | ^^^ help: use the applicable keyword: `Self` - -error: unnecessary structure name repetition --> $DIR/use_self.rs:23:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:24:13 - | -LL | Foo::new() - | ^^^ help: use the applicable keyword: `Self` - -error: unnecessary structure name repetition - --> $DIR/use_self.rs:90:56 + --> $DIR/use_self.rs:94:24 | -LL | fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> { - | ^^^ help: use the applicable keyword: `Self` +LL | fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:105:13 + --> $DIR/use_self.rs:109:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:113:25 + --> $DIR/use_self.rs:117:25 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -60,7 +48,7 @@ LL | use_self_expand!(); // Should lint in local macros = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: unnecessary structure name repetition - --> $DIR/use_self.rs:114:17 + --> $DIR/use_self.rs:118:17 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` @@ -71,94 +59,82 @@ LL | use_self_expand!(); // Should lint in local macros = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: unnecessary structure name repetition - --> $DIR/use_self.rs:149:21 + --> $DIR/use_self.rs:141:29 | -LL | fn baz() -> Foo { - | ^^^ help: use the applicable keyword: `Self` +LL | fn bar() -> Bar { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:150:13 + --> $DIR/use_self.rs:142:21 | -LL | Foo {} - | ^^^ help: use the applicable keyword: `Self` +LL | Bar { foo: Foo {} } + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:137:29 + --> $DIR/use_self.rs:153:21 | -LL | fn bar() -> Bar { - | ^^^ help: use the applicable keyword: `Self` +LL | fn baz() -> Foo { + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:138:21 + --> $DIR/use_self.rs:154:13 | -LL | Bar { foo: Foo {} } - | ^^^ help: use the applicable keyword: `Self` +LL | Foo {} + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:167:21 + --> $DIR/use_self.rs:171:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:168:21 + --> $DIR/use_self.rs:172:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:169:21 + --> $DIR/use_self.rs:173:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:200:13 - | -LL | nested::A::fun_1(); - | ^^^^^^^^^ help: use the applicable keyword: `Self` - -error: unnecessary structure name repetition - --> $DIR/use_self.rs:201:13 - | -LL | nested::A::A; - | ^^^^^^^^^ help: use the applicable keyword: `Self` - -error: unnecessary structure name repetition - --> $DIR/use_self.rs:203:13 + --> $DIR/use_self.rs:218:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:222:13 + --> $DIR/use_self.rs:254:13 | -LL | TestStruct::from_something() - | ^^^^^^^^^^ help: use the applicable keyword: `Self` +LL | S {} + | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:236:25 + --> $DIR/use_self.rs:282:29 | -LL | async fn g() -> S { - | ^ help: use the applicable keyword: `Self` +LL | fn foo(value: T) -> Foo<T> { + | ^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:237:13 + --> $DIR/use_self.rs:283:13 | -LL | S {} - | ^ help: use the applicable keyword: `Self` +LL | Foo { value } + | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:241:16 + --> $DIR/use_self.rs:320:21 | -LL | &p[S::A..S::B] - | ^ help: use the applicable keyword: `Self` +LL | type From = T::From; + | ^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self.rs:241:22 + --> $DIR/use_self.rs:321:19 | -LL | &p[S::A..S::B] - | ^ help: use the applicable keyword: `Self` +LL | type To = T::To; + | ^^^^^ help: use the applicable keyword: `Self` -error: aborting due to 25 previous errors +error: aborting due to 21 previous errors diff --git a/tests/ui/use_self_trait.fixed b/tests/ui/use_self_trait.fixed index 1582ae114bf..d425f953a9c 100644 --- a/tests/ui/use_self_trait.fixed +++ b/tests/ui/use_self_trait.fixed @@ -33,7 +33,7 @@ impl SelfTrait for Bad { fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {} fn vals(_: Self) -> Self { - Self::default() + Bad::default() } } @@ -47,7 +47,7 @@ impl Mul for Bad { impl Clone for Bad { fn clone(&self) -> Self { - Self + Bad } } diff --git a/tests/ui/use_self_trait.stderr b/tests/ui/use_self_trait.stderr index 4f2506cc119..fa528cc5b7d 100644 --- a/tests/ui/use_self_trait.stderr +++ b/tests/ui/use_self_trait.stderr @@ -61,12 +61,6 @@ LL | fn vals(_: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> $DIR/use_self_trait.rs:36:9 - | -LL | Bad::default() - | ^^^ help: use the applicable keyword: `Self` - -error: unnecessary structure name repetition --> $DIR/use_self_trait.rs:41:19 | LL | type Output = Bad; @@ -84,11 +78,5 @@ error: unnecessary structure name repetition LL | fn mul(self, rhs: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` -error: unnecessary structure name repetition - --> $DIR/use_self_trait.rs:50:9 - | -LL | Bad - | ^^^ help: use the applicable keyword: `Self` - -error: aborting due to 15 previous errors +error: aborting due to 13 previous errors |
