]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/use_self.rs
Merge branch 'master' into fix-3739
[rust.git] / clippy_lints / src / use_self.rs
1 use if_chain::if_chain;
2 use rustc::hir::def::{CtorKind, Def};
3 use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
4 use rustc::hir::*;
5 use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
6 use rustc::ty;
7 use rustc::{declare_tool_lint, lint_array};
8 use rustc_errors::Applicability;
9 use syntax_pos::symbol::keywords::SelfUpper;
10
11 use crate::utils::span_lint_and_sugg;
12
13 declare_clippy_lint! {
14     /// **What it does:** Checks for unnecessary repetition of structure name when a
15     /// replacement with `Self` is applicable.
16     ///
17     /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
18     /// name
19     /// feels inconsistent.
20     ///
21     /// **Known problems:**
22     /// - False positive when using associated types (#2843)
23     /// - False positives in some situations when using generics (#3410)
24     ///
25     /// **Example:**
26     /// ```rust
27     /// struct Foo {}
28     /// impl Foo {
29     ///     fn new() -> Foo {
30     ///         Foo {}
31     ///     }
32     /// }
33     /// ```
34     /// could be
35     /// ```rust
36     /// struct Foo {}
37     /// impl Foo {
38     ///     fn new() -> Self {
39     ///         Self {}
40     ///     }
41     /// }
42     /// ```
43     pub USE_SELF,
44     pedantic,
45     "Unnecessary structure name repetition whereas `Self` is applicable"
46 }
47
48 #[derive(Copy, Clone, Default)]
49 pub struct UseSelf;
50
51 impl LintPass for UseSelf {
52     fn get_lints(&self) -> LintArray {
53         lint_array!(USE_SELF)
54     }
55
56     fn name(&self) -> &'static str {
57         "UseSelf"
58     }
59 }
60
61 const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
62
63 fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
64     // Path segments only include actual path, no methods or fields.
65     let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span;
66     // Only take path up to the end of last_path_span.
67     let span = path.span.with_hi(last_path_span.hi());
68
69     span_lint_and_sugg(
70         cx,
71         USE_SELF,
72         span,
73         "unnecessary structure name repetition",
74         "use the applicable keyword",
75         "Self".to_owned(),
76         Applicability::MachineApplicable,
77     );
78 }
79
80 struct TraitImplTyVisitor<'a, 'tcx: 'a> {
81     item_type: ty::Ty<'tcx>,
82     cx: &'a LateContext<'a, 'tcx>,
83     trait_type_walker: ty::walk::TypeWalker<'tcx>,
84     impl_type_walker: ty::walk::TypeWalker<'tcx>,
85 }
86
87 impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
88     fn visit_ty(&mut self, t: &'tcx Ty) {
89         let trait_ty = self.trait_type_walker.next();
90         let impl_ty = self.impl_type_walker.next();
91
92         if let TyKind::Path(QPath::Resolved(_, path)) = &t.node {
93             // The implementation and trait types don't match which means that
94             // the concrete type was specified by the implementation
95             if impl_ty != trait_ty {
96                 if let Some(impl_ty) = impl_ty {
97                     if self.item_type == impl_ty {
98                         let is_self_ty = if let def::Def::SelfTy(..) = path.def {
99                             true
100                         } else {
101                             false
102                         };
103
104                         if !is_self_ty {
105                             span_use_self_lint(self.cx, path);
106                         }
107                     }
108                 }
109             }
110         }
111
112         walk_ty(self, t)
113     }
114
115     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
116         NestedVisitorMap::None
117     }
118 }
119
120 fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
121     cx: &'a LateContext<'a, 'tcx>,
122     item_type: ty::Ty<'tcx>,
123     impl_item: &ImplItem,
124     impl_decl: &'tcx FnDecl,
125     impl_trait_ref: &ty::TraitRef<'_>,
126 ) {
127     let trait_method = cx
128         .tcx
129         .associated_items(impl_trait_ref.def_id)
130         .find(|assoc_item| {
131             assoc_item.kind == ty::AssociatedKind::Method
132                 && cx
133                     .tcx
134                     .hygienic_eq(impl_item.ident, assoc_item.ident, impl_trait_ref.def_id)
135         })
136         .expect("impl method matches a trait method");
137
138     let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
139     let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);
140
141     let impl_method_def_id = cx.tcx.hir().local_def_id_from_hir_id(impl_item.hir_id);
142     let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
143     let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);
144
145     let output_ty = if let FunctionRetTy::Return(ty) = &impl_decl.output {
146         Some(&**ty)
147     } else {
148         None
149     };
150
151     // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
152     // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
153     // that declaration. We use `impl_decl_ty` to see if the type was declared as `Self`
154     // and use `impl_ty` to check its concrete type.
155     for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip(
156         impl_method_sig
157             .inputs_and_output
158             .iter()
159             .zip(trait_method_sig.inputs_and_output),
160     ) {
161         let mut visitor = TraitImplTyVisitor {
162             cx,
163             item_type,
164             trait_type_walker: trait_ty.walk(),
165             impl_type_walker: impl_ty.walk(),
166         };
167
168         visitor.visit_ty(&impl_decl_ty);
169     }
170 }
171
172 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
173     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
174         if in_external_macro(cx.sess(), item.span) {
175             return;
176         }
177         if_chain! {
178             if let ItemKind::Impl(.., ref item_type, ref refs) = item.node;
179             if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.node;
180             then {
181                 let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
182                 let should_check = if let Some(ref params) = *parameters {
183                     !params.parenthesized && !params.args.iter().any(|arg| match arg {
184                         GenericArg::Lifetime(_) => true,
185                         _ => false,
186                     })
187                 } else {
188                     true
189                 };
190
191                 if should_check {
192                     let visitor = &mut UseSelfVisitor {
193                         item_path,
194                         cx,
195                     };
196                     let impl_def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
197                     let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);
198
199                     if let Some(impl_trait_ref) = impl_trait_ref {
200                         for impl_item_ref in refs {
201                             let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
202                             if let ImplItemKind::Method(MethodSig{ decl: impl_decl, .. }, impl_body_id)
203                                     = &impl_item.node {
204                                 let item_type = cx.tcx.type_of(impl_def_id);
205                                 check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);
206
207                                 let body = cx.tcx.hir().body(*impl_body_id);
208                                 visitor.visit_body(body);
209                             } else {
210                                 visitor.visit_impl_item(impl_item);
211                             }
212                         }
213                     } else {
214                         for impl_item_ref in refs {
215                             let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
216                             visitor.visit_impl_item(impl_item);
217                         }
218                     }
219                 }
220             }
221         }
222     }
223 }
224
225 struct UseSelfVisitor<'a, 'tcx: 'a> {
226     item_path: &'a Path,
227     cx: &'a LateContext<'a, 'tcx>,
228 }
229
230 impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
231     fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
232         if path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
233             if self.item_path.def == path.def {
234                 span_use_self_lint(self.cx, path);
235             } else if let Def::StructCtor(ctor_did, CtorKind::Fn) = path.def {
236                 if self.item_path.def.opt_def_id() == self.cx.tcx.parent_def_id(ctor_did) {
237                     span_use_self_lint(self.cx, path);
238                 }
239             }
240         }
241         walk_path(self, path);
242     }
243
244     fn visit_item(&mut self, item: &'tcx Item) {
245         match item.node {
246             ItemKind::Use(..)
247             | ItemKind::Static(..)
248             | ItemKind::Enum(..)
249             | ItemKind::Struct(..)
250             | ItemKind::Union(..)
251             | ItemKind::Impl(..) => {
252                 // Don't check statements that shadow `Self` or where `Self` can't be used
253             },
254             _ => walk_item(self, item),
255         }
256     }
257
258     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
259         NestedVisitorMap::All(&self.cx.tcx.hir())
260     }
261 }