]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/use_self.rs
Don't trigger `Self` suggestion inside derives
[rust.git] / clippy_lints / src / use_self.rs
1 use rustc::lint::{LintArray, LateLintPass, LateContext, LintPass};
2 use rustc::hir::*;
3 use rustc::hir::intravisit::{Visitor, walk_path, NestedVisitorMap};
4 use utils::{span_lint_and_then, in_macro};
5 use syntax::ast::NodeId;
6 use syntax_pos::symbol::keywords::SelfType;
7
8 /// **What it does:** Checks for unnecessary repetition of structure name when a
9 /// replacement with `Self` is applicable.
10 ///
11 /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct name
12 /// feels inconsistent.
13 ///
14 /// **Known problems:** None.
15 ///
16 /// **Example:**
17 /// ```rust
18 /// struct Foo {}
19 /// impl Foo {
20 ///     fn new() -> Foo {
21 ///         Foo {}
22 ///     }
23 /// }
24 /// ```
25 /// could be
26 /// ```
27 /// struct Foo {}
28 /// impl Foo {
29 ///     fn new() -> Self {
30 ///         Self {}
31 ///     }
32 /// }
33 /// ```
34 declare_lint! {
35     pub USE_SELF,
36     Allow,
37     "Unnecessary structure name repetition whereas `Self` is applicable"
38 }
39
40 #[derive(Copy, Clone, Default)]
41 pub struct UseSelf;
42
43 impl LintPass for UseSelf {
44     fn get_lints(&self) -> LintArray {
45         lint_array!(USE_SELF)
46     }
47 }
48
49 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
50     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
51         if in_macro(item.span) {
52             return;
53         }
54         if_let_chain!([
55             let ItemImpl(.., ref item_type, ref refs) = item.node,
56             let Ty_::TyPath(QPath::Resolved(_, ref item_path)) = item_type.node,
57         ], {
58             let visitor = &mut UseSelfVisitor {
59                 item_path: item_path,
60                 cx: cx,
61             };
62             for impl_item_ref in refs {
63                 visitor.visit_impl_item(cx.tcx.hir.impl_item(impl_item_ref.id));
64             }
65         })
66     }
67 }
68
69 struct UseSelfVisitor<'a, 'tcx: 'a> {
70     item_path: &'a Path,
71     cx: &'a LateContext<'a, 'tcx>,
72 }
73
74 impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
75     fn visit_path(&mut self, path: &'tcx Path, _id: NodeId) {
76         if self.item_path.def == path.def &&
77            path.segments
78             .last()
79             .expect("segments should be composed of at least 1 element")
80             .name != SelfType.name() {
81             span_lint_and_then(self.cx, USE_SELF, path.span, "unnecessary structure name repetition", |db| {
82                 db.span_suggestion(path.span,
83                                    "use the applicable keyword",
84                                    "Self".to_owned());
85             });
86         }
87
88         walk_path(self, path);
89     }
90
91     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
92         NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir)
93     }
94 }