-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathself_named_constructors.rs
89 lines (82 loc) · 2.8 KB
/
self_named_constructors.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use clippy_utils::diagnostics::span_lint;
use clippy_utils::return_ty;
use clippy_utils::ty::contains_adt_constructor;
use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Warns when constructors have the same name as their types.
///
/// ### Why is this bad?
/// Repeating the name of the type is redundant.
///
/// ### Example
/// ```rust,ignore
/// struct Foo {}
///
/// impl Foo {
/// pub fn foo() -> Foo {
/// Foo {}
/// }
/// }
/// ```
/// Use instead:
/// ```rust,ignore
/// struct Foo {}
///
/// impl Foo {
/// pub fn new() -> Foo {
/// Foo {}
/// }
/// }
/// ```
#[clippy::version = "1.55.0"]
pub SELF_NAMED_CONSTRUCTORS,
style,
"method should not have the same name as the type it is implemented for"
}
declare_lint_pass!(SelfNamedConstructors => [SELF_NAMED_CONSTRUCTORS]);
impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
match impl_item.kind {
ImplItemKind::Fn(ref sig, _) => {
if sig.decl.implicit_self.has_implicit_self() {
return;
}
},
_ => return,
}
let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir_expect_item(parent);
let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
let ret_ty = return_ty(cx, impl_item.owner_id);
// Do not check trait impls
if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) {
return;
}
// Ensure method is constructor-like
if let Some(self_adt) = self_ty.ty_adt_def() {
if !contains_adt_constructor(ret_ty, self_adt) {
return;
}
} else if !ret_ty.contains(self_ty) {
return;
}
if let Some(self_def) = self_ty.ty_adt_def()
&& let Some(self_local_did) = self_def.did().as_local()
&& let Node::Item(x) = cx.tcx.hir_node_by_def_id(self_local_did)
&& let Some(type_ident) = x.kind.ident()
&& let type_name = type_ident.name.as_str().to_lowercase()
&& (impl_item.ident.name.as_str() == type_name
|| impl_item.ident.name.as_str().replace('_', "") == type_name)
{
span_lint(
cx,
SELF_NAMED_CONSTRUCTORS,
impl_item.span,
format!("constructor `{}` has the same name as the type", impl_item.ident.name),
);
}
}
}