1 use clippy_utils::diagnostics::span_lint;
2 use clippy_utils::return_ty;
3 use clippy_utils::ty::{contains_adt_constructor, contains_ty};
4 use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node};
5 use rustc_lint::{LateContext, LateLintPass};
6 use rustc_session::{declare_lint_pass, declare_tool_lint};
10 /// Warns when constructors have the same name as their types.
12 /// ### Why is this bad?
13 /// Repeating the name of the type is redundant.
20 /// pub fn foo() -> Foo {
30 /// pub fn new() -> Foo {
35 #[clippy::version = "1.55.0"]
36 pub SELF_NAMED_CONSTRUCTORS,
38 "method should not have the same name as the type it is implemented for"
41 declare_lint_pass!(SelfNamedConstructors => [SELF_NAMED_CONSTRUCTORS]);
43 impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
44 fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
45 match impl_item.kind {
46 ImplItemKind::Fn(ref sig, _) => {
47 if sig.decl.implicit_self.has_implicit_self() {
54 let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
55 let item = cx.tcx.hir().expect_item(parent);
56 let self_ty = cx.tcx.type_of(item.def_id);
57 let ret_ty = return_ty(cx, impl_item.hir_id());
59 // Do not check trait impls
60 if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) {
64 // Ensure method is constructor-like
65 if let Some(self_adt) = self_ty.ty_adt_def() {
66 if !contains_adt_constructor(cx.tcx, ret_ty, self_adt) {
69 } else if !contains_ty(cx.tcx, ret_ty, self_ty) {
74 if let Some(self_def) = self_ty.ty_adt_def();
75 if let Some(self_local_did) = self_def.did.as_local();
76 let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
77 if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id);
78 let type_name = x.ident.name.as_str().to_lowercase();
79 if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace('_', "") == type_name;
84 SELF_NAMED_CONSTRUCTORS,
86 &format!("constructor `{}` has the same name as the type", impl_item.ident.name),