]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/use_self.rs
rustup https://github.com/rust-lang/rust/pull/67455
[rust.git] / clippy_lints / src / use_self.rs
index 96e725c42297b29c8abf34250ce436d2a05ae9b5..4b9945d20b5c0a9405eb328edae5c95fa2891878 100644 (file)
@@ -1,16 +1,17 @@
 use if_chain::if_chain;
+use rustc::declare_lint_pass;
 use rustc::hir;
-use rustc::hir::def::{CtorKind, DefKind, Res};
+use rustc::hir::def::{DefKind, Res};
 use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
 use rustc::hir::*;
 use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty;
 use rustc::ty::{DefIdTree, Ty};
-use rustc::{declare_lint_pass, declare_tool_lint};
 use rustc_errors::Applicability;
+use rustc_session::declare_tool_lint;
 use syntax_pos::symbol::kw;
 
-use crate::utils::span_lint_and_sugg;
+use crate::utils::{differing_macro_contexts, span_lint_and_sugg};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for unnecessary repetition of structure name when a
@@ -43,7 +44,7 @@
     /// }
     /// ```
     pub USE_SELF,
-    pedantic,
+    nursery,
     "Unnecessary structure name repetition whereas `Self` is applicable"
 }
 
 
 const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
 
-fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
+fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path, last_segment: Option<&PathSegment>) {
+    let last_segment = last_segment.unwrap_or_else(|| path.segments.last().expect(SEGMENTS_MSG));
+
     // Path segments only include actual path, no methods or fields.
-    let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span;
+    let last_path_span = last_segment.ident.span;
+
+    if differing_macro_contexts(path.span, last_path_span) {
+        return;
+    }
+
     // Only take path up to the end of last_path_span.
     let span = path.span.with_hi(last_path_span.hi());
 
@@ -80,22 +88,18 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         let trait_ty = self.trait_type_walker.next();
         let impl_ty = self.impl_type_walker.next();
 
-        if let TyKind::Path(QPath::Resolved(_, path)) = &t.node {
+        if_chain! {
+            if let TyKind::Path(QPath::Resolved(_, path)) = &t.kind;
+
             // The implementation and trait types don't match which means that
             // the concrete type was specified by the implementation
-            if impl_ty != trait_ty {
-                if let Some(impl_ty) = impl_ty {
-                    if self.item_type == impl_ty {
-                        let is_self_ty = if let def::Res::SelfTy(..) = path.res {
-                            true
-                        } else {
-                            false
-                        };
-
-                        if !is_self_ty {
-                            span_use_self_lint(self.cx, path);
-                        }
-                    }
+            if impl_ty != trait_ty;
+            if let Some(impl_ty) = impl_ty;
+            if self.item_type == impl_ty;
+            then {
+                match path.res {
+                    def::Res::SelfTy(..) => {},
+                    _ => span_use_self_lint(self.cx, path, None)
                 }
             }
         }
@@ -129,7 +133,7 @@ fn check_trait_method_impl_decl<'a, 'tcx>(
     let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
     let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);
 
-    let impl_method_def_id = cx.tcx.hir().local_def_id_from_hir_id(impl_item.hir_id);
+    let impl_method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
     let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
     let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);
 
@@ -166,8 +170,8 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
             return;
         }
         if_chain! {
-            if let ItemKind::Impl(.., ref item_type, ref refs) = item.node;
-            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.node;
+            if let ItemKind::Impl(.., ref item_type, ref refs) = item.kind;
+            if let TyKind::Path(QPath::Resolved(_, ref item_path)) = item_type.kind;
             then {
                 let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
                 let should_check = if let Some(ref params) = *parameters {
@@ -184,14 +188,14 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
                         item_path,
                         cx,
                     };
-                    let impl_def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
+                    let impl_def_id = cx.tcx.hir().local_def_id(item.hir_id);
                     let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);
 
                     if let Some(impl_trait_ref) = impl_trait_ref {
                         for impl_item_ref in refs {
                             let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
-                            if let ImplItemKind::Method(MethodSig{ decl: impl_decl, .. }, impl_body_id)
-                                    = &impl_item.node {
+                            if let ImplItemKind::Method(FnSig{ decl: impl_decl, .. }, impl_body_id)
+                                    = &impl_item.kind {
                                 let item_type = cx.tcx.type_of(impl_def_id);
                                 check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);
 
@@ -220,20 +224,41 @@ struct UseSelfVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
     fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
-        if path.segments.last().expect(SEGMENTS_MSG).ident.name != kw::SelfUpper {
-            if self.item_path.res == path.res {
-                span_use_self_lint(self.cx, path);
-            } else if let Res::Def(DefKind::Ctor(def::CtorOf::Struct, CtorKind::Fn), ctor_did) = path.res {
-                if self.item_path.res.opt_def_id() == self.cx.tcx.parent(ctor_did) {
-                    span_use_self_lint(self.cx, path);
+        if !path.segments.iter().any(|p| p.ident.span.is_dummy()) {
+            if path.segments.len() >= 2 {
+                let last_but_one = &path.segments[path.segments.len() - 2];
+                if last_but_one.ident.name != kw::SelfUpper {
+                    let enum_def_id = match path.res {
+                        Res::Def(DefKind::Variant, variant_def_id) => self.cx.tcx.parent(variant_def_id),
+                        Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), ctor_def_id) => {
+                            let variant_def_id = self.cx.tcx.parent(ctor_def_id);
+                            variant_def_id.and_then(|def_id| self.cx.tcx.parent(def_id))
+                        },
+                        _ => None,
+                    };
+
+                    if self.item_path.res.opt_def_id() == enum_def_id {
+                        span_use_self_lint(self.cx, path, Some(last_but_one));
+                    }
+                }
+            }
+
+            if path.segments.last().expect(SEGMENTS_MSG).ident.name != kw::SelfUpper {
+                if self.item_path.res == path.res {
+                    span_use_self_lint(self.cx, path, None);
+                } else if let Res::Def(DefKind::Ctor(def::CtorOf::Struct, _), ctor_def_id) = path.res {
+                    if self.item_path.res.opt_def_id() == self.cx.tcx.parent(ctor_def_id) {
+                        span_use_self_lint(self.cx, path, None);
+                    }
                 }
             }
         }
+
         walk_path(self, path);
     }
 
     fn visit_item(&mut self, item: &'tcx Item) {
-        match item.node {
+        match item.kind {
             ItemKind::Use(..)
             | ItemKind::Static(..)
             | ItemKind::Enum(..)