]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/self_named_constructors.rs
Add 'library/portable-simd/' from commit '1ce1c645cf27c4acdefe6ec8a11d1f0491954a99'
[rust.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     pub SELF_NAMED_CONSTRUCTORS,
36     style,
37     "method should not have the same name as the type it is implemented for"
38 }
39
40 declare_lint_pass!(SelfNamedConstructors => [SELF_NAMED_CONSTRUCTORS]);
41
42 impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
43     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
44         match impl_item.kind {
45             ImplItemKind::Fn(ref sig, _) => {
46                 if sig.decl.implicit_self.has_implicit_self() {
47                     return;
48                 }
49             },
50             _ => return,
51         }
52
53         let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
54         let item = cx.tcx.hir().expect_item(parent);
55         let self_ty = cx.tcx.type_of(item.def_id);
56         let ret_ty = return_ty(cx, impl_item.hir_id());
57
58         // Do not check trait impls
59         if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) {
60             return;
61         }
62
63         // Ensure method is constructor-like
64         if let Some(self_adt) = self_ty.ty_adt_def() {
65             if !contains_adt_constructor(cx.tcx, ret_ty, self_adt) {
66                 return;
67             }
68         } else if !contains_ty(cx.tcx, ret_ty, self_ty) {
69             return;
70         }
71
72         if_chain! {
73             if let Some(self_def) = self_ty.ty_adt_def();
74             if let Some(self_local_did) = self_def.did.as_local();
75             let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
76             if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id);
77             let type_name = x.ident.name.as_str().to_lowercase();
78             if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace("_", "") == type_name;
79
80             then {
81                 span_lint(
82                     cx,
83                     SELF_NAMED_CONSTRUCTORS,
84                     impl_item.span,
85                     &format!("constructor `{}` has the same name as the type", impl_item.ident.name),
86                 );
87             }
88         }
89     }
90 }