]> git.proxmox.com Git - rustc.git/blob - src/tools/clippy/clippy_lints/src/self_named_constructors.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / self_named_constructors.rs
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};
7
8 declare_clippy_lint! {
9 /// ### What it does
10 /// Warns when constructors have the same name as their types.
11 ///
12 /// ### Why is this bad?
13 /// Repeating the name of the type is redundant.
14 ///
15 /// ### Example
16 /// ```rust,ignore
17 /// struct Foo {}
18 ///
19 /// impl Foo {
20 /// pub fn foo() -> Foo {
21 /// Foo {}
22 /// }
23 /// }
24 /// ```
25 /// Use instead:
26 /// ```rust,ignore
27 /// struct Foo {}
28 ///
29 /// impl Foo {
30 /// pub fn new() -> Foo {
31 /// Foo {}
32 /// }
33 /// }
34 /// ```
35 #[clippy::version = "1.55.0"]
36 pub SELF_NAMED_CONSTRUCTORS,
37 style,
38 "method should not have the same name as the type it is implemented for"
39 }
40
41 declare_lint_pass!(SelfNamedConstructors => [SELF_NAMED_CONSTRUCTORS]);
42
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() {
48 return;
49 }
50 },
51 _ => return,
52 }
53
54 let parent = cx.tcx.hir().get_parent_item(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());
58
59 // Do not check trait impls
60 if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) {
61 return;
62 }
63
64 // Ensure method is constructor-like
65 if let Some(self_adt) = self_ty.ty_adt_def() {
66 if !contains_adt_constructor(ret_ty, self_adt) {
67 return;
68 }
69 } else if !contains_ty(ret_ty, self_ty) {
70 return;
71 }
72
73 if_chain! {
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;
80
81 then {
82 span_lint(
83 cx,
84 SELF_NAMED_CONSTRUCTORS,
85 impl_item.span,
86 &format!("constructor `{}` has the same name as the type", impl_item.ident.name),
87 );
88 }
89 }
90 }
91 }