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